@gojargo/jargo-elements 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.
package/LICENSE ADDED
@@ -0,0 +1,24 @@
1
+ BSD 2-Clause License
2
+
3
+ Copyright (c) 2026, the jargo authors
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package/README.md ADDED
@@ -0,0 +1,80 @@
1
+ # @gojargo/jargo-elements
2
+
3
+ **Web components** for jargo — the framework-agnostic path for Angular, Svelte,
4
+ Solid, or plain HTML. Built on [`@gojargo/jargo-ui`](../jargo-ui) (visual +
5
+ theme) and [`@gojargo/jargo-client-js`](../jargo-client-js) (the client).
6
+
7
+ - **`<jargo-orb>`** — the Orb (no client needed).
8
+ - **`<jargo-connect-button>`**, **`<jargo-mic-button>`**, **`<jargo-status>`**,
9
+ **`<jargo-transcript>`** — client-driven; they read a client set via
10
+ `setJargoClient()`.
11
+
12
+ Part of the [`jargo-web`](https://github.com/gojargo/jargo-web) monorepo.
13
+
14
+ ## Install
15
+
16
+ ```bash
17
+ npm install @gojargo/jargo-elements
18
+ ```
19
+
20
+ ## Usage
21
+
22
+ Register the elements, import the theme, set a client, then use them in markup:
23
+
24
+ ```html
25
+ <script type="module">
26
+ import { setJargoClient } from "@gojargo/jargo-elements";
27
+ import "@gojargo/jargo-elements/define";
28
+ import "@gojargo/jargo-ui/theme.css";
29
+ import { JargoClient } from "@gojargo/jargo-client-js";
30
+
31
+ setJargoClient(new JargoClient({ baseUrl: "https://jargo.example.com" }));
32
+ </script>
33
+
34
+ <jargo-status></jargo-status>
35
+ <jargo-orb colors="aurora"></jargo-orb>
36
+ <jargo-transcript empty-label="Say hello to start…"></jargo-transcript>
37
+ <jargo-connect-button></jargo-connect-button>
38
+ <jargo-mic-button></jargo-mic-button>
39
+ ```
40
+
41
+ `setJargoClient(client)` makes one client the default for every element on the
42
+ page; an element can override it by setting its `.client` property. Register
43
+ manually instead of `/define` with `defineJargoElements()` (or just
44
+ `defineJargoOrb()`).
45
+
46
+ The client-driven elements render in light DOM and are styled by
47
+ `@gojargo/jargo-ui/theme.css` — theme them with the same `--jargo-*` variables.
48
+
49
+ The `<jargo-orb>` also registers under a custom tag:
50
+
51
+ ```js
52
+ import { defineJargoOrb } from "@gojargo/jargo-elements";
53
+ defineJargoOrb("voice-orb"); // <voice-orb>
54
+ ```
55
+
56
+ ### `<jargo-orb>` attributes
57
+
58
+ Size it with CSS (defaults to 220×220). Attributes mirror the Orb options in
59
+ kebab-case: `rings`, `radius`, `inner-scale`, `line-width`, `speed`,
60
+ `idle-amplitude`, `reactivity`, `glow`, `core`, `blend`, `background`, plus:
61
+
62
+ - `colors` — a palette name (`spectrum`, `aurora`, `ember`, `mono`) or a
63
+ comma/space-separated list of CSS colors.
64
+ - `level` — manual drive level, `0`..`1`.
65
+ - `paused` — present to pause the animation.
66
+
67
+ ### Live audio
68
+
69
+ Drive it from a stream (e.g. a jargo bot's remote audio) via the element's
70
+ method:
71
+
72
+ ```js
73
+ const orb = document.querySelector("jargo-orb");
74
+ orb.attachStream(client.remoteStream);
75
+ client.on("remoteTrack", (s) => orb.attachStream(s));
76
+ ```
77
+
78
+ ## License
79
+
80
+ BSD-2-Clause. See [LICENSE](./LICENSE) and [NOTICE](./NOTICE).
@@ -0,0 +1,341 @@
1
+ // src/index.ts
2
+ import {
3
+ Orb,
4
+ OrbPalettes
5
+ } from "@gojargo/jargo-ui";
6
+
7
+ // src/components.ts
8
+ import { TranscriptTracker } from "@gojargo/jargo-client-js";
9
+
10
+ // src/client-registry.ts
11
+ var current = null;
12
+ var subscribers = /* @__PURE__ */ new Set();
13
+ function setJargoClient(client) {
14
+ current = client;
15
+ subscribers.forEach((fn) => fn(client));
16
+ }
17
+ function getJargoClient() {
18
+ return current;
19
+ }
20
+ function subscribeJargoClient(fn) {
21
+ subscribers.add(fn);
22
+ return () => subscribers.delete(fn);
23
+ }
24
+
25
+ // src/JargoClientElement.ts
26
+ var JargoClientElement = class extends HTMLElement {
27
+ constructor() {
28
+ super(...arguments);
29
+ /** The bound client, available to subclasses in {@link bind}/{@link render}. */
30
+ this.jargo = null;
31
+ this.clientOverride = null;
32
+ this.offs = [];
33
+ }
34
+ /** Set a specific client, overriding the global {@link setJargoClient} registry. */
35
+ set client(client) {
36
+ this.clientOverride = client;
37
+ this.rebind();
38
+ }
39
+ get client() {
40
+ return this.clientOverride ?? getJargoClient();
41
+ }
42
+ connectedCallback() {
43
+ this.offRegistry = subscribeJargoClient(() => {
44
+ if (!this.clientOverride) this.rebind();
45
+ });
46
+ this.rebind();
47
+ }
48
+ disconnectedCallback() {
49
+ this.offRegistry?.();
50
+ this.teardown();
51
+ }
52
+ attributeChangedCallback() {
53
+ this.render();
54
+ }
55
+ /** Track a cleanup (e.g. an event unsubscribe) tied to the current binding. */
56
+ track(off) {
57
+ this.offs.push(off);
58
+ }
59
+ rebind() {
60
+ this.teardown();
61
+ this.jargo = this.client;
62
+ if (this.jargo) this.bind(this.jargo);
63
+ this.render();
64
+ }
65
+ teardown() {
66
+ this.offs.forEach((off) => off());
67
+ this.offs = [];
68
+ }
69
+ /** Subscribe to client events here via {@link track}; called on each (re)bind. */
70
+ bind(_client) {
71
+ }
72
+ };
73
+ function escapeHtml(s) {
74
+ return s.replace(
75
+ /[&<>]/g,
76
+ (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;" })[c]
77
+ );
78
+ }
79
+ function micIcon(muted) {
80
+ return `<svg class="jargo-mic-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="3" width="6" height="11" rx="3"/><path d="M5 11a7 7 0 0 0 14 0"/><line x1="12" y1="18" x2="12" y2="21"/>${muted ? '<line x1="3" y1="3" x2="21" y2="21"/>' : ""}</svg>`;
81
+ }
82
+
83
+ // src/components.ts
84
+ var isConnected = (s) => s === "connected" || s === "ready";
85
+ var JargoConnectButtonElement = class extends JargoClientElement {
86
+ constructor() {
87
+ super(...arguments);
88
+ this.state = "disconnected";
89
+ }
90
+ bind(client) {
91
+ this.state = client.state;
92
+ this.track(
93
+ client.on("transportStateChanged", (s) => {
94
+ this.state = s;
95
+ this.render();
96
+ })
97
+ );
98
+ }
99
+ render() {
100
+ const conn = isConnected(this.state);
101
+ const connecting = this.state === "connecting";
102
+ const label = conn ? this.getAttribute("label-connected") ?? "End conversation" : connecting ? this.getAttribute("label-connecting") ?? "Connecting\u2026" : this.getAttribute("label-idle") ?? "Start conversation";
103
+ this.innerHTML = `<button class="jargo-btn ${conn ? "jargo-btn--danger" : "jargo-btn--primary"}" ${connecting ? "disabled aria-busy='true'" : ""}>${connecting ? '<span class="jargo-spinner"></span>' : ""}${escapeHtml(label)}</button>`;
104
+ const btn = this.querySelector("button");
105
+ if (btn) {
106
+ btn.onclick = () => {
107
+ const c = this.jargo;
108
+ if (!c) return;
109
+ if (isConnected(c.state)) c.disconnect();
110
+ else void c.connect().catch(() => {
111
+ });
112
+ };
113
+ }
114
+ }
115
+ };
116
+ JargoConnectButtonElement.observedAttributes = [
117
+ "label-idle",
118
+ "label-connecting",
119
+ "label-connected"
120
+ ];
121
+ var JargoMicButtonElement = class extends JargoClientElement {
122
+ constructor() {
123
+ super(...arguments);
124
+ this.state = "disconnected";
125
+ this.enabled = true;
126
+ }
127
+ bind(client) {
128
+ this.state = client.state;
129
+ this.enabled = client.micEnabled;
130
+ this.track(
131
+ client.on("transportStateChanged", (s) => {
132
+ this.state = s;
133
+ this.enabled = client.micEnabled;
134
+ this.render();
135
+ })
136
+ );
137
+ }
138
+ render() {
139
+ const conn = isConnected(this.state);
140
+ const label = this.enabled ? this.getAttribute("label-mute") ?? "Mute" : this.getAttribute("label-unmute") ?? "Unmute";
141
+ this.innerHTML = `<button class="jargo-btn jargo-btn--ghost" ${conn ? "" : "disabled"} aria-pressed="${!this.enabled}" data-muted="${!this.enabled}">${micIcon(
142
+ !this.enabled
143
+ )}${escapeHtml(label)}</button>`;
144
+ const btn = this.querySelector("button");
145
+ if (btn) {
146
+ btn.onclick = () => {
147
+ const c = this.jargo;
148
+ if (!c) return;
149
+ this.enabled = c.toggleMic();
150
+ this.render();
151
+ };
152
+ }
153
+ }
154
+ };
155
+ JargoMicButtonElement.observedAttributes = ["label-mute", "label-unmute"];
156
+ var STATUS_LABELS = {
157
+ disconnected: "Offline",
158
+ connecting: "Connecting\u2026",
159
+ connected: "Connected",
160
+ ready: "Live",
161
+ error: "Error"
162
+ };
163
+ var JargoStatusElement = class extends JargoClientElement {
164
+ constructor() {
165
+ super(...arguments);
166
+ this.state = "disconnected";
167
+ }
168
+ bind(client) {
169
+ this.state = client.state;
170
+ this.track(
171
+ client.on("transportStateChanged", (s) => {
172
+ this.state = s;
173
+ this.render();
174
+ })
175
+ );
176
+ }
177
+ render() {
178
+ const label = this.getAttribute(`label-${this.state}`) ?? STATUS_LABELS[this.state];
179
+ this.innerHTML = `<span class="jargo-status jargo-status--${this.state}" role="status"><span class="jargo-status__dot"></span>${escapeHtml(
180
+ label
181
+ )}</span>`;
182
+ }
183
+ };
184
+ JargoStatusElement.observedAttributes = [
185
+ "label-disconnected",
186
+ "label-connecting",
187
+ "label-connected",
188
+ "label-ready",
189
+ "label-error"
190
+ ];
191
+ var JargoTranscriptElement = class extends JargoClientElement {
192
+ constructor() {
193
+ super();
194
+ this.tracker = null;
195
+ this.messages = [];
196
+ this.style.display = "block";
197
+ }
198
+ bind(client) {
199
+ const tracker = new TranscriptTracker(client);
200
+ this.tracker = tracker;
201
+ this.messages = tracker.getMessages();
202
+ this.track(
203
+ tracker.onChange((m) => {
204
+ this.messages = m;
205
+ this.render();
206
+ })
207
+ );
208
+ this.track(() => {
209
+ tracker.destroy();
210
+ this.tracker = null;
211
+ });
212
+ }
213
+ render() {
214
+ const empty = this.getAttribute("empty-label") ?? "No messages yet.";
215
+ const body = this.messages.length ? this.messages.map(
216
+ (m) => `<div class="jargo-msg jargo-msg--${m.role}" data-streaming="${!m.final}"><span class="jargo-msg__role">${m.role === "user" ? "You" : "Assistant"}</span><span class="jargo-msg__text">${escapeHtml(m.text)}</span></div>`
217
+ ).join("") : `<p class="jargo-transcript__empty">${escapeHtml(empty)}</p>`;
218
+ this.innerHTML = `<div class="jargo-transcript" role="log" aria-live="polite" aria-relevant="additions text" style="height:100%">${body}</div>`;
219
+ const list = this.querySelector(".jargo-transcript");
220
+ if (list) list.scrollTop = list.scrollHeight;
221
+ }
222
+ };
223
+ JargoTranscriptElement.observedAttributes = ["empty-label"];
224
+
225
+ // src/index.ts
226
+ var JargoOrbElement = class extends HTMLElement {
227
+ constructor() {
228
+ super();
229
+ this.orb = null;
230
+ const root = this.attachShadow({ mode: "open" });
231
+ const style = document.createElement("style");
232
+ style.textContent = ":host{display:block;width:220px;height:220px}canvas{display:block;width:100%;height:100%}";
233
+ this.canvas = document.createElement("canvas");
234
+ root.append(style, this.canvas);
235
+ }
236
+ connectedCallback() {
237
+ if (this.orb) return;
238
+ this.orb = new Orb(this.canvas, this.readOptions());
239
+ const level = this.getAttribute("level");
240
+ if (level !== null) this.orb.setLevel(parseFloat(level));
241
+ if (!this.hasAttribute("paused")) this.orb.start();
242
+ }
243
+ disconnectedCallback() {
244
+ this.orb?.destroy();
245
+ this.orb = null;
246
+ }
247
+ attributeChangedCallback(name, _old, value) {
248
+ const orb = this.orb;
249
+ if (!orb) return;
250
+ if (name === "level") {
251
+ if (value !== null) orb.setLevel(parseFloat(value));
252
+ return;
253
+ }
254
+ if (name === "paused") {
255
+ if (value !== null) orb.stop();
256
+ else orb.start();
257
+ return;
258
+ }
259
+ orb.setOptions(this.readOptions());
260
+ }
261
+ /** Drive the orb from a MediaStream (e.g. a bot's remote audio); null detaches. */
262
+ attachStream(stream) {
263
+ this.orb?.attachStream(stream);
264
+ }
265
+ /** Manually set the drive level (0..1). */
266
+ setLevel(level) {
267
+ this.orb?.setLevel(level);
268
+ }
269
+ readOptions() {
270
+ const o = {};
271
+ const num = (attr, key) => {
272
+ const v = this.getAttribute(attr);
273
+ if (v !== null && v !== "") o[key] = parseFloat(v);
274
+ };
275
+ num("rings", "rings");
276
+ num("radius", "radius");
277
+ num("inner-scale", "innerScale");
278
+ num("line-width", "lineWidth");
279
+ num("speed", "speed");
280
+ num("idle-amplitude", "idleAmplitude");
281
+ num("reactivity", "reactivity");
282
+ num("glow", "glow");
283
+ const core = this.getAttribute("core");
284
+ if (core !== null) o.core = core !== "false";
285
+ const blend = this.getAttribute("blend");
286
+ if (blend === "lighter" || blend === "source-over") o.blend = blend;
287
+ const bg = this.getAttribute("background");
288
+ if (bg !== null) o.background = bg;
289
+ const colors = this.getAttribute("colors");
290
+ if (colors) {
291
+ o.colors = OrbPalettes[colors] ?? colors.split(/[,\s]+/).filter(Boolean);
292
+ }
293
+ return o;
294
+ }
295
+ };
296
+ JargoOrbElement.observedAttributes = [
297
+ "rings",
298
+ "radius",
299
+ "inner-scale",
300
+ "line-width",
301
+ "speed",
302
+ "idle-amplitude",
303
+ "reactivity",
304
+ "glow",
305
+ "core",
306
+ "blend",
307
+ "background",
308
+ "colors",
309
+ "level",
310
+ "paused"
311
+ ];
312
+ function define(tag, ctor) {
313
+ if (typeof customElements !== "undefined" && !customElements.get(tag)) {
314
+ customElements.define(tag, ctor);
315
+ }
316
+ }
317
+ function defineJargoOrb(tag = "jargo-orb") {
318
+ define(tag, JargoOrbElement);
319
+ }
320
+ function defineJargoElements() {
321
+ defineJargoOrb();
322
+ define("jargo-connect-button", JargoConnectButtonElement);
323
+ define("jargo-mic-button", JargoMicButtonElement);
324
+ define("jargo-status", JargoStatusElement);
325
+ define("jargo-transcript", JargoTranscriptElement);
326
+ }
327
+
328
+ export {
329
+ setJargoClient,
330
+ getJargoClient,
331
+ JargoClientElement,
332
+ JargoConnectButtonElement,
333
+ JargoMicButtonElement,
334
+ JargoStatusElement,
335
+ JargoTranscriptElement,
336
+ OrbPalettes,
337
+ JargoOrbElement,
338
+ defineJargoOrb,
339
+ defineJargoElements
340
+ };
341
+ //# sourceMappingURL=chunk-JTFSFMFL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/components.ts","../src/client-registry.ts","../src/JargoClientElement.ts"],"sourcesContent":["// @gojargo/jargo-elements — native web components for jargo. The visual\n// <jargo-orb> is built on @gojargo/jargo-ui; the client-driven components\n// (<jargo-connect-button>, <jargo-mic-button>, <jargo-status>,\n// <jargo-transcript>) read a client set via setJargoClient(). Style them all\n// by importing \"@gojargo/jargo-ui/theme.css\" once.\n//\n// import \"@gojargo/jargo-elements/define\";\n// import \"@gojargo/jargo-ui/theme.css\";\n// setJargoClient(new JargoClient({ baseUrl }));\n// // <jargo-orb colors=\"aurora\"></jargo-orb>\n// // <jargo-connect-button></jargo-connect-button>\n\nimport {\n Orb,\n OrbPalettes,\n type OrbOptions,\n type OrbPaletteName,\n} from \"@gojargo/jargo-ui\";\nimport {\n JargoConnectButtonElement,\n JargoMicButtonElement,\n JargoStatusElement,\n JargoTranscriptElement,\n} from \"./components\";\n\nexport { setJargoClient, getJargoClient } from \"./client-registry\";\nexport { JargoClientElement } from \"./JargoClientElement\";\nexport {\n JargoConnectButtonElement,\n JargoMicButtonElement,\n JargoStatusElement,\n JargoTranscriptElement,\n} from \"./components\";\n\n// OrbOptions keys that take a number, mapped from their kebab-case attributes.\ntype NumKey =\n | \"rings\"\n | \"radius\"\n | \"innerScale\"\n | \"lineWidth\"\n | \"speed\"\n | \"idleAmplitude\"\n | \"reactivity\"\n | \"glow\"\n | \"maxDpr\";\n\n/**\n * `<jargo-orb>` — the Orb as a custom element. Size it with CSS (defaults to\n * 220×220). Attributes mirror the Orb options (kebab-case): `rings`, `radius`,\n * `inner-scale`, `line-width`, `speed`, `idle-amplitude`, `reactivity`, `glow`,\n * `core`, `blend`, `background`, plus `colors` (a palette name like `aurora`,\n * or a comma/space-separated list of CSS colors), `level` (0..1), and `paused`.\n *\n * Drive it from live audio with the {@link attachStream} method.\n */\nexport class JargoOrbElement extends HTMLElement {\n static readonly observedAttributes = [\n \"rings\",\n \"radius\",\n \"inner-scale\",\n \"line-width\",\n \"speed\",\n \"idle-amplitude\",\n \"reactivity\",\n \"glow\",\n \"core\",\n \"blend\",\n \"background\",\n \"colors\",\n \"level\",\n \"paused\",\n ];\n\n private orb: Orb | null = null;\n private readonly canvas: HTMLCanvasElement;\n\n constructor() {\n super();\n const root = this.attachShadow({ mode: \"open\" });\n const style = document.createElement(\"style\");\n style.textContent =\n \":host{display:block;width:220px;height:220px}canvas{display:block;width:100%;height:100%}\";\n this.canvas = document.createElement(\"canvas\");\n root.append(style, this.canvas);\n }\n\n connectedCallback(): void {\n if (this.orb) return;\n this.orb = new Orb(this.canvas, this.readOptions());\n const level = this.getAttribute(\"level\");\n if (level !== null) this.orb.setLevel(parseFloat(level));\n if (!this.hasAttribute(\"paused\")) this.orb.start();\n }\n\n disconnectedCallback(): void {\n this.orb?.destroy();\n this.orb = null;\n }\n\n attributeChangedCallback(\n name: string,\n _old: string | null,\n value: string | null,\n ): void {\n const orb = this.orb;\n if (!orb) return;\n if (name === \"level\") {\n if (value !== null) orb.setLevel(parseFloat(value));\n return;\n }\n if (name === \"paused\") {\n if (value !== null) orb.stop();\n else orb.start();\n return;\n }\n orb.setOptions(this.readOptions());\n }\n\n /** Drive the orb from a MediaStream (e.g. a bot's remote audio); null detaches. */\n attachStream(stream: MediaStream | null): void {\n this.orb?.attachStream(stream);\n }\n\n /** Manually set the drive level (0..1). */\n setLevel(level: number): void {\n this.orb?.setLevel(level);\n }\n\n private readOptions(): OrbOptions {\n const o: OrbOptions = {};\n const num = (attr: string, key: NumKey) => {\n const v = this.getAttribute(attr);\n if (v !== null && v !== \"\") o[key] = parseFloat(v);\n };\n num(\"rings\", \"rings\");\n num(\"radius\", \"radius\");\n num(\"inner-scale\", \"innerScale\");\n num(\"line-width\", \"lineWidth\");\n num(\"speed\", \"speed\");\n num(\"idle-amplitude\", \"idleAmplitude\");\n num(\"reactivity\", \"reactivity\");\n num(\"glow\", \"glow\");\n\n const core = this.getAttribute(\"core\");\n if (core !== null) o.core = core !== \"false\";\n const blend = this.getAttribute(\"blend\");\n if (blend === \"lighter\" || blend === \"source-over\") o.blend = blend;\n const bg = this.getAttribute(\"background\");\n if (bg !== null) o.background = bg;\n\n const colors = this.getAttribute(\"colors\");\n if (colors) {\n o.colors =\n (OrbPalettes as Record<string, string[]>)[colors] ??\n colors.split(/[,\\s]+/).filter(Boolean);\n }\n return o;\n }\n}\n\nfunction define(tag: string, ctor: CustomElementConstructor): void {\n if (typeof customElements !== \"undefined\" && !customElements.get(tag)) {\n customElements.define(tag, ctor);\n }\n}\n\n/** Register {@link JargoOrbElement} as `<jargo-orb>` (or a custom tag). */\nexport function defineJargoOrb(tag = \"jargo-orb\"): void {\n define(tag, JargoOrbElement);\n}\n\n/**\n * Register all jargo web components: `<jargo-orb>`, `<jargo-connect-button>`,\n * `<jargo-mic-button>`, `<jargo-status>`, `<jargo-transcript>`.\n */\nexport function defineJargoElements(): void {\n defineJargoOrb();\n define(\"jargo-connect-button\", JargoConnectButtonElement);\n define(\"jargo-mic-button\", JargoMicButtonElement);\n define(\"jargo-status\", JargoStatusElement);\n define(\"jargo-transcript\", JargoTranscriptElement);\n}\n\nexport { OrbPalettes };\nexport type { OrbOptions, OrbPaletteName };\n","import type { JargoClient, TransportState } from \"@gojargo/jargo-client-js\";\nimport { TranscriptTracker, type TranscriptMessage } from \"@gojargo/jargo-client-js\";\nimport { JargoClientElement, escapeHtml, micIcon } from \"./JargoClientElement\";\n\nconst isConnected = (s: TransportState) => s === \"connected\" || s === \"ready\";\n\n/** `<jargo-connect-button>` — start/end the conversation, following the state. */\nexport class JargoConnectButtonElement extends JargoClientElement {\n static readonly observedAttributes = [\n \"label-idle\",\n \"label-connecting\",\n \"label-connected\",\n ];\n private state: TransportState = \"disconnected\";\n\n protected bind(client: JargoClient): void {\n this.state = client.state;\n this.track(\n client.on(\"transportStateChanged\", (s) => {\n this.state = s;\n this.render();\n }),\n );\n }\n\n protected render(): void {\n const conn = isConnected(this.state);\n const connecting = this.state === \"connecting\";\n const label = conn\n ? (this.getAttribute(\"label-connected\") ?? \"End conversation\")\n : connecting\n ? (this.getAttribute(\"label-connecting\") ?? \"Connecting…\")\n : (this.getAttribute(\"label-idle\") ?? \"Start conversation\");\n this.innerHTML = `<button class=\"jargo-btn ${\n conn ? \"jargo-btn--danger\" : \"jargo-btn--primary\"\n }\" ${connecting ? \"disabled aria-busy='true'\" : \"\"}>${\n connecting ? '<span class=\"jargo-spinner\"></span>' : \"\"\n }${escapeHtml(label)}</button>`;\n const btn = this.querySelector(\"button\");\n if (btn) {\n btn.onclick = () => {\n const c = this.jargo;\n if (!c) return;\n if (isConnected(c.state)) c.disconnect();\n else void c.connect().catch(() => {});\n };\n }\n }\n}\n\n/** `<jargo-mic-button>` — mute/unmute the microphone. */\nexport class JargoMicButtonElement extends JargoClientElement {\n static readonly observedAttributes = [\"label-mute\", \"label-unmute\"];\n private state: TransportState = \"disconnected\";\n private enabled = true;\n\n protected bind(client: JargoClient): void {\n this.state = client.state;\n this.enabled = client.micEnabled;\n this.track(\n client.on(\"transportStateChanged\", (s) => {\n this.state = s;\n this.enabled = client.micEnabled;\n this.render();\n }),\n );\n }\n\n protected render(): void {\n const conn = isConnected(this.state);\n const label = this.enabled\n ? (this.getAttribute(\"label-mute\") ?? \"Mute\")\n : (this.getAttribute(\"label-unmute\") ?? \"Unmute\");\n this.innerHTML = `<button class=\"jargo-btn jargo-btn--ghost\" ${\n conn ? \"\" : \"disabled\"\n } aria-pressed=\"${!this.enabled}\" data-muted=\"${!this.enabled}\">${micIcon(\n !this.enabled,\n )}${escapeHtml(label)}</button>`;\n const btn = this.querySelector(\"button\");\n if (btn) {\n btn.onclick = () => {\n const c = this.jargo;\n if (!c) return;\n this.enabled = c.toggleMic();\n this.render();\n };\n }\n }\n}\n\nconst STATUS_LABELS: Record<TransportState, string> = {\n disconnected: \"Offline\",\n connecting: \"Connecting…\",\n connected: \"Connected\",\n ready: \"Live\",\n error: \"Error\",\n};\n\n/** `<jargo-status>` — a badge reflecting the connection state. */\nexport class JargoStatusElement extends JargoClientElement {\n static readonly observedAttributes = [\n \"label-disconnected\",\n \"label-connecting\",\n \"label-connected\",\n \"label-ready\",\n \"label-error\",\n ];\n private state: TransportState = \"disconnected\";\n\n protected bind(client: JargoClient): void {\n this.state = client.state;\n this.track(\n client.on(\"transportStateChanged\", (s) => {\n this.state = s;\n this.render();\n }),\n );\n }\n\n protected render(): void {\n const label =\n this.getAttribute(`label-${this.state}`) ?? STATUS_LABELS[this.state];\n this.innerHTML = `<span class=\"jargo-status jargo-status--${this.state}\" role=\"status\"><span class=\"jargo-status__dot\"></span>${escapeHtml(\n label,\n )}</span>`;\n }\n}\n\n/**\n * `<jargo-transcript>` — an auto-scrolling message list built from the shared\n * {@link TranscriptTracker}. Size it with CSS (defaults to `display:block`).\n */\nexport class JargoTranscriptElement extends JargoClientElement {\n static readonly observedAttributes = [\"empty-label\"];\n private tracker: TranscriptTracker | null = null;\n private messages: TranscriptMessage[] = [];\n\n constructor() {\n super();\n this.style.display = \"block\";\n }\n\n protected bind(client: JargoClient): void {\n const tracker = new TranscriptTracker(client);\n this.tracker = tracker;\n this.messages = tracker.getMessages();\n this.track(\n tracker.onChange((m) => {\n this.messages = m;\n this.render();\n }),\n );\n this.track(() => {\n tracker.destroy();\n this.tracker = null;\n });\n }\n\n protected render(): void {\n const empty = this.getAttribute(\"empty-label\") ?? \"No messages yet.\";\n const body = this.messages.length\n ? this.messages\n .map(\n (m) =>\n `<div class=\"jargo-msg jargo-msg--${m.role}\" data-streaming=\"${!m.final}\"><span class=\"jargo-msg__role\">${\n m.role === \"user\" ? \"You\" : \"Assistant\"\n }</span><span class=\"jargo-msg__text\">${escapeHtml(m.text)}</span></div>`,\n )\n .join(\"\")\n : `<p class=\"jargo-transcript__empty\">${escapeHtml(empty)}</p>`;\n this.innerHTML = `<div class=\"jargo-transcript\" role=\"log\" aria-live=\"polite\" aria-relevant=\"additions text\" style=\"height:100%\">${body}</div>`;\n const list = this.querySelector<HTMLElement>(\".jargo-transcript\");\n if (list) list.scrollTop = list.scrollHeight;\n }\n}\n","// A tiny registry so the client-driven web components can find a JargoClient\n// without a framework's context. Set one client for the page:\n//\n// import { setJargoClient } from \"@gojargo/jargo-elements\";\n// setJargoClient(new JargoClient({ baseUrl }));\n//\n// Individual elements can override it by setting their `.client` property.\n\nimport type { JargoClient } from \"@gojargo/jargo-client-js\";\n\nlet current: JargoClient | null = null;\nconst subscribers = new Set<(client: JargoClient | null) => void>();\n\n/** Set (or clear) the client the jargo web components use by default. */\nexport function setJargoClient(client: JargoClient | null): void {\n current = client;\n subscribers.forEach((fn) => fn(client));\n}\n\n/** The current default client, if any. */\nexport function getJargoClient(): JargoClient | null {\n return current;\n}\n\n/** Subscribe to default-client changes. Returns an unsubscribe function. */\nexport function subscribeJargoClient(\n fn: (client: JargoClient | null) => void,\n): () => void {\n subscribers.add(fn);\n return () => subscribers.delete(fn);\n}\n","import type { JargoClient } from \"@gojargo/jargo-client-js\";\nimport { getJargoClient, subscribeJargoClient } from \"./client-registry\";\n\n/**\n * Base class for client-driven jargo web components. It resolves the client\n * (an explicit `.client` property, else the {@link setJargoClient} registry),\n * re-binds when it changes, and renders in light DOM so the app's\n * `@gojargo/jargo-ui/theme.css` styles apply.\n */\nexport abstract class JargoClientElement extends HTMLElement {\n /** The bound client, available to subclasses in {@link bind}/{@link render}. */\n protected jargo: JargoClient | null = null;\n\n private clientOverride: JargoClient | null = null;\n private offRegistry?: () => void;\n private offs: Array<() => void> = [];\n\n /** Set a specific client, overriding the global {@link setJargoClient} registry. */\n set client(client: JargoClient | null) {\n this.clientOverride = client;\n this.rebind();\n }\n get client(): JargoClient | null {\n return this.clientOverride ?? getJargoClient();\n }\n\n connectedCallback(): void {\n this.offRegistry = subscribeJargoClient(() => {\n if (!this.clientOverride) this.rebind();\n });\n this.rebind();\n }\n\n disconnectedCallback(): void {\n this.offRegistry?.();\n this.teardown();\n }\n\n attributeChangedCallback(): void {\n this.render();\n }\n\n /** Track a cleanup (e.g. an event unsubscribe) tied to the current binding. */\n protected track(off: () => void): void {\n this.offs.push(off);\n }\n\n private rebind(): void {\n this.teardown();\n this.jargo = this.client;\n if (this.jargo) this.bind(this.jargo);\n this.render();\n }\n\n private teardown(): void {\n this.offs.forEach((off) => off());\n this.offs = [];\n }\n\n /** Subscribe to client events here via {@link track}; called on each (re)bind. */\n protected bind(_client: JargoClient): void {}\n\n /** Render the element's light-DOM markup; called on bind and attribute changes. */\n protected abstract render(): void;\n}\n\nexport function escapeHtml(s: string): string {\n return s.replace(\n /[&<>]/g,\n (c) => ({ \"&\": \"&amp;\", \"<\": \"&lt;\", \">\": \"&gt;\" })[c] as string,\n );\n}\n\nexport function micIcon(muted: boolean): string {\n return `<svg class=\"jargo-mic-icon\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"9\" y=\"3\" width=\"6\" height=\"11\" rx=\"3\"/><path d=\"M5 11a7 7 0 0 0 14 0\"/><line x1=\"12\" y1=\"18\" x2=\"12\" y2=\"21\"/>${\n muted ? '<line x1=\"3\" y1=\"3\" x2=\"21\" y2=\"21\"/>' : \"\"\n }</svg>`;\n}\n"],"mappings":"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","names":[]}