@osvi-ai/chat 0.0.0-stage → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1 -3
  3. package/dist/core.js +10 -0
  4. package/dist/core.js.map +1 -0
  5. package/dist/index-HWHyM4-l.js +1331 -0
  6. package/dist/index-HWHyM4-l.js.map +1 -0
  7. package/dist/types/core/client.d.ts +67 -0
  8. package/dist/types/core/connection.d.ts +78 -0
  9. package/dist/types/core/errors.d.ts +14 -0
  10. package/dist/types/core/http.d.ts +38 -0
  11. package/dist/types/core/index.d.ts +7 -0
  12. package/dist/types/core/interactions.d.ts +50 -0
  13. package/dist/types/core/protocol/envelope.d.ts +2 -0
  14. package/dist/types/core/protocol/readers.d.ts +14 -0
  15. package/dist/types/core/protocol/types.d.ts +118 -0
  16. package/dist/types/core/protocol/validators.d.ts +10 -0
  17. package/dist/types/core/state.d.ts +23 -0
  18. package/dist/types/core/storage.d.ts +10 -0
  19. package/dist/types/core/version.d.ts +1 -0
  20. package/dist/types/ui/define.d.ts +1 -0
  21. package/dist/types/ui/icons.d.ts +9 -0
  22. package/dist/types/ui/index.d.ts +9 -0
  23. package/dist/types/ui/osvi-chat.d.ts +70 -0
  24. package/dist/types/ui/panel/attrs.d.ts +6 -0
  25. package/dist/types/ui/panel/composer.d.ts +10 -0
  26. package/dist/types/ui/panel/linkify.d.ts +7 -0
  27. package/dist/types/ui/panel/transcript.d.ts +4 -0
  28. package/dist/types/ui/strings.d.ts +27 -0
  29. package/dist/types/ui/styles.d.ts +1 -0
  30. package/dist/types/ui/theme.d.ts +22 -0
  31. package/dist/types/ui/tools/base.d.ts +14 -0
  32. package/dist/types/ui/tools/osvi-buttons.d.ts +10 -0
  33. package/dist/types/ui/tools/osvi-carousel.d.ts +16 -0
  34. package/dist/types/ui/tools/osvi-date-picker.d.ts +17 -0
  35. package/dist/types/widget/config.d.ts +23 -0
  36. package/dist/types/widget/index.d.ts +1 -0
  37. package/dist/types/widget/launcher.d.ts +35 -0
  38. package/dist/types/widget/widget.d.ts +13 -0
  39. package/dist/ui.js +109 -0
  40. package/dist/ui.js.map +1 -0
  41. package/dist/ui.mjs +646 -0
  42. package/dist/ui.mjs.map +1 -0
  43. package/dist/widget.js +132 -0
  44. package/dist/widget.js.map +1 -0
  45. package/package.json +60 -4
package/dist/ui.mjs ADDED
@@ -0,0 +1,646 @@
1
+ import { nothing as c, html as a, svg as b, LitElement as W, css as X, unsafeCSS as nt } from "lit";
2
+ import { property as l, state as v } from "lit/decorators.js";
3
+ import { c as at, i as ot, a as lt, b as B } from "./index-HWHyM4-l.js";
4
+ import { repeat as dt } from "lit/directives/repeat.js";
5
+ import { live as ct } from "lit/directives/live.js";
6
+ const Z = { primary: "#4f46e5", background: "#ffffff", surface: "#f4f4f5", text: "#18181b", userBubble: "#4f46e5", assistantBubble: "#f4f4f5" }, pt = { primary: "#6366f1", background: "#0a0a12", surface: "#1c1c27", text: "#f4f4f5", userBubble: "#6366f1", assistantBubble: "#1f1f2b" }, ht = { none: "0px", sm: "6px", md: "10px", lg: "16px", full: "9999px" }, C = { primary: "--osvi-color-primary", background: "--osvi-color-background", surface: "--osvi-color-surface", text: "--osvi-color-text", userBubble: "--osvi-color-user-bubble", assistantBubble: "--osvi-color-assistant-bubble" }, ut = (i) => `var(${C[i]}, ${Z[i]})`;
7
+ function E(i) {
8
+ const t = { ...i?.mode === "dark" ? pt : Z, ...i?.colors };
9
+ !i?.colors?.userBubble && i?.colors?.primary && (t.userBubble = i.colors.primary);
10
+ const e = {};
11
+ for (const s of Object.keys(C)) e[C[s]] = t[s];
12
+ const r = i?.radius ?? "md";
13
+ return e["--osvi-radius"] = typeof r == "number" ? `${r}px` : ht[r], e;
14
+ }
15
+ function bt(i) {
16
+ if (!i) return {};
17
+ if (i.mode) return E(i);
18
+ const t = E(i), e = {};
19
+ for (const r of Object.keys(i.colors ?? {})) e[C[r]] = t[C[r]];
20
+ return i.radius !== void 0 && (e["--osvi-radius"] = t["--osvi-radius"]), e;
21
+ }
22
+ const O = /* @__PURE__ */ new WeakMap();
23
+ function Q(i, t) {
24
+ for (const r of O.get(i) ?? []) i.style.removeProperty(r);
25
+ const e = bt(t);
26
+ for (const [r, s] of Object.entries(e)) i.style.setProperty(r, s);
27
+ O.set(i, Object.keys(e));
28
+ }
29
+ const H = {
30
+ placeholder: "Type your message…",
31
+ send: "Send",
32
+ typing: "Typing…",
33
+ humanJoined: "A team member has joined",
34
+ chooseOption: "Choose an option to continue.",
35
+ typeAnswer: "Type your answer below, then press Send.",
36
+ sending: "Sending your response…",
37
+ pausedForHuman: "Choices are paused while a team member is connected.",
38
+ sendFailed: "Message not sent.",
39
+ retry: "Retry",
40
+ sessionEnded: "Conversation ended",
41
+ reconnecting: "Reconnecting…",
42
+ offline: "You are offline. We will reconnect automatically.",
43
+ unavailable: "This chat is unavailable.",
44
+ originBlocked: "This chat is not enabled for this website.",
45
+ rateLimited: "Too many requests. Please try again in a few minutes.",
46
+ tryAgain: "Try again",
47
+ closeChat: "Close chat",
48
+ poweredBy: "Powered by Osvi AI",
49
+ newChat: "New chat",
50
+ emptyState: "Send a message to start chatting.",
51
+ defaultTitle: "Chat"
52
+ }, N = /* @__PURE__ */ new Set();
53
+ function tt(i, t) {
54
+ N.has(i) || (N.add(i), console.warn(`[osvi-chat] ${t}`));
55
+ }
56
+ function x(i, t) {
57
+ return i != null && t.includes(i) ? i : void 0;
58
+ }
59
+ function K(i) {
60
+ if (i != null)
61
+ return x(i, ["none", "sm", "md", "lg", "full"]) ?? (/^\d{1,2}(?:px)?$/.test(i) ? Number(i.replace(/px$/, "")) : void 0);
62
+ }
63
+ function V(i) {
64
+ if (i) {
65
+ try {
66
+ const t = new URL(i);
67
+ if (!t.username && !t.password && (t.protocol === "https:" || t.protocol === "http:" && ["localhost", "127.0.0.1"].includes(t.hostname))) return i.replace(/\/+$/, "");
68
+ } catch {
69
+ }
70
+ tt("base-url", "ignored an invalid base-url (https required, http only for localhost)");
71
+ }
72
+ }
73
+ function ft(i) {
74
+ if (i) {
75
+ if (/^data:image\/(png|jpeg|gif|webp);base64,[a-z0-9+/]+={0,2}$/i.test(i)) return i;
76
+ try {
77
+ const t = new URL(i);
78
+ if (t.protocol === "https:" && !t.username && !t.password) return i;
79
+ } catch {
80
+ }
81
+ }
82
+ }
83
+ function J(i, t) {
84
+ if (t) {
85
+ try {
86
+ const e = JSON.parse(t);
87
+ if (e && typeof e == "object" && !Array.isArray(e)) return e;
88
+ } catch {
89
+ }
90
+ tt(i, `ignored invalid JSON in the ${i} attribute`);
91
+ }
92
+ }
93
+ const gt = /https?:\/\/[^\s<>"']+/g, S = (i, t) => i.split(t).length - 1;
94
+ function vt(i) {
95
+ for (; ; ) {
96
+ const t = i[i.length - 1];
97
+ if (t && ".,!?;:".includes(t) || t === ")" && S(i, ")") > S(i, "(") || t === "]" && S(i, "]") > S(i, "[")) {
98
+ i = i.slice(0, -1);
99
+ continue;
100
+ }
101
+ return i;
102
+ }
103
+ }
104
+ function mt(i) {
105
+ const t = [];
106
+ let e = 0;
107
+ for (const r of i.matchAll(gt)) {
108
+ const s = vt(r[0]), n = r.index;
109
+ try {
110
+ const o = new URL(s);
111
+ if (!["http:", "https:"].includes(o.protocol)) continue;
112
+ } catch {
113
+ continue;
114
+ }
115
+ n > e && t.push({ text: i.slice(e, n) }), t.push({ href: s, text: s }), e = n + s.length;
116
+ }
117
+ return e < i.length && t.push({ text: i.slice(e) }), t.length ? t : [{ text: i }];
118
+ }
119
+ function yt(i, t, e, r, s) {
120
+ return a`${i.items.length ? dt(i.items, (n) => n.id, (n) => {
121
+ if (n.kind === "divider") return a`<p class="divider">${t.sessionEnded}</p>`;
122
+ if (n.kind === "message") return a`<article class=${`bubble ${n.role}`}>${n.role === "human" ? a`<small class="team">Team</small>` : c}<p>${mt(n.content).map((k) => "href" in k ? a`<a href=${k.href} target="_blank" rel="noopener noreferrer">${k.text}</a>` : k.text)}</p>${n.role === "user" && n.status === "failed" ? a`<span class="failed"><span>${t.sendFailed}</span><button type="button" @click=${() => s(n.id)}>${t.retry}</button></span>` : c}</article>`;
123
+ const o = n.interaction, h = o.interaction_id === i.activeInteraction?.interaction_id && o.interaction_status === "pending", f = !h || i.interactionPending || i.mode === "human";
124
+ switch (o.tool_type) {
125
+ case "ui_buttons":
126
+ return a`<osvi-buttons data-live=${h ? "true" : "false"} .interaction=${o} .disabled=${f} .variant=${e.buttons ?? "chips"} base-url=${r}></osvi-buttons>`;
127
+ case "ui_carousel":
128
+ return a`<osvi-carousel data-live=${h ? "true" : "false"} .interaction=${o} .disabled=${f} .variant=${e.carousel ?? "slider"} base-url=${r}></osvi-carousel>`;
129
+ case "ui_date_picker":
130
+ return a`<osvi-date-picker data-live=${h ? "true" : "false"} .interaction=${o} .disabled=${f} base-url=${r}></osvi-date-picker>`;
131
+ default:
132
+ return a`<p>${o.content}</p>`;
133
+ }
134
+ }) : a`<p class="empty">${t.emptyState}</p>`}${i.awaitingReply ? a`<div class="typing" role="img" aria-label=${t.typing}><i></i><i></i><i></i></div>` : c}`;
135
+ }
136
+ const m = (i, t = "") => b`<svg class=${t} viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">${i}</svg>`;
137
+ m(b`<path d="M4 5.5A2.5 2.5 0 0 1 6.5 3h11A2.5 2.5 0 0 1 20 5.5v8a2.5 2.5 0 0 1-2.5 2.5H10l-4.2 3.6c-.5.4-1.3.1-1.3-.6V16A2.5 2.5 0 0 1 4 13.5z"/><path d="M8.5 8.5h7M8.5 11.5h4"/>`);
138
+ const xt = m(b`<path d="M4 5.5A2.5 2.5 0 0 1 6.5 3h11A2.5 2.5 0 0 1 20 5.5v8a2.5 2.5 0 0 1-2.5 2.5H10l-4.2 3.6c-.5.4-1.3.1-1.3-.6V16A2.5 2.5 0 0 1 4 13.5z"/><path d="M12 6.5v6M9 9.5h6"/>`), $t = m(b`<path d="M6 6l12 12M18 6L6 18"/>`);
139
+ m(b`<path d="M4 5.5A2.5 2.5 0 0 1 6.5 3h11A2.5 2.5 0 0 1 20 5.5v8a2.5 2.5 0 0 1-2.5 2.5H10l-4.2 3.6c-.5.4-1.3.1-1.3-.6V16A2.5 2.5 0 0 1 4 13.5z"/><path d="M8.5 8.5h7M8.5 11.5h4"/>`, "chat");
140
+ m(b`<path d="M6 6l12 12M18 6L6 18"/>`, "close");
141
+ const wt = m(b`<path d="M12 19V5M5.5 11.5L12 5l6.5 6.5"/>`), et = m(b`<path d="M15 6l-6 6 6 6"/>`), R = m(b`<path d="M9 6l6 6-6 6"/>`), kt = b`<svg viewBox="0 0 134 134" aria-hidden="true" focusable="false"><defs><linearGradient id="osvi-g" x1="-36.28" y1="32.2" x2="161.98" y2="93.64" gradientUnits="userSpaceOnUse"><stop offset=".304" stop-color="#155DFC"/><stop offset=".822" stop-color="#353333"/></linearGradient><mask id="osvi-m" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="-7" y="-6" width="149" height="150"><path fill-rule="evenodd" clip-rule="evenodd" fill="#0F0F0F" d="M141.385 114.008L141.622 108.411V29.4704L141.385 23.8743C139.964 7.44314 126.224 -5.41602 109.523 -5.41602H25.3094C8.60869 -5.41602 -5.13083 7.44314 -6.55216 23.8743L-6.78906 29.4704V108.411L-6.55216 114.008C-5.13083 130.439 8.60869 143.298 25.3094 143.298H109.523C126.224 143.298 139.964 130.439 141.385 114.008ZM25.3094 102.339C9.55625 102.339 65.7059 83.8874 53.6176 66.6191C42.3654 50.5452 93.7703 32.6852 109.523 32.6852C125.277 32.6852 73.161 54.1172 81.4521 80.9071C86.1899 96.2156 40.944 102.339 25.3094 102.339Z"/></mask></defs><g mask="url(#osvi-m)"><ellipse cx="66.88" cy="66.79" rx="67.22" ry="66.81" fill="url(#osvi-g)"/></g></svg>`;
142
+ function _t(i) {
143
+ return a`<div class="composer"><textarea rows="1" aria-label="Message" placeholder=${i.placeholder} .value=${ct(i.draft)} ?disabled=${i.disabled} @input=${(t) => {
144
+ const e = t.target;
145
+ e.style.height = "auto", e.style.height = `${Math.min(e.scrollHeight, 120)}px`, i.input(t);
146
+ }} @keydown=${(t) => {
147
+ t.key === "Enter" && !t.shiftKey && !t.isComposing && !i.disabled && (t.preventDefault(), i.send());
148
+ }}></textarea><button type="button" class="send" title=${i.strings.send} aria-label=${i.strings.send} ?disabled=${i.disabled || !i.draft.trim()} @click=${i.send}>${wt}<span class="sr">${i.strings.send}</span></button></div>`;
149
+ }
150
+ var Ct = Object.defineProperty, p = (i, t, e, r) => {
151
+ for (var s = void 0, n = i.length - 1, o; n >= 0; n--)
152
+ (o = i[n]) && (s = o(t, e, s) || s);
153
+ return s && Ct(t, e, s), s;
154
+ };
155
+ const G = () => ({ status: "idle", mode: "ai", awaitingReply: !1, items: [], activeInteraction: null, interactionPending: !1, agent: null, error: null }), it = { fromAttribute: (i) => i !== "false" };
156
+ var g;
157
+ const d = (g = class extends W {
158
+ constructor() {
159
+ super(...arguments), this.agentId = "", this.baseUrl = "", this.client = null, this.theme = {}, this.variants = {}, this.strings = {}, this.poweredBy = !0, this.newChat = !0, this.header = {}, this.closable = !1, this.chatState = G(), this.draft = "", this.busy = !1, this.typed = null, this.ownClient = null, this.boundClient = null, this.ownKey = "", this.generation = 0, this.followBottom = !0, this.focusedInteraction = null, this.send = () => {
160
+ if (this.blocked || !this.draft.trim() || !this.boundClient) return;
161
+ const t = this.boundClient, e = this.draft.trim(), r = this.typed;
162
+ this.draft = "", r && this.restoreDraft(), this.requestUpdate();
163
+ const s = this.renderRoot.querySelector("textarea");
164
+ s && (s.style.height = ""), this.run(() => r ? t.respond(r.id, { kind: "text", value: e }) : t.send(e));
165
+ }, this.respond = (t) => {
166
+ const e = t.detail, r = this.chatState;
167
+ if (!e || this.busy || r.mode !== "ai" || r.interactionPending || r.activeInteraction?.interaction_status !== "pending" || e.interactionId !== r.activeInteraction.interaction_id) return;
168
+ t.stopPropagation();
169
+ const s = this.boundClient;
170
+ s && this.run(() => s.respond(e.interactionId, e.response));
171
+ }, this.requestInput = (t) => {
172
+ const e = t.detail, r = this.chatState;
173
+ !e || this.busy || r.mode !== "ai" || r.interactionPending || r.activeInteraction?.interaction_status !== "pending" || e.interactionId !== r.activeInteraction.interaction_id || (t.stopPropagation(), this.typed = { id: e.interactionId, placeholder: typeof e.placeholder == "string" ? e.placeholder : void 0, previousDraft: this.typed?.previousDraft ?? this.draft }, this.draft = "", this.requestUpdate(), this.updateComplete.then(() => this.renderRoot.querySelector("textarea")?.focus()));
174
+ };
175
+ }
176
+ connectedCallback() {
177
+ super.connectedCallback(), this.syncClient();
178
+ }
179
+ disconnectedCallback() {
180
+ super.disconnectedCallback(), this.releaseClient();
181
+ }
182
+ releaseClient() {
183
+ ++this.generation, this.unsubscribe?.(), this.unsubscribe = void 0, this.boundClient = null;
184
+ const t = this.ownClient;
185
+ this.ownClient = null, this.ownKey = "", t?.destroy(), this.busy = !1, this.typed = null, this.focusedInteraction = null, this.requestUpdate();
186
+ }
187
+ syncClient() {
188
+ if (!this.isConnected || !this.client && !this.agentId && !this.boundClient) return;
189
+ const t = JSON.stringify([this.agentId, V(this.baseUrl)]);
190
+ if ((this.client ? this.boundClient === this.client && !this.ownClient : this.ownClient && t === this.ownKey) || (this.releaseClient(), this.chatState = G(), !this.client && !this.agentId)) return;
191
+ const e = !this.client, r = this.client ?? g.clientFactory({ agentId: this.agentId, baseUrl: V(this.baseUrl) });
192
+ this.boundClient = r, e && (this.ownClient = r, this.ownKey = t);
193
+ const s = this.generation;
194
+ this.chatState = r.getState(), this.requestUpdate(), this.unsubscribe = r.subscribe((n) => {
195
+ this.generation !== s || this.boundClient !== r || (this.chatState = n, this.requestUpdate(), this.typed && (n.mode === "human" || n.activeInteraction?.interaction_id !== this.typed.id || n.activeInteraction.interaction_status !== "pending") && this.restoreDraft());
196
+ }), e && this.run(() => r.start());
197
+ }
198
+ willUpdate() {
199
+ this.syncClient(), Q(this, this.mergedTheme());
200
+ }
201
+ mergedTheme() {
202
+ const t = J("theme", this.themeAttribute), e = {}, r = t?.colors;
203
+ if (r && typeof r == "object" && !Array.isArray(r))
204
+ for (const o of ["primary", "background", "surface", "text", "userBubble", "assistantBubble"]) {
205
+ const h = r[o];
206
+ typeof h == "string" && (e[o] = h);
207
+ }
208
+ typeof this.primaryColor == "string" && (e.primary = this.primaryColor);
209
+ const s = K(this.radius) ?? (typeof t?.radius == "number" && Number.isInteger(t.radius) && t.radius >= 0 && t.radius <= 99 ? t.radius : typeof t?.radius == "string" ? K(t.radius) : void 0), n = x(this.mode, ["light", "dark"]) ?? x(typeof t?.mode == "string" ? t.mode : void 0, ["light", "dark"]);
210
+ return { ...this.theme, colors: { ...this.theme?.colors, ...e }, ...s === void 0 ? {} : { radius: s }, ...n === void 0 ? {} : { mode: n } };
211
+ }
212
+ get labels() {
213
+ const t = { ...H };
214
+ for (const e of [this.strings, J("strings", this.stringsAttribute)])
215
+ for (const r of Object.keys(H)) typeof e?.[r] == "string" && (t[r] = e[r]);
216
+ return t;
217
+ }
218
+ get blocked() {
219
+ const t = this.chatState;
220
+ return !this.boundClient || this.busy || t.status === "connecting" || t.status === "closed" && !!t.error && !t.error.retryable || t.mode === "ai" && (t.interactionPending || t.activeInteraction?.interaction_status === "pending" && !this.typed);
221
+ }
222
+ get sessionBusy() {
223
+ return this.busy || this.chatState.status === "connecting" || this.chatState.interactionPending || this.chatState.items.some((t) => t.kind === "message" && t.status === "sending");
224
+ }
225
+ async run(t) {
226
+ if (this.busy || !this.boundClient) return;
227
+ const e = this.generation;
228
+ this.busy = !0, this.requestUpdate();
229
+ try {
230
+ await t();
231
+ } catch {
232
+ } finally {
233
+ this.generation === e && (this.busy = !1, this.requestUpdate());
234
+ }
235
+ }
236
+ restoreDraft() {
237
+ this.typed && (this.draft = this.typed.previousDraft, this.typed = null, this.requestUpdate());
238
+ }
239
+ async focusActiveInteraction() {
240
+ if (await this.updateComplete, !this.isConnected || this.chatState.activeInteraction?.interaction_status !== "pending") return;
241
+ const t = this.renderRoot.querySelector('[data-live="true"]');
242
+ if (!t) return;
243
+ const e = this.chatState.activeInteraction.interaction_id;
244
+ await t.updateComplete, !(!this.isConnected || this.chatState.activeInteraction?.interaction_id !== e) && t.shadowRoot?.querySelector('button:not(:disabled),input:not(:disabled),select:not(:disabled),textarea:not(:disabled),[tabindex="0"]')?.focus();
245
+ }
246
+ updated() {
247
+ const t = this.renderRoot.querySelector(".transcript");
248
+ t && this.followBottom && (t.scrollTop = t.scrollHeight);
249
+ const e = this.chatState.activeInteraction?.interaction_status === "pending" ? this.chatState.activeInteraction.interaction_id : null;
250
+ e !== this.focusedInteraction && (this.focusedInteraction = e, e && this.isConnected && !this.hidden && document.visibilityState !== "hidden" && this.focusActiveInteraction());
251
+ }
252
+ statusText(t) {
253
+ const e = this.chatState;
254
+ return e.error?.code === "origin_not_allowed" ? t.originBlocked : e.error && ["agent_inactive", "agent_archived", "agent_not_found"].includes(e.error.code) ? t.unavailable : e.error?.code === "rate_limited" ? t.rateLimited : e.error?.code === "token_failed" ? e.error.message : e.status === "recovering" ? t.reconnecting : e.status === "offline" ? t.offline : e.interactionPending || this.busy && this.typed ? t.sending : e.activeInteraction?.interaction_status === "pending" ? e.mode === "human" ? t.pausedForHuman : this.typed ? t.typeAnswer : t.chooseOption : e.status === "closed" ? t.sessionEnded : "";
255
+ }
256
+ render() {
257
+ const t = this.labels, e = this.chatState, r = this.boundClient, s = ft(this.headerAvatar ?? this.header.avatarUrl), n = { ...this.variants, ...x(this.buttons, ["chips", "list"]) ? { buttons: x(this.buttons, ["chips", "list"]) } : {}, ...x(this.carousel, ["slider", "list"]) ? { carousel: x(this.carousel, ["slider", "list"]) } : {} }, o = this.headerTitle ?? this.header.title ?? e.agent?.name ?? t.defaultTitle;
258
+ return a`<header>${s ? a`<img class="avatar" src=${s} alt="" referrerpolicy="no-referrer">` : a`<span class="avatar" aria-hidden="true">${o.trim().charAt(0).toUpperCase()}</span>`}<div class="heading"><h2>${o}</h2>${this.headerSubtitle ?? this.header.subtitle ? a`<p>${this.headerSubtitle ?? this.header.subtitle}</p>` : c}${e.mode === "human" ? a`<small>${t.humanJoined}</small>` : c}</div>
259
+ ${this.newChat ? a`<button type="button" class="icon" title=${t.newChat} ?disabled=${!r || this.sessionBusy} @click=${() => r && !this.sessionBusy && void this.run(() => r.newSession({ keepHistory: this.newChatHistory === "keep" }))}>${xt}<span class="sr">${t.newChat}</span></button>` : c}
260
+ ${this.closable ? a`<button type="button" class="icon" title=${t.closeChat} aria-label=${t.closeChat} @click=${() => this.dispatchEvent(new CustomEvent("osvi-close", { bubbles: !0, composed: !0 }))}>${$t}</button>` : c}</header>
261
+ <div class="transcript" role="log" aria-live="polite" aria-label="Conversation" @scroll=${(h) => {
262
+ const f = h.currentTarget;
263
+ this.followBottom = f.scrollHeight - f.scrollTop - f.clientHeight <= 80;
264
+ }} @osvi-respond=${this.respond} @osvi-request-input=${this.requestInput}>${yt(e, t, n, r?.resolveUrl("") ?? "", (h) => {
265
+ r && this.run(() => r.retry(h));
266
+ })}</div>
267
+ <div class="status" role="status">${this.statusText(t)}${e.error?.retryable && (e.status === "idle" || e.status === "closed") ? a`<button type="button" ?disabled=${this.busy || !r} @click=${() => r && void this.run(() => r.start())}>${t.tryAgain}</button>` : c}</div>
268
+ ${_t({ strings: t, draft: this.draft, placeholder: this.typed?.placeholder ?? t.placeholder, disabled: this.blocked, input: (h) => {
269
+ this.draft = h.target.value, this.requestUpdate();
270
+ }, send: this.send })}
271
+ ${this.poweredBy ? a`<footer><a href="https://osvi.ai" target="_blank" rel="noopener noreferrer">${kt}<span>${t.poweredBy}</span></a></footer>` : c}`;
272
+ }
273
+ }, g.clientFactory = at, g.properties = { themeAttribute: { attribute: "theme" }, stringsAttribute: { attribute: "strings" } }, g.styles = X`
274
+ :host { --p:var(--osvi-color-primary,#4f46e5); --bg:var(--osvi-color-background,#fff); --surface:var(--osvi-color-surface,#f4f4f5); --text:var(--osvi-color-text,#18181b);
275
+ --ub:var(--osvi-color-user-bubble,var(--p)); --ab:var(--osvi-color-assistant-bubble,var(--surface)); --r:var(--osvi-radius,14px);
276
+ --sub:color-mix(in srgb,var(--text) 58%,var(--bg)); --line:color-mix(in srgb,var(--text) 11%,var(--bg));
277
+ display:flex; flex-direction:column; height:100%; min-height:260px; color:var(--text); background:var(--bg); font-family:inherit; font-size:14px; line-height:1.5; border-radius:var(--r); overflow:hidden; }
278
+ * { box-sizing:border-box; } h2,p { margin:0; }
279
+ button,textarea { font:inherit; color:inherit; } button { cursor:pointer; } button:disabled { cursor:default; opacity:.45; }
280
+ button:focus-visible,textarea:focus-visible,a:focus-visible { outline:3px solid color-mix(in srgb,var(--p) 55%,transparent); outline-offset:2px; }
281
+ .sr { position:absolute; width:1px; height:1px; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; }
282
+ header { display:flex; align-items:center; gap:12px; padding:14px 12px 14px 16px; border-bottom:1px solid var(--line); }
283
+ .avatar { width:38px; height:38px; border-radius:50%; flex:none; object-fit:cover; display:grid; place-items:center; background:var(--p); color:#fff; font-weight:700; font-size:15px; }
284
+ .heading { flex:1; min-width:0; } h2 { font-size:15px; line-height:1.3; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
285
+ .heading p,.heading small { display:block; font-size:12.5px; color:var(--sub); }
286
+ .heading small { color:var(--p); font-weight:600; }
287
+ .icon { width:34px; height:34px; border:0; border-radius:10px; background:transparent; color:var(--sub); display:grid; place-items:center; flex:none; }
288
+ .icon:hover:not(:disabled) { background:var(--surface); color:var(--text); } .icon svg { width:18px; height:18px; }
289
+ .transcript { flex:1; overflow:auto; padding:18px 16px; min-height:0; display:flex; flex-direction:column; gap:10px; }
290
+ .empty { margin:auto; color:var(--sub); text-align:center; }
291
+ .bubble { width:fit-content; max-width:84%; padding:10px 14px; border-radius:var(--r); border-bottom-left-radius:6px; background:var(--ab); overflow-wrap:anywhere; white-space:pre-wrap; }
292
+ .bubble.user { align-self:flex-end; color:#fff; background:var(--ub); border-bottom-left-radius:var(--r); border-bottom-right-radius:6px; }
293
+ .bubble a { color:inherit; } .team { display:block; font-size:11px; font-weight:600; color:var(--p); margin-bottom:2px; }
294
+ .failed { display:flex; align-items:center; gap:8px; font-size:12px; margin-top:6px; } .failed button { border:0; background:rgb(255 255 255/.2); border-radius:8px; padding:2px 8px; }
295
+ .divider { display:flex; align-items:center; gap:10px; color:var(--sub); font-size:12px; } .divider::before,.divider::after { content:""; flex:1; height:1px; background:var(--line); }
296
+ .typing { display:inline-flex; gap:4px; padding:12px 14px; background:var(--ab); border-radius:var(--r); border-bottom-left-radius:6px; width:fit-content; }
297
+ .typing i { width:6px; height:6px; border-radius:50%; background:var(--sub); animation:osvi-dot 1.2s infinite; } .typing i:nth-child(2) { animation-delay:.15s; } .typing i:nth-child(3) { animation-delay:.3s; }
298
+ @keyframes osvi-dot { 0%,60%,100% { opacity:.35; transform:none; } 30% { opacity:1; transform:translateY(-3px); } }
299
+ osvi-buttons,osvi-carousel,osvi-date-picker { display:block; max-width:100%; }
300
+ .status { padding:0 16px; font-size:12.5px; color:var(--sub); display:flex; gap:8px; align-items:center; } .status:empty { display:none; }
301
+ .status button { border:1px solid var(--line); background:var(--bg); border-radius:8px; padding:3px 10px; }
302
+ .composer { margin:10px 12px; display:flex; align-items:flex-end; gap:8px; border:1px solid var(--line); border-radius:18px; padding:6px 6px 6px 14px; background:var(--surface); }
303
+ .composer:focus-within { border-color:var(--p); box-shadow:0 0 0 3px color-mix(in srgb,var(--p) 18%,transparent); }
304
+ textarea { flex:1; min-width:0; border:0; outline:0; background:transparent; resize:none; min-height:24px; max-height:120px; padding:6px 0; field-sizing:content; }
305
+ textarea::placeholder { color:var(--sub); } textarea:focus-visible { outline:0; }
306
+ .send { width:36px; height:36px; border:0; border-radius:50%; background:var(--p); color:#fff; display:grid; place-items:center; flex:none; } .send svg { width:17px; height:17px; }
307
+ footer { padding:0 16px 12px; text-align:center; font-size:11.5px; } footer a { color:var(--sub); text-decoration:none; display:inline-flex; align-items:center; gap:6px; }
308
+ footer a:hover { color:var(--text); } footer svg { width:14px; height:14px; flex:none; }
309
+ @media (prefers-reduced-motion:reduce) { .typing i { animation:none; } }
310
+ `, g);
311
+ p([
312
+ l({ attribute: "agent-id" })
313
+ ], d.prototype, "agentId");
314
+ p([
315
+ l({ attribute: "base-url" })
316
+ ], d.prototype, "baseUrl");
317
+ p([
318
+ l({ attribute: !1 })
319
+ ], d.prototype, "client");
320
+ p([
321
+ l({ attribute: !1 })
322
+ ], d.prototype, "theme");
323
+ p([
324
+ l({ attribute: !1 })
325
+ ], d.prototype, "variants");
326
+ p([
327
+ l({ attribute: !1 })
328
+ ], d.prototype, "strings");
329
+ p([
330
+ l({ attribute: "powered-by", converter: it })
331
+ ], d.prototype, "poweredBy");
332
+ p([
333
+ l({ attribute: "new-chat", converter: it })
334
+ ], d.prototype, "newChat");
335
+ p([
336
+ l({ attribute: "new-chat-history" })
337
+ ], d.prototype, "newChatHistory");
338
+ p([
339
+ l({ attribute: !1 })
340
+ ], d.prototype, "header");
341
+ p([
342
+ l({ type: Boolean })
343
+ ], d.prototype, "closable");
344
+ p([
345
+ l({ attribute: "header-title" })
346
+ ], d.prototype, "headerTitle");
347
+ p([
348
+ l({ attribute: "header-subtitle" })
349
+ ], d.prototype, "headerSubtitle");
350
+ p([
351
+ l({ attribute: "header-avatar" })
352
+ ], d.prototype, "headerAvatar");
353
+ p([
354
+ l({ attribute: "primary-color" })
355
+ ], d.prototype, "primaryColor");
356
+ p([
357
+ l()
358
+ ], d.prototype, "radius");
359
+ p([
360
+ l()
361
+ ], d.prototype, "mode");
362
+ p([
363
+ l()
364
+ ], d.prototype, "buttons");
365
+ p([
366
+ l()
367
+ ], d.prototype, "carousel");
368
+ p([
369
+ v()
370
+ ], d.prototype, "chatState");
371
+ p([
372
+ v()
373
+ ], d.prototype, "draft");
374
+ p([
375
+ v()
376
+ ], d.prototype, "busy");
377
+ p([
378
+ v()
379
+ ], d.prototype, "typed");
380
+ let St = d;
381
+ function U(i, t) {
382
+ typeof customElements > "u" || customElements.get(i) || customElements.define(i, t);
383
+ }
384
+ const I = (i) => nt(ut(i)), D = X`
385
+ :host { --p:${I("primary")}; --bg:${I("background")}; --surface:${I("surface")}; --text:${I("text")}; --r:var(--osvi-radius,14px);
386
+ --sub:color-mix(in srgb,var(--text) 58%,var(--bg)); --line:color-mix(in srgb,var(--text) 11%,var(--bg));
387
+ display:block; font:inherit; color:var(--text); }
388
+ * { box-sizing:border-box; }
389
+ p { margin:0 0 6px; } .label { font-weight:600; } .description { color:var(--sub); font-size:13px; }
390
+ .answer { display:inline-block; margin-top:2px; padding:4px 10px; border-radius:999px; background:color-mix(in srgb,var(--p) 12%,var(--bg)); color:var(--p); font-weight:600; font-size:13px; }
391
+ .sr { position:absolute; width:1px; height:1px; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; }
392
+ button { font:inherit; color:inherit; cursor:pointer; }
393
+ button:focus-visible { outline:3px solid color-mix(in srgb,var(--p) 55%,transparent); outline-offset:2px; }
394
+ button:disabled { opacity:.45; cursor:default; }
395
+ small { display:block; color:var(--sub); font-size:12px; font-weight:400; }
396
+ .chips { display:flex; flex-wrap:wrap; gap:8px; }
397
+ .chips button { border:1.5px solid color-mix(in srgb,var(--p) 55%,var(--line)); background:var(--bg); color:var(--p); border-radius:999px; padding:7px 14px; font-weight:600; font-size:13px; text-align:center; }
398
+ .chips button:hover:not(:disabled) { background:color-mix(in srgb,var(--p) 10%,var(--bg)); }
399
+ .text { display:grid; gap:1px; min-width:0; }
400
+ .chips small { color:inherit; opacity:.8; }
401
+ .list { display:grid; gap:6px; }
402
+ .list > button { display:flex; justify-content:space-between; align-items:center; gap:10px; width:100%; text-align:left; border:1px solid var(--line); background:var(--bg); border-radius:12px; padding:10px 12px; }
403
+ .list > button:hover:not(:disabled) { border-color:var(--p); }
404
+ .list > button svg { width:16px; height:16px; flex:none; color:var(--sub); }
405
+ .card { background:var(--bg); border:1px solid var(--line); border-radius:var(--r); overflow:hidden; box-shadow:0 6px 18px -10px rgb(16 18 30/.35); }
406
+ .card .body { padding:10px 12px 12px; display:grid; gap:4px; } .card h3 { margin:0; font-size:14px; } .card p { margin:0; color:var(--sub); font-size:12.5px; }
407
+ .image { aspect-ratio:16 / 9; max-width:100%; display:grid; place-items:center; overflow:hidden; background:var(--surface); color:var(--sub); font-size:12px; }
408
+ .image img { width:100%; height:100%; object-fit:cover; display:block; }
409
+ .primary { justify-self:start; margin-top:6px; border:0; border-radius:10px; background:var(--p); color:#fff; font-weight:600; font-size:13px; padding:8px 14px; }
410
+ .list .card { display:grid; grid-template-columns:minmax(0,88px) 1fr; } .list .card .image { aspect-ratio:auto; height:100%; min-height:88px; }
411
+ .list .card:not(:has(.image)) { grid-template-columns:1fr; }
412
+ .navigation { display:flex; align-items:center; justify-content:space-between; gap:8px; margin:10px 0 0; }
413
+ .round { width:32px; height:32px; border-radius:50%; border:1px solid var(--line); background:var(--bg); display:grid; place-items:center; padding:0; flex:none; }
414
+ .round:hover:not(:disabled) { border-color:var(--p); } .round svg { width:15px; height:15px; }
415
+ .dots { display:flex; gap:5px; align-items:center; } .dots i { width:6px; height:6px; border-radius:3px; background:var(--line); transition:width .2s; } .dots i.on { width:16px; background:var(--p); }
416
+ .calendar { border:1px solid var(--line); border-radius:var(--r); padding:10px; background:var(--bg); display:grid; gap:6px; }
417
+ .calendar .navigation { margin:0; font-weight:600; font-size:13px; }
418
+ .days, .weekdays { display:grid; grid-template-columns:repeat(7, minmax(0, 1fr)); gap:2px 0; text-align:center; }
419
+ .weekdays { color:var(--sub); font-size:11px; }
420
+ .days button { border:0; background:transparent; height:30px; border-radius:8px; padding:0; font-size:12.5px; font-variant-numeric:tabular-nums; }
421
+ .days button:hover:not(:disabled) { background:var(--surface); }
422
+ .days button.today { box-shadow:inset 0 0 0 1.5px var(--line); }
423
+ .days button.in { background:color-mix(in srgb,var(--p) 14%,transparent); border-radius:0; }
424
+ .days button[aria-pressed="true"] { background:var(--p); color:#fff; }
425
+ .days button.start:not(.end) { border-radius:8px 0 0 8px; } .days button.end:not(.start) { border-radius:0 8px 8px 0; }
426
+ .hint { color:var(--sub); font-size:12px; margin:0; }
427
+ @media (prefers-reduced-motion:reduce) { .dots i { transition:none; } }
428
+ `;
429
+ var It = Object.defineProperty, P = (i, t, e, r) => {
430
+ for (var s = void 0, n = i.length - 1, o; n >= 0; n--)
431
+ (o = i[n]) && (s = o(t, e, s) || s);
432
+ return s && It(t, e, s), s;
433
+ };
434
+ class w extends W {
435
+ constructor() {
436
+ super(...arguments), this.interaction = null, this.disabled = !1, this.baseUrl = "";
437
+ }
438
+ get live() {
439
+ return !this.disabled && this.interaction?.interaction_status === "pending";
440
+ }
441
+ get valid() {
442
+ const t = this.interaction;
443
+ return !!t && t.tool_type === this.toolType && ot(t, t.presentation);
444
+ }
445
+ respond(t) {
446
+ !this.interaction || !this.live || !this.valid || this.dispatchEvent(new CustomEvent("osvi-respond", { bubbles: !0, composed: !0, detail: { interactionId: this.interaction.interaction_id, response: t } }));
447
+ }
448
+ updated(t) {
449
+ t.has("theme") && Q(this, this.theme);
450
+ }
451
+ }
452
+ P([
453
+ l({ attribute: !1 })
454
+ ], w.prototype, "interaction");
455
+ P([
456
+ l({ type: Boolean })
457
+ ], w.prototype, "disabled");
458
+ P([
459
+ l({ attribute: !1 })
460
+ ], w.prototype, "theme");
461
+ P([
462
+ l({ attribute: "base-url" })
463
+ ], w.prototype, "baseUrl");
464
+ var At = Object.defineProperty, Mt = (i, t, e, r) => {
465
+ for (var s = void 0, n = i.length - 1, o; n >= 0; n--)
466
+ (o = i[n]) && (s = o(t, e, s) || s);
467
+ return s && At(t, e, s), s;
468
+ };
469
+ const j = class j extends w {
470
+ constructor() {
471
+ super(...arguments), this.toolType = "ui_buttons", this.variant = "chips";
472
+ }
473
+ render() {
474
+ const t = this.interaction;
475
+ if (!t) return c;
476
+ if (!this.valid) return a`<p>${t.content}</p>`;
477
+ const e = t.presentation, r = t.response_payload?.kind === "text" ? t.response_payload.value : e.options.find((s) => s.id === (t.response_payload?.kind === "selection" ? t.response_payload.value : t.selected_option_id))?.label;
478
+ return a`<p class="label">${e.label}</p>${e.description ? a`<p class="description">${e.description}</p>` : c}
479
+ ${this.live ? a`<div role="group" aria-label="Options" class=${this.variant} @keydown=${this.onKey}>
480
+ ${e.options.map((s) => a`<button type="button" @click=${() => this.pick(s.id, s.allow_input, s.input_placeholder)}><span class="text"><span>${s.label}</span>${s.description ? a`<small>${s.description}</small>` : c}</span>${this.variant === "list" ? R : c}</button>`)}
481
+ </div>` : r ? a`<p class="answer">${r}</p>` : c}`;
482
+ }
483
+ pick(t, e, r) {
484
+ !this.live || !this.valid || !this.interaction || (this.interaction.schema_version === 2 && e ? this.dispatchEvent(new CustomEvent("osvi-request-input", { bubbles: !0, composed: !0, detail: { interactionId: this.interaction.interaction_id, placeholder: r } })) : this.respond({ kind: "selection", value: t }));
485
+ }
486
+ onKey(t) {
487
+ if (!["ArrowDown", "ArrowUp", "ArrowRight", "ArrowLeft"].includes(t.key)) return;
488
+ const e = [...this.renderRoot.querySelectorAll("button")], r = e.indexOf(this.renderRoot.activeElement), s = t.key === "ArrowDown" || t.key === "ArrowRight" ? 1 : -1;
489
+ e[(r + s + e.length) % e.length]?.focus(), t.preventDefault();
490
+ }
491
+ };
492
+ j.styles = D;
493
+ let M = j;
494
+ Mt([
495
+ l()
496
+ ], M.prototype, "variant");
497
+ var Ut = Object.defineProperty, q = (i, t, e, r) => {
498
+ for (var s = void 0, n = i.length - 1, o; n >= 0; n--)
499
+ (o = i[n]) && (s = o(t, e, s) || s);
500
+ return s && Ut(t, e, s), s;
501
+ };
502
+ const F = class F extends w {
503
+ constructor() {
504
+ super(...arguments), this.toolType = "ui_carousel", this.variant = "slider", this.index = 0, this.imageFailed = /* @__PURE__ */ new Set(), this.suppressPointerClick = !1;
505
+ }
506
+ willUpdate(t) {
507
+ t.has("interaction") && (this.index = 0, this.imageFailed = /* @__PURE__ */ new Set(), this.pointerStart = void 0, this.suppressPointerClick = !1);
508
+ }
509
+ render() {
510
+ const t = this.interaction;
511
+ if (!t) return c;
512
+ if (!this.valid) return a`<p>${t.content}</p>`;
513
+ const e = t.presentation, r = e.items.find((s) => s.id === (t.response_payload?.kind === "selection" ? t.response_payload.value : t.selected_option_id));
514
+ return a`<p class="label">${e.label}</p>${e.description ? a`<p class="description">${e.description}</p>` : c}
515
+ ${this.live ? this.variant === "list" ? a`<div class="list">${e.items.map((s, n) => this.card(s, n))}</div>` : a`<div @pointerdown=${(s) => {
516
+ this.pointerStart = s.clientX, this.suppressPointerClick = !1;
517
+ }} @pointerup=${(s) => {
518
+ this.pointerStart !== void 0 && Math.abs(s.clientX - this.pointerStart) > 40 && (this.suppressPointerClick = !0, this.navigate(s.clientX < this.pointerStart ? 1 : -1, e.items.length)), this.pointerStart = void 0;
519
+ }} @pointercancel=${() => {
520
+ this.pointerStart = void 0;
521
+ }}>${this.card(e.items[this.index], this.index)}</div>
522
+ <div class="navigation"><button type="button" class="round" aria-label="Previous card" ?disabled=${this.index === 0} @click=${() => this.navigate(-1, e.items.length)}>${et}</button>
523
+ <span class="dots" aria-hidden="true">${e.items.map((s, n) => a`<i class=${n === this.index ? "on" : ""}></i>`)}</span><span class="sr" aria-live="polite">${this.index + 1} of ${e.items.length}</span>
524
+ <button type="button" class="round" aria-label="Next card" ?disabled=${this.index === e.items.length - 1} @click=${() => this.navigate(1, e.items.length)}>${R}</button></div>` : r ? a`<p class="answer">${r.title}</p>` : c}`;
525
+ }
526
+ navigate(t, e) {
527
+ this.index = Math.max(0, Math.min(e - 1, this.index + t));
528
+ }
529
+ select(t, e) {
530
+ if (this.suppressPointerClick && t.detail !== 0) {
531
+ this.suppressPointerClick = !1, t.preventDefault(), t.stopPropagation();
532
+ return;
533
+ }
534
+ this.respond({ kind: "selection", value: e });
535
+ }
536
+ card(t, e) {
537
+ const r = t.image;
538
+ return a`<article class="card">${r && lt(r.url) ? a`<div class="image">${this.imageFailed.has(e) ? a`<span role="img" aria-label="Image unavailable">Image unavailable</span>` : a`<img src=${this.baseUrl.replace(/\/$/, "") + r.url} alt=${r.alt} referrerpolicy="no-referrer" loading="lazy" @error=${() => {
539
+ this.imageFailed = /* @__PURE__ */ new Set([...this.imageFailed, e]);
540
+ }}>`}</div>` : c}
541
+ <div class="body"><h3>${t.title}</h3>${t.description ? a`<p>${t.description}</p>` : c}
542
+ <button type="button" class="primary" @click=${(s) => this.select(s, t.id)}>${t.action_label ?? "Select"}</button></div></article>`;
543
+ }
544
+ };
545
+ F.styles = D;
546
+ let _ = F;
547
+ q([
548
+ l()
549
+ ], _.prototype, "variant");
550
+ q([
551
+ v()
552
+ ], _.prototype, "index");
553
+ q([
554
+ v()
555
+ ], _.prototype, "imageFailed");
556
+ var Pt = Object.defineProperty, T = (i, t, e, r) => {
557
+ for (var s = void 0, n = i.length - 1, o; n >= 0; n--)
558
+ (o = i[n]) && (s = o(t, e, s) || s);
559
+ return s && Pt(t, e, s), s;
560
+ };
561
+ const st = (i) => `${String(i.getFullYear()).padStart(4, "0")}-${String(i.getMonth() + 1).padStart(2, "0")}-${String(i.getDate()).padStart(2, "0")}`, A = () => st(/* @__PURE__ */ new Date()), Y = (i) => {
562
+ const t = /* @__PURE__ */ new Date(0);
563
+ return t.setHours(0, 0, 0, 0), t.setFullYear(Number(i.slice(0, 4)), Number(i.slice(5, 7)) - 1, Number(i.slice(8, 10))), t;
564
+ }, y = (i) => i.slice(0, 7), L = class L extends w {
565
+ constructor() {
566
+ super(...arguments), this.toolType = "ui_date_picker", this.variant = "grid", this.month = y(A()), this.start = "", this.end = "";
567
+ }
568
+ earliest(t) {
569
+ return t.min_date && t.min_date > A() ? t.min_date : A();
570
+ }
571
+ willUpdate(t) {
572
+ t.has("interaction") && (this.start = "", this.end = "", this.valid && (this.month = y(this.earliest(this.interaction.presentation))));
573
+ }
574
+ render() {
575
+ const t = this.interaction;
576
+ if (!t) return c;
577
+ if (!this.valid) return a`<p>${t.content}</p>`;
578
+ const e = t.presentation, r = t.response_payload, s = r?.kind === "date_range" ? `${r.value.start_date} – ${r.value.end_date}` : r?.kind === "date" || r?.kind === "text" ? r.value : t.selected_option_id;
579
+ if (!this.live) return a`<p class="label">${e.label}</p>${e.description ? a`<p class="description">${e.description}</p>` : c}${s ? a`<p class="answer">${s}</p>` : c}`;
580
+ const n = Y(`${this.month}-01`), o = new Date(n);
581
+ o.setMonth(o.getMonth() + 1, 0);
582
+ const h = this.earliest(e), f = Array.from({ length: o.getDate() }, (u, z) => `${this.month}-${String(z + 1).padStart(2, "0")}`), k = e.selection_mode === "range" ? this.start ? this.end ? `${this.start} – ${this.end}` : `Check-in: ${this.start}. Choose check-out.` : "Choose check-in, then check-out." : this.start, rt = A();
583
+ return a`<p class="label">${e.label}</p>${e.description ? a`<p class="description">${e.description}</p>` : c}
584
+ <div class="calendar"><div class="navigation"><button type="button" class="round" aria-label="Previous month" ?disabled=${this.month <= y(h)} @click=${() => this.moveMonth(-1, e)}>${et}</button>
585
+ <span aria-live="polite">${n.toLocaleDateString(void 0, { month: "long", year: "numeric" })}</span>
586
+ <button type="button" class="round" aria-label="Next month" ?disabled=${!!e.max_date && this.month >= y(e.max_date)} @click=${() => this.moveMonth(1, e)}>${R}</button></div>
587
+ <div class="weekdays" aria-hidden="true">${["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"].map((u) => a`<span>${u}</span>`)}</div>
588
+ <div class="days" role="group" aria-label="Choose date" @keydown=${this.onKey}>
589
+ ${Array.from({ length: n.getDay() }, () => a`<span></span>`)}
590
+ ${f.map((u, z) => a`<button type="button" class=${[u === rt ? "today" : "", u === this.start ? "start" : "", u === this.end ? "end" : "", this.start && this.end && u > this.start && u < this.end ? "in" : ""].filter(Boolean).join(" ")} aria-label=${u} aria-pressed=${u === this.start || u === this.end} ?disabled=${u < h || !!e.max_date && u > e.max_date} @click=${() => this.pick(u, e)}>${z + 1}</button>`)}
591
+ </div><p class="hint" aria-live="polite">${k}</p>
592
+ <button type="button" class="primary" ?disabled=${!this.start || e.selection_mode === "range" && (!this.end || this.start >= this.end)} @click=${() => this.confirm(e)}>${e.confirm_label ?? "Confirm date"}</button></div>`;
593
+ }
594
+ moveMonth(t, e) {
595
+ const r = Y(`${this.month}-01`);
596
+ r.setMonth(r.getMonth() + t);
597
+ const s = y(st(r));
598
+ s >= y(this.earliest(e)) && (!e.max_date || s <= y(e.max_date)) && (this.month = s);
599
+ }
600
+ pick(t, e) {
601
+ !this.live || !this.valid || !B(t) || t < this.earliest(e) || e.max_date && t > e.max_date || (e.selection_mode === "single" || !this.start || this.end || t <= this.start ? (this.start = t, this.end = "") : this.end = t);
602
+ }
603
+ confirm(t) {
604
+ !B(this.start) || this.start < this.earliest(t) || t.max_date && this.start > t.max_date || (t.selection_mode === "single" ? this.respond({ kind: "date", value: this.start }) : B(this.end) && this.start < this.end && (!t.max_date || this.end <= t.max_date) && this.respond({ kind: "date_range", value: { start_date: this.start, end_date: this.end } }));
605
+ }
606
+ onKey(t) {
607
+ const r = { ArrowLeft: -1, ArrowRight: 1, ArrowUp: -7, ArrowDown: 7 }[t.key];
608
+ if (r === void 0) return;
609
+ const s = [...this.renderRoot.querySelectorAll(".days button")], n = s.indexOf(this.renderRoot.activeElement);
610
+ if (n < 0) return;
611
+ let o = n + r;
612
+ for (; o >= 0 && o < s.length && s[o]?.disabled; ) o += r > 0 ? 1 : -1;
613
+ s[o]?.focus(), t.preventDefault();
614
+ }
615
+ };
616
+ L.styles = D;
617
+ let $ = L;
618
+ T([
619
+ l()
620
+ ], $.prototype, "variant");
621
+ T([
622
+ v()
623
+ ], $.prototype, "month");
624
+ T([
625
+ v()
626
+ ], $.prototype, "start");
627
+ T([
628
+ v()
629
+ ], $.prototype, "end");
630
+ U("osvi-chat", St);
631
+ U("osvi-buttons", M);
632
+ U("osvi-carousel", _);
633
+ U("osvi-date-picker", $);
634
+ export {
635
+ H as DEFAULT_STRINGS,
636
+ M as OsviButtons,
637
+ _ as OsviCarousel,
638
+ St as OsviChat,
639
+ $ as OsviDatePicker,
640
+ Q as applyTheme,
641
+ ut as cssVar,
642
+ U as defineOnce,
643
+ bt as explicitThemeVariables,
644
+ E as themeVariables
645
+ };
646
+ //# sourceMappingURL=ui.mjs.map