@ghchinoy/lit-audio-ui 0.4.3 → 0.4.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,56 +2,40 @@
2
2
 
3
3
  A lightweight, framework-agnostic Web Components library for high-performance audio visualization and control, built natively for the browser using [Lit](https://lit.dev/).
4
4
 
5
- Take a look at the [examples and documentation](https://ghchinoy.github.io/scream-ui/) to see the components in action.
5
+ Take a look at the [interactive gallery and documentation](https://ghchinoy.github.io/scream-ui/) to see the components in action.
6
6
 
7
7
  ## Why Lit Web Components?
8
8
 
9
- When building complex, high-frequency audio visualizers (like real-time canvas waveforms), performance and bundle size are critical. Traditional React/ShadcnUI libraries often bring significant overhead due to Virtual DOM reconciliation loops and heavy CSS framework dependencies (like Tailwind).
10
-
11
- By leveraging **Lit** and native Web Components, this library offers distinct advantages:
9
+ When building complex, high-frequency audio visualizers (like real-time canvas waveforms), performance and bundle size are critical. By leveraging **Lit** and native Web Components, this library offers distinct advantages:
12
10
 
13
11
  * **Microscopic Footprint:** No massive framework runtimes. Lit simply provides lightweight, reactive syntactic sugar over standard browser APIs.
14
- * **Blazing Fast Canvas & Audio:** Direct DOM access means no Virtual DOM bottlenecks when piping 60fps `AnalyserNode` data directly into `<canvas>` elements.
15
- * **Framework Agnostic:** Because they compile to standard HTML tags (e.g., `<ui-live-waveform>`), you can drop these components into **any** frontend stack—React, Vue, Angular, Svelte, or vanilla HTMLwith zero friction.
16
- * **Scoped Styling:** Uses standard CSS variables and Material Design 3 tokens. No Tailwind installation, complex class merging, or CSS-in-JS runtime required.
17
- * **Atomic Composition:** Powered by `@lit/context`, the complex monolithic audio players are broken down into atomic, highly composable state machines.
18
-
12
+ * **Blazing Fast Canvas & Audio:** Direct DOM access means no Virtual DOM bottlenecks when piping 60fps data directly into `<canvas>` elements.
13
+ * **Framework Agnostic:** Compiles to standard HTML tags. Drop these into React, Vue, Angular, Svelte, or vanilla HTML with zero friction.
14
+ * **Atomic Design:** Organized into **Atoms, Molecules, Organisms, and Providers** for maximum reusability.
19
15
 
20
16
  ## How to Use (For AI Agents)
21
17
 
22
- If you are an AI coding agent integrating this library into an application, please refer to the [AGENT_SKILL.md](./AGENT_SKILL.md) for specialized integration protocols, state management patterns, and "Zero-JS" branding guidelines. This document is designed to help you autonomously implement robust audio interfaces that adhere to the library's "Lit Way" architecture.
23
-
24
-
25
- ## How to Use the Lit Components (For Users)
26
-
27
- As a Web Components library, you can use these elements directly in your HTML or inside any frontend framework.
18
+ If you are an AI coding agent integrating this library into an application, please refer to the [AGENT_SKILL.md](https://github.com/ghchinoy/scream-ui/blob/main/packages/lit-audio-ui/AGENT_SKILL.md) for specialized integration protocols, state management patterns, and "Zero-JS" branding guidelines.
28
19
 
20
+ ## How to Use (For Users)
29
21
 
30
22
  ### 1. Installation
31
- Install the package via npm:
32
23
  ```bash
33
24
  npm install @ghchinoy/lit-audio-ui
34
25
  ```
35
26
 
36
- ### 2. Usage (CDN)
37
- For a zero-install experience, you can use the library directly from a CDN like [esm.run](https://esm.run/):
38
- ```html
39
- <script type="module" src="https://esm.run/@ghchinoy/lit-audio-ui"></script>
40
- ```
41
-
42
- ### 3. Import the Library (Bundlers)
43
- Import the components into your JavaScript/TypeScript entry point:
27
+ ### 2. Import the Library
44
28
  ```javascript
45
29
  // Import the entire library
46
30
  import '@ghchinoy/lit-audio-ui';
47
31
 
48
- // Or import specific components
49
- import '@ghchinoy/lit-audio-ui/components/ui-voice-button';
50
- import '@ghchinoy/lit-audio-ui/components/ui-live-waveform';
32
+ // Or import specific categories for better tree-shaking
33
+ import '@ghchinoy/lit-audio-ui/atoms/ui-audio-play-button.js';
34
+ import '@ghchinoy/lit-audio-ui/molecules/ui-live-waveform.js';
51
35
  ```
52
36
 
53
- ### 4. Use in HTML
54
- Once imported, the custom elements are registered with the browser and can be used like standard HTML tags:
37
+ ### 3. Use in HTML
38
+ Once imported, custom elements are registered and used like standard HTML tags:
55
39
 
56
40
  ```html
57
41
  <!-- Example: A voice recording button -->
@@ -61,98 +45,45 @@ Once imported, the custom elements are registered with the browser and can be us
61
45
  <ui-live-waveform .analyserNode="${myAudioAnalyser}"></ui-live-waveform>
62
46
  ```
63
47
 
64
- ### 5. Theming (Material Design 3)
65
- These components are deeply theme-aware and utilize Material Design 3 design tokens. To customize their colors (or support light/dark modes), simply define the CSS variables in your stylesheet:
66
-
67
- ```css
68
- :root {
69
- --md-sys-color-primary: #0066cc;
70
- --md-sys-color-on-primary: #ffffff;
71
- --md-sys-color-surface-container: #f3f3f3;
72
- /* ...other MD3 tokens */
73
- }
74
-
75
- .dark {
76
- --md-sys-color-primary: #a8c7fa;
77
- --md-sys-color-on-primary: #003062;
78
- --md-sys-color-surface-container: #212121;
79
- }
80
- ```
81
-
82
48
  ## Available Components
83
49
 
84
- The library currently ships with the following native WebComponents:
50
+ ### 🧪 Atoms (Primitives)
51
+ * **`<ui-audio-play-button>`**: Context-aware play/pause toggle.
52
+ * **`<ui-audio-next-button>` / `<ui-audio-prev-button>`**: Playlist navigation buttons.
53
+ * **`<ui-audio-progress-slider>`**: Reactive scrubber for playback.
54
+ * **`<ui-audio-time-display>`**: Flexible time visualizer (elapsed, remaining, combined).
55
+ * **`<ui-speech-record-button>`**: Atomic trigger for recording context.
56
+ * **`<ui-shimmering-text>`**: Pure CSS text loading effect.
85
57
 
86
- * 🎙️ **`<ui-voice-button>`**: A compound interactive button that dynamically mounts a live visualizer depending on its state. Cycles gracefully through `idle`, `recording`, `processing`, `success`, and `error` states.
87
- * 📊 **`<ui-waveform>`**: A static, pre-computed scrubbable waveform timeline for audio playback visualization.
88
- * 🌊 **`<ui-live-waveform>`**: A real-time visualizer that responds to an active `AudioContext`. Includes aggressive noise-gating, center-out mirroring, and a synthetic "processing" animation state.
89
- * 〰️ **`<ui-scrolling-waveform>`**: An infinitely scrolling procedural audio visualization animation. Perfect for active "listening" states where a live `AnalyserNode` is unavailable.
90
- * 🎵 **`<ui-audio-player>`**: A classic monolithic pill-shaped audio player.
91
- * 🧩 **Compound Audio Architecture**: Use `<ui-audio-provider>`, `<ui-audio-play-button>`, `<ui-audio-progress-slider>`, and `<ui-audio-time-display>` to construct entirely custom audio layouts powered by a headless state machine via `@lit/context`.
92
- * **`<ui-shimmering-text>`**: A pure CSS, dependency-free text loading effect translating complex gradients into native `@keyframes`.
93
- * 🎛️ **`<ui-mic-selector>`**: Handles hardware microphone enumeration (`navigator.mediaDevices`), permissions, and displays a live audio preview directly inside a dropdown menu.
94
- * 🎭 **`<ui-voice-picker>`**: A searchable dropdown menu (combobox) that handles rendering complex persona objects, including real-time audio previews injected directly into the menu items.
95
- * 🗣️ **Atomic Speech Architecture**: Use `<ui-speech-provider>`, `<ui-speech-record-button>`, `<ui-speech-preview>`, and `<ui-speech-cancel-button>` to build custom recording UIs (like the Smart Textarea) with built-in state management and visualization.
58
+ ### 🧬 Molecules (Functional Units)
59
+ * **`<ui-live-waveform>`**: Real-time visualizer for an active `AudioContext`.
60
+ * **`<ui-spectrum-visualizer>`**: Traditional frequency-bar spectrum.
61
+ * **`<ui-orb>`**: 3D WebGL (Three.js) agent visualizer.
62
+ * **`<ui-3d-flip>`**: Layout utility for 3D card-flipping interactions.
63
+ * **`<ui-playlist>`**: Reactive list component for queue management.
64
+ * **`<ui-mic-selector>`**: Hardware enumeration and permission handler.
65
+ * **`<ui-voice-picker>`**: Searchable persona selector with audio previews.
96
66
 
67
+ ### 🧩 Providers (State)
68
+ * **`<ui-audio-provider>`**: Headless state machine for playback and playlists.
69
+ * **`<ui-speech-provider>`**: Headless lifecycle manager for voice recording (Auto, Simulation, or Manual mode).
97
70
 
98
- ## How to Build & Extend (For Developers)
71
+ ## Theming (Material Design 3)
99
72
 
100
- We welcome contributions! If you want to extend the components, tweak the canvas math, or add new visualizers, here is how you can get started.
73
+ Customize colors and typography via standard CSS variables:
101
74
 
102
- ### Prerequisites
103
- - Node.js (v18+)
104
- - npm or pnpm
105
-
106
- ### Local Development Setup
107
-
108
- 1. **Clone & Install**
109
- ```bash
110
- git clone <repository-url>
111
- cd packages/lit-audio-ui
112
- npm install
113
- ```
114
-
115
- 2. **Start the Dev Server**
116
- This will start a local Vite development server. It serves the `index.html` file, which acts as our component workbench and functional test bed.
117
- ```bash
118
- npm run dev
119
- ```
120
-
121
- 3. **Code Structure**
122
- - `/packages/lit-audio-ui/src/components/`: This is where the Lit elements (`.ts`) live. Each component should be self-contained with its scoped CSS (`static styles`).
123
- - `/packages/lit-audio-ui/src/utils/`: Shared utilities, such as the `AudioContext` and FFT math ported from the original ElevenLabs React repository.
124
- - `/packages/lit-audio-ui/demo/index.html`: The development workbench. Whenever you create a new component or port a feature, add a demo block here.
125
- - `/packages/lit-audio-ui/demo/demo-layouts.ts`: Complex composite examples and layout logic used in the workbench.
126
-
127
- ### Building for Production
128
- To compile the TypeScript and bundle the library for distribution:
129
- ```bash
130
- cd packages/lit-audio-ui
131
- npm run build
132
- ```
133
- This generates the optimized assets in the `/dist` folder.
134
-
135
- ### Linting
136
- We use `google/gts` (Google TypeScript Style) and the `eslint-plugin-lit` ruleset to enforce code quality and Lit best practices.
137
- ```bash
138
- cd packages/lit-audio-ui
139
- npm run lint
140
- npm run fix
75
+ ```css
76
+ :root {
77
+ --md-sys-color-primary: #0066cc;
78
+ --ui-speech-record-color: #ff4444; /* Custom branding */
79
+ --ui-speech-preview-font-size: 18px;
80
+ }
141
81
  ```
142
82
 
143
83
  ## Acknowledgements
144
84
 
145
- This project is deeply inspired by the beautiful, open-source audio components designed and built by **[ElevenLabs](https://elevenlabs.io/)** (`@elevenlabs/ui`).
146
-
147
- We are incredibly grateful for their contribution to the open-source community. Their original repository provided the foundational audio mathematics, canvas drawing logic, and WebGL shader configurations that make these visualizers look buttery smooth. While their library focuses heavily on the React ecosystem, this project reimagines those beautiful designs as standard, universal browser APIs.
85
+ Deeply inspired by the beautiful, open-source audio components built by **[ElevenLabs](https://elevenlabs.io/)** (`@elevenlabs/ui`). This project reimplement those designs as standard, universal browser APIs.
148
86
 
149
87
  # License
150
88
 
151
89
  Apache 2.0; see [`LICENSE`](LICENSE) for details.
152
-
153
-
154
- # Disclaimer
155
-
156
- This project is not an official Google project. It is not supported by
157
- Google and Google specifically disclaims all warranties as to its quality,
158
- merchantability, or fitness for a particular purpose.
@@ -0,0 +1,95 @@
1
+ import { __decorate as e } from "../../_virtual/_@oxc-project_runtime@0.113.0/helpers/decorate.js";
2
+ import { LitElement as t, css as n, html as r } from "lit";
3
+ import { customElement as i, property as a } from "lit/decorators.js";
4
+ /**
5
+ * Copyright 2026 Google LLC
6
+ *
7
+ * Licensed under the Apache License, Version 2.0 (the "License");
8
+ * you may not use this file except in compliance with the License.
9
+ * You may obtain a copy of the License at
10
+ *
11
+ * http://www.apache.org/licenses/LICENSE-2.0
12
+ *
13
+ * Unless required by applicable law or agreed to in writing, software
14
+ * distributed under the License is distributed on an "AS IS" BASIS,
15
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ * See the License for the specific language governing permissions and
17
+ * limitations under the License.
18
+ */
19
+ var o = class extends t {
20
+ constructor(...e) {
21
+ super(...e), this.variant = "contained", this.direction = "inbound";
22
+ }
23
+ static {
24
+ this.styles = n`
25
+ :host {
26
+ display: inline-flex;
27
+ max-width: 85%;
28
+ font-family: inherit;
29
+ color-scheme: light dark;
30
+ }
31
+
32
+ .bubble {
33
+ display: flex;
34
+ flex-direction: column;
35
+ gap: 8px;
36
+ padding: 14px 18px;
37
+ font-size: 0.95rem;
38
+ line-height: 1.5;
39
+ box-sizing: border-box;
40
+ transition: background-color 0.2s, color 0.2s;
41
+ }
42
+
43
+ /* Variant: Contained */
44
+ :host([variant='contained']) .bubble {
45
+ border-radius: 16px;
46
+ }
47
+
48
+ :host([variant='contained'][direction='inbound']) .bubble {
49
+ background: var(
50
+ --ui-message-bubble-inbound-bg,
51
+ var(--md-sys-color-surface-container-high, #e2e2e2)
52
+ );
53
+ color: var(--md-sys-color-on-surface);
54
+ border-bottom-left-radius: 4px;
55
+ }
56
+
57
+ :host([variant='contained'][direction='outbound']) .bubble {
58
+ background: var(
59
+ --ui-message-bubble-outbound-bg,
60
+ var(--md-sys-color-primary, #0066cc)
61
+ );
62
+ color: var(--md-sys-color-on-primary, #ffffff);
63
+ border-bottom-right-radius: 4px;
64
+ }
65
+
66
+ /* Variant: Flat */
67
+ :host([variant='flat']) .bubble {
68
+ padding: 8px 0;
69
+ background: transparent;
70
+ color: var(--md-sys-color-on-surface);
71
+ }
72
+
73
+ :host([variant='flat'][direction='outbound']) .bubble {
74
+ padding: 12px 16px;
75
+ background: var(--md-sys-color-surface-container-highest);
76
+ border-radius: 12px;
77
+ }
78
+ `;
79
+ }
80
+ render() {
81
+ return r`
82
+ <div class="bubble">
83
+ <slot></slot>
84
+ </div>
85
+ `;
86
+ }
87
+ };
88
+ e([a({
89
+ type: String,
90
+ reflect: !0
91
+ })], o.prototype, "variant", void 0), e([a({
92
+ type: String,
93
+ reflect: !0
94
+ })], o.prototype, "direction", void 0), o = e([i("ui-message-bubble")], o);
95
+ export { o as UiMessageBubble };
@@ -59,12 +59,11 @@ var c = class extends r {
59
59
  `;
60
60
  }
61
61
  render() {
62
- if (!this._context) return a``;
63
- let { state: e } = this._context, t = e === "recording", n = e === "processing" || e === "connecting", r = "mic";
62
+ let e = this._context?.state || "idle", t = e === "recording", n = e === "processing" || e === "connecting", r = "mic";
64
63
  return t && (r = "stop"), n && (r = "hourglass_empty"), e === "success" && (r = "check"), e === "error" && (r = "error"), a`
65
64
  <md-filled-icon-button
66
65
  class="${e}"
67
- ?disabled=${n}
66
+ ?disabled=${n || !this._context}
68
67
  @click=${this._handleClick}
69
68
  >
70
69
  <md-icon>${r}</md-icon>
@@ -0,0 +1,54 @@
1
+ import { __decorate as e } from "../../_virtual/_@oxc-project_runtime@0.113.0/helpers/decorate.js";
2
+ import { LitElement as t, css as n, html as r } from "lit";
3
+ import { customElement as i, property as a } from "lit/decorators.js";
4
+ /**
5
+ * Copyright 2026 Google LLC
6
+ *
7
+ * Licensed under the Apache License, Version 2.0 (the "License");
8
+ * you may not use this file except in compliance with the License.
9
+ * You may obtain a copy of the License at
10
+ *
11
+ * http://www.apache.org/licenses/LICENSE-2.0
12
+ *
13
+ * Unless required by applicable law or agreed to in writing, software
14
+ * distributed under the License is distributed on an "AS IS" BASIS,
15
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ * See the License for the specific language governing permissions and
17
+ * limitations under the License.
18
+ */
19
+ var o = class extends t {
20
+ constructor(...e) {
21
+ super(...e), this.delay = "0s";
22
+ }
23
+ static {
24
+ this.styles = n`
25
+ :host {
26
+ display: inline-block;
27
+ }
28
+ .dot {
29
+ width: 6px;
30
+ height: 6px;
31
+ border-radius: 50%;
32
+ background: var(--ui-typing-dot-color, currentColor);
33
+ animation: pulse 1.2s infinite ease-in-out;
34
+ }
35
+
36
+ @keyframes pulse {
37
+ 0%,
38
+ 100% {
39
+ transform: scale(0.8);
40
+ opacity: 0.4;
41
+ }
42
+ 50% {
43
+ transform: scale(1.2);
44
+ opacity: 1;
45
+ }
46
+ }
47
+ `;
48
+ }
49
+ render() {
50
+ return r`<div class="dot" style="animation-delay: ${this.delay}"></div>`;
51
+ }
52
+ };
53
+ e([a({ type: String })], o.prototype, "delay", void 0), o = e([i("ui-typing-dot")], o);
54
+ export { o as UiTypingDot };
@@ -0,0 +1,112 @@
1
+ import { __decorate as e } from "../../_virtual/_@oxc-project_runtime@0.113.0/helpers/decorate.js";
2
+ import "../atoms/ui-message-bubble.js";
3
+ import { LitElement as t, css as n, html as r } from "lit";
4
+ import { customElement as i, property as a } from "lit/decorators.js";
5
+ import { classMap as o } from "lit/directives/class-map.js";
6
+ /**
7
+ * Copyright 2026 Google LLC
8
+ *
9
+ * Licensed under the Apache License, Version 2.0 (the "License");
10
+ * you may not use this file except in compliance with the License.
11
+ * You may obtain a copy of the License at
12
+ *
13
+ * http://www.apache.org/licenses/LICENSE-2.0
14
+ *
15
+ * Unless required by applicable law or agreed to in writing, software
16
+ * distributed under the License is distributed on an "AS IS" BASIS,
17
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
+ * See the License for the specific language governing permissions and
19
+ * limitations under the License.
20
+ */
21
+ var s = class extends t {
22
+ constructor(...e) {
23
+ super(...e), this.direction = "inbound", this.variant = "contained";
24
+ }
25
+ static {
26
+ this.styles = n`
27
+ :host {
28
+ display: flex;
29
+ width: 100%;
30
+ margin-bottom: 1rem;
31
+ font-family: inherit;
32
+ }
33
+
34
+ .item-container {
35
+ display: flex;
36
+ gap: 12px;
37
+ width: 100%;
38
+ align-items: flex-end;
39
+ }
40
+
41
+ .item-container.inbound {
42
+ justify-content: flex-start;
43
+ }
44
+
45
+ .item-container.outbound {
46
+ flex-direction: row-reverse;
47
+ justify-content: flex-start; /* This correctly pushes to the right because of row-reverse */
48
+ }
49
+
50
+ .avatar-slot {
51
+ width: 32px;
52
+ height: 32px;
53
+ flex-shrink: 0;
54
+ display: flex;
55
+ align-items: center;
56
+ justify-content: center;
57
+ }
58
+
59
+ /* Hide avatar slot if no children are present */
60
+ .avatar-slot:not(:has(*)) {
61
+ display: none;
62
+ }
63
+
64
+ .content-wrapper {
65
+ display: flex;
66
+ flex-direction: column;
67
+ gap: 4px;
68
+ max-width: 80%;
69
+ }
70
+
71
+ .item-container.inbound .content-wrapper {
72
+ align-items: flex-start;
73
+ }
74
+
75
+ .item-container.outbound .content-wrapper {
76
+ align-items: flex-end;
77
+ }
78
+
79
+ .meta-slot {
80
+ font-size: 0.7rem;
81
+ font-weight: 500;
82
+ opacity: 0.6;
83
+ padding: 0 4px;
84
+ display: flex;
85
+ gap: 8px;
86
+ }
87
+ `;
88
+ }
89
+ render() {
90
+ return r`
91
+ <div class=${o({
92
+ "item-container": !0,
93
+ [this.direction]: !0
94
+ })}>
95
+ <div class="avatar-slot">
96
+ <slot name="avatar"></slot>
97
+ </div>
98
+
99
+ <div class="content-wrapper">
100
+ <ui-message-bubble .direction=${this.direction} .variant=${this.variant}>
101
+ <slot></slot>
102
+ </ui-message-bubble>
103
+ <div class="meta-slot">
104
+ <slot name="meta"></slot>
105
+ </div>
106
+ </div>
107
+ </div>
108
+ `;
109
+ }
110
+ };
111
+ e([a({ type: String })], s.prototype, "direction", void 0), e([a({ type: String })], s.prototype, "variant", void 0), s = e([i("ui-chat-item")], s);
112
+ export { s as UiChatItem };
@@ -0,0 +1,71 @@
1
+ import { __decorate as e } from "../../_virtual/_@oxc-project_runtime@0.113.0/helpers/decorate.js";
2
+ import { LitElement as t, css as n, html as r } from "lit";
3
+ import { customElement as i, query as a } from "lit/decorators.js";
4
+ /**
5
+ * Copyright 2026 Google LLC
6
+ *
7
+ * Licensed under the Apache License, Version 2.0 (the "License");
8
+ * you may not use this file except in compliance with the License.
9
+ * You may obtain a copy of the License at
10
+ *
11
+ * http://www.apache.org/licenses/LICENSE-2.0
12
+ *
13
+ * Unless required by applicable law or agreed to in writing, software
14
+ * distributed under the License is distributed on an "AS IS" BASIS,
15
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ * See the License for the specific language governing permissions and
17
+ * limitations under the License.
18
+ */
19
+ var o = class extends t {
20
+ static {
21
+ this.styles = n`
22
+ :host {
23
+ display: block;
24
+ height: 100%;
25
+ width: 100%;
26
+ overflow: hidden;
27
+ }
28
+
29
+ .scroll-container {
30
+ height: 100%;
31
+ width: 100%;
32
+ overflow-y: auto;
33
+ display: flex;
34
+ flex-direction: column;
35
+ padding: 1rem;
36
+ box-sizing: border-box;
37
+ scroll-behavior: smooth;
38
+ }
39
+
40
+ /* Scrollbar Styling */
41
+ .scroll-container::-webkit-scrollbar {
42
+ width: 6px;
43
+ }
44
+ .scroll-container::-webkit-scrollbar-track {
45
+ background: transparent;
46
+ }
47
+ .scroll-container::-webkit-scrollbar-thumb {
48
+ background: var(--md-sys-color-outline-variant);
49
+ border-radius: 10px;
50
+ }
51
+ `;
52
+ }
53
+ updated(e) {
54
+ super.updated(e), this.scrollToBottom();
55
+ }
56
+ /**
57
+ * Imperatively scroll to the most recent message.
58
+ */
59
+ scrollToBottom() {
60
+ this._container && (this._container.scrollTop = this._container.scrollHeight);
61
+ }
62
+ render() {
63
+ return r`
64
+ <div class="scroll-container">
65
+ <slot @slotchange=${this.scrollToBottom}></slot>
66
+ </div>
67
+ `;
68
+ }
69
+ };
70
+ e([a(".scroll-container")], o.prototype, "_container", void 0), o = e([i("ui-chat-list")], o);
71
+ export { o as UiChatList };
@@ -77,11 +77,15 @@ var o = class extends t {
77
77
  }
78
78
 
79
79
  .preview-panel {
80
- display: none;
80
+ display: block; /* Keep in DOM for script access */
81
81
  }
82
82
 
83
- .preview-panel.active {
84
- display: block;
83
+ :host([mode='code']) .preview-panel {
84
+ position: absolute;
85
+ visibility: hidden;
86
+ pointer-events: none;
87
+ height: 0;
88
+ overflow: hidden;
85
89
  }
86
90
 
87
91
  .code-panel {
@@ -98,7 +102,7 @@ var o = class extends t {
98
102
  border: 1px solid var(--md-sys-color-outline-variant);
99
103
  }
100
104
 
101
- .code-panel.active {
105
+ :host([mode='code']) .code-panel {
102
106
  display: block;
103
107
  }
104
108
  `;
@@ -126,16 +130,17 @@ var o = class extends t {
126
130
  </div>
127
131
 
128
132
  <div class="content-area">
129
- <div class="preview-panel ${this.mode === "preview" ? "active" : ""}">
133
+ <div class="preview-panel">
130
134
  <slot></slot>
131
135
  </div>
132
136
 
133
- <pre
134
- class="code-panel ${this.mode === "code" ? "active" : ""}"
135
- ><code><slot name="code"></slot></code></pre>
137
+ <pre class="code-panel"><code><slot name="code"></slot></code></pre>
136
138
  </div>
137
139
  `;
138
140
  }
139
141
  };
140
- e([a({ type: String })], o.prototype, "title", void 0), e([a({ type: String })], o.prototype, "description", void 0), e([a({ type: String })], o.prototype, "mode", void 0), o = e([i("ui-showcase-card")], o);
142
+ e([a({ type: String })], o.prototype, "title", void 0), e([a({ type: String })], o.prototype, "description", void 0), e([a({
143
+ type: String,
144
+ reflect: !0
145
+ })], o.prototype, "mode", void 0), o = e([i("ui-showcase-card")], o);
141
146
  export { o as UiShowcaseCard };
@@ -53,8 +53,7 @@ var c = class extends r {
53
53
  `;
54
54
  }
55
55
  render() {
56
- if (!this._context) return a``;
57
- let { state: e, transcript: t, partialTranscript: n, analyserNode: r } = this._context, i = e === "recording", o = e === "processing" || e === "connecting";
56
+ let { state: e = "idle", transcript: t = "", partialTranscript: n = "", analyserNode: r = void 0 } = this._context || {}, i = e === "recording", o = e === "processing" || e === "connecting";
58
57
  return a`
59
58
  ${!i && !o && !(t || n) ? a`<span class="placeholder">${this.placeholder}</span>` : a`<span class="transcript">${n || t}</span>`}
60
59
 
@@ -0,0 +1,43 @@
1
+ import { __decorate as e } from "../../_virtual/_@oxc-project_runtime@0.113.0/helpers/decorate.js";
2
+ import "../atoms/ui-typing-dot.js";
3
+ import { LitElement as t, css as n, html as r } from "lit";
4
+ import { customElement as i } from "lit/decorators.js";
5
+ /**
6
+ * Copyright 2026 Google LLC
7
+ *
8
+ * Licensed under the Apache License, Version 2.0 (the "License");
9
+ * you may not use this file except in compliance with the License.
10
+ * You may obtain a copy of the License at
11
+ *
12
+ * http://www.apache.org/licenses/LICENSE-2.0
13
+ *
14
+ * Unless required by applicable law or agreed to in writing, software
15
+ * distributed under the License is distributed on an "AS IS" BASIS,
16
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
+ * See the License for the specific language governing permissions and
18
+ * limitations under the License.
19
+ */
20
+ var a = class extends t {
21
+ static {
22
+ this.styles = n`
23
+ :host {
24
+ display: inline-flex;
25
+ align-items: center;
26
+ gap: 4px;
27
+ padding: 8px 12px;
28
+ background: var(--md-sys-color-surface-container-low);
29
+ border-radius: 12px;
30
+ border-bottom-left-radius: 4px;
31
+ }
32
+ `;
33
+ }
34
+ render() {
35
+ return r`
36
+ <ui-typing-dot delay="0s"></ui-typing-dot>
37
+ <ui-typing-dot delay="0.2s"></ui-typing-dot>
38
+ <ui-typing-dot delay="0.4s"></ui-typing-dot>
39
+ `;
40
+ }
41
+ };
42
+ a = e([i("ui-typing-indicator")], a);
43
+ export { a as UiTypingIndicator };
@@ -10,6 +10,7 @@ var u = class extends i {
10
10
  state: "idle",
11
11
  transcript: "",
12
12
  partialTranscript: "",
13
+ analyserNode: void 0,
13
14
  start: () => this.start(),
14
15
  stop: () => this.stop(),
15
16
  cancel: () => this.cancel()