@syntrologie/adapt-chatbot 2.38.0 → 2.40.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/dist/AdaptiveChatBar.js +1 -1
- package/dist/AdaptiveChatTrail.d.ts +18 -0
- package/dist/AdaptiveChatTrail.d.ts.map +1 -1
- package/dist/AdaptiveChatTrail.js +1 -1
- package/dist/ChatSession.d.ts +23 -0
- package/dist/ChatSession.d.ts.map +1 -1
- package/dist/ChatTransport.d.ts.map +1 -1
- package/dist/LeaveAMessageLit.d.ts +130 -9
- package/dist/LeaveAMessageLit.d.ts.map +1 -1
- package/dist/LeaveAMessageLit.test.d.ts.map +1 -1
- package/dist/{chunk-P74YY3MD.js → chunk-3Z52KSYZ.js} +23 -3
- package/dist/chunk-3Z52KSYZ.js.map +7 -0
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +354 -66
- package/dist/runtime.js.map +2 -2
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +92 -0
- package/dist/schema.js.map +2 -2
- package/dist/support-chat/crisp.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-P74YY3MD.js.map +0 -7
package/dist/runtime.js
CHANGED
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
getElementInstanceStore,
|
|
18
18
|
setElementInstanceStore
|
|
19
19
|
} from "./chunk-EWPPVPJ4.js";
|
|
20
|
-
import "./chunk-
|
|
20
|
+
import "./chunk-3Z52KSYZ.js";
|
|
21
21
|
import "./chunk-VZIUXXAM.js";
|
|
22
22
|
import "./chunk-OIGVZGSX.js";
|
|
23
23
|
import {
|
|
@@ -266,6 +266,33 @@ var ChatSession = class {
|
|
|
266
266
|
msg.toolCalls = [...msg.toolCalls ?? [], { ...toolCall }];
|
|
267
267
|
this.notify();
|
|
268
268
|
}
|
|
269
|
+
/**
|
|
270
|
+
* Create an empty, already-settled assistant message at `id` if one
|
|
271
|
+
* doesn't already exist. Idempotent — safe to call on every tool-call
|
|
272
|
+
* sighting.
|
|
273
|
+
*
|
|
274
|
+
* Exists for TOOL-ONLY turns: pydantic-ai's AG-UI adapter mints a fresh
|
|
275
|
+
* `parent_message_id` per model response regardless of content
|
|
276
|
+
* (`before_response` → `self.new_message_id()`) and stamps it on every
|
|
277
|
+
* `TOOL_CALL_START`, even when the response has no text. When the
|
|
278
|
+
* model's entire action is one or more tool calls with no narration
|
|
279
|
+
* (a parallel `mount_*` + `suggest_replies` batch, most commonly), no
|
|
280
|
+
* `TEXT_MESSAGE_START` is ever emitted for that id, so nothing would
|
|
281
|
+
* otherwise create the host message `addToolCall` needs — and the tool
|
|
282
|
+
* call (and any chips/receipts derived from it) silently vanishes
|
|
283
|
+
* (BUG-1786654199). Call this before `addToolCall` on a tool call's
|
|
284
|
+
* first sighting so it always has a message to land on.
|
|
285
|
+
*
|
|
286
|
+
* Deliberately status:'complete' (not 'streaming' via `receiveStart`):
|
|
287
|
+
* a tool-only message has no text to stream, so there's nothing for a
|
|
288
|
+
* later `receiveEnd` to settle — leaving it 'streaming' would paint
|
|
289
|
+
* the trail's streaming/typing visual state forever.
|
|
290
|
+
*/
|
|
291
|
+
ensureAssistantMessage(id) {
|
|
292
|
+
if (this._messages.some((m) => m.id === id)) return;
|
|
293
|
+
this._messages.push({ id, role: "assistant", text: "", status: "complete" });
|
|
294
|
+
this.notify();
|
|
295
|
+
}
|
|
269
296
|
/**
|
|
270
297
|
* Partially update a tool call by id. Used by the transport to
|
|
271
298
|
* advance status (args-streaming → running → done) as AG-UI events
|
|
@@ -1222,6 +1249,7 @@ var ChatTransport = class {
|
|
|
1222
1249
|
if (!targetMessageId) return;
|
|
1223
1250
|
const parsedArgs = parseToolCallArgs(event.toolCall);
|
|
1224
1251
|
if (!existing) {
|
|
1252
|
+
chatSession.ensureAssistantMessage(targetMessageId);
|
|
1225
1253
|
chatSession.addToolCall(targetMessageId, {
|
|
1226
1254
|
id: event.toolCall.id,
|
|
1227
1255
|
name: event.toolCall.name,
|
|
@@ -1806,6 +1834,7 @@ var crispBridge = {
|
|
|
1806
1834
|
(msg) => {
|
|
1807
1835
|
if (!active) return;
|
|
1808
1836
|
push(["do", "chat:hide"]);
|
|
1837
|
+
if (msg?.from !== "operator") return;
|
|
1809
1838
|
if (typeof msg?.content === "string") cb(msg.content);
|
|
1810
1839
|
}
|
|
1811
1840
|
]);
|
|
@@ -2268,51 +2297,177 @@ var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
|
2268
2297
|
var box = {
|
|
2269
2298
|
display: "flex",
|
|
2270
2299
|
flexDirection: "column",
|
|
2271
|
-
gap: "
|
|
2300
|
+
gap: "10px",
|
|
2272
2301
|
fontFamily: "var(--sc-font-family, system-ui)",
|
|
2273
|
-
fontSize: "
|
|
2302
|
+
fontSize: "13px",
|
|
2303
|
+
// Defect: card content sat flush against its container's edges (no
|
|
2304
|
+
// padding anywhere). Fixed, compact — matches the rest of this file's
|
|
2305
|
+
// "form scale" sizing, not the content section's chat-bubble padding.
|
|
2306
|
+
padding: "16px",
|
|
2307
|
+
boxSizing: "border-box"
|
|
2274
2308
|
};
|
|
2275
|
-
var
|
|
2276
|
-
|
|
2309
|
+
var fieldWrapStyles = {
|
|
2310
|
+
position: "relative",
|
|
2277
2311
|
borderRadius: "var(--sc-content-border-radius, 8px)",
|
|
2278
2312
|
border: "var(--sc-content-bubble-border, 1px solid currentColor)",
|
|
2279
2313
|
background: "var(--sc-content-bubble-background, transparent)",
|
|
2314
|
+
boxSizing: "border-box",
|
|
2315
|
+
// Clips the (square-cornered, 100%-filled) inner field to this shell's
|
|
2316
|
+
// rounded corners — without it, flat textarea/input corners can poke
|
|
2317
|
+
// past the shell's curve at the very edges.
|
|
2318
|
+
overflow: "hidden"
|
|
2319
|
+
};
|
|
2320
|
+
var messageWrapStyles = {
|
|
2321
|
+
...fieldWrapStyles,
|
|
2322
|
+
height: "84px"
|
|
2323
|
+
};
|
|
2324
|
+
var singleLineWrapStyles = {
|
|
2325
|
+
...fieldWrapStyles,
|
|
2326
|
+
height: "44px"
|
|
2327
|
+
};
|
|
2328
|
+
var fieldInnerBase = {
|
|
2329
|
+
border: "none",
|
|
2330
|
+
outline: "none",
|
|
2331
|
+
background: "transparent",
|
|
2280
2332
|
color: "inherit",
|
|
2281
|
-
font: "inherit"
|
|
2333
|
+
font: "inherit",
|
|
2334
|
+
width: "100%",
|
|
2335
|
+
height: "100%",
|
|
2336
|
+
boxSizing: "border-box",
|
|
2337
|
+
resize: "none"
|
|
2338
|
+
};
|
|
2339
|
+
var messageInnerStyles = {
|
|
2340
|
+
...fieldInnerBase,
|
|
2341
|
+
padding: "8px 42px 8px 10px",
|
|
2342
|
+
overflowY: "auto"
|
|
2343
|
+
};
|
|
2344
|
+
var singleLineInnerStyles = {
|
|
2345
|
+
...fieldInnerBase,
|
|
2346
|
+
padding: "0 42px 0 10px"
|
|
2347
|
+
};
|
|
2348
|
+
var srOnlyStyles = {
|
|
2349
|
+
position: "absolute",
|
|
2350
|
+
width: "1px",
|
|
2351
|
+
height: "1px",
|
|
2352
|
+
padding: "0",
|
|
2353
|
+
margin: "-1px",
|
|
2354
|
+
overflow: "hidden",
|
|
2355
|
+
whiteSpace: "nowrap",
|
|
2356
|
+
border: "0"
|
|
2357
|
+
};
|
|
2358
|
+
var sendIcon = html`<svg width="14" height="14" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M8 14V2M8 2L3 7M8 2L13 7" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>`;
|
|
2359
|
+
var embeddedIconButtonStyles = {
|
|
2360
|
+
position: "absolute",
|
|
2361
|
+
right: "5px",
|
|
2362
|
+
bottom: "5px",
|
|
2363
|
+
display: "flex",
|
|
2364
|
+
alignItems: "center",
|
|
2365
|
+
justifyContent: "center",
|
|
2366
|
+
width: "30px",
|
|
2367
|
+
height: "30px",
|
|
2368
|
+
padding: "0",
|
|
2369
|
+
borderRadius: "50%",
|
|
2370
|
+
border: "none",
|
|
2371
|
+
background: "var(--sc-color-primary, #000000)",
|
|
2372
|
+
color: "var(--sc-launcher-color, #ffffff)",
|
|
2373
|
+
cursor: "pointer"
|
|
2374
|
+
};
|
|
2375
|
+
var embeddedIconButtonCenteredStyles = {
|
|
2376
|
+
...embeddedIconButtonStyles,
|
|
2377
|
+
bottom: "auto",
|
|
2378
|
+
top: "50%",
|
|
2379
|
+
transform: "translateY(-50%)"
|
|
2380
|
+
};
|
|
2381
|
+
var embeddedIconButtonDisabledStyles = {
|
|
2382
|
+
...embeddedIconButtonStyles,
|
|
2383
|
+
background: "rgba(120, 120, 120, 0.25)",
|
|
2384
|
+
color: "rgba(90, 90, 90, 0.9)",
|
|
2385
|
+
cursor: "default"
|
|
2386
|
+
};
|
|
2387
|
+
var embeddedIconButtonCenteredDisabledStyles = {
|
|
2388
|
+
...embeddedIconButtonCenteredStyles,
|
|
2389
|
+
background: "rgba(120, 120, 120, 0.25)",
|
|
2390
|
+
color: "rgba(90, 90, 90, 0.9)",
|
|
2391
|
+
cursor: "default"
|
|
2282
2392
|
};
|
|
2283
2393
|
var buttonStyles = {
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
background: "var(--sc-chip-background, transparent)",
|
|
2290
|
-
color: "var(--sc-tile-title-color, inherit)",
|
|
2394
|
+
padding: "11px 14px",
|
|
2395
|
+
borderRadius: "var(--sc-border-radius, 8px)",
|
|
2396
|
+
border: "none",
|
|
2397
|
+
background: "var(--sc-color-primary, #000000)",
|
|
2398
|
+
color: "var(--sc-launcher-color, #ffffff)",
|
|
2291
2399
|
fontWeight: "600",
|
|
2292
2400
|
cursor: "pointer",
|
|
2293
|
-
font: "inherit"
|
|
2401
|
+
font: "inherit",
|
|
2402
|
+
width: "100%",
|
|
2403
|
+
boxSizing: "border-box"
|
|
2294
2404
|
};
|
|
2295
|
-
var
|
|
2296
|
-
|
|
2405
|
+
var fieldRowStyles = {
|
|
2406
|
+
display: "flex",
|
|
2407
|
+
alignItems: "center",
|
|
2408
|
+
gap: "8px"
|
|
2409
|
+
};
|
|
2410
|
+
var skipButtonStyles = {
|
|
2411
|
+
flexShrink: "0",
|
|
2412
|
+
padding: "0",
|
|
2413
|
+
border: "none",
|
|
2414
|
+
background: "transparent",
|
|
2415
|
+
color: "inherit",
|
|
2416
|
+
textDecoration: "underline",
|
|
2417
|
+
cursor: "pointer",
|
|
2418
|
+
font: "inherit",
|
|
2419
|
+
fontSize: "12px",
|
|
2420
|
+
opacity: "0.8",
|
|
2421
|
+
whiteSpace: "nowrap"
|
|
2297
2422
|
};
|
|
2298
2423
|
var mutedTextStyles = {
|
|
2299
2424
|
margin: "0",
|
|
2300
2425
|
// No opacity token exists in any publishable section — plain constant.
|
|
2301
2426
|
opacity: "0.8"
|
|
2302
2427
|
};
|
|
2428
|
+
var trailHostStyles = {
|
|
2429
|
+
display: "flex",
|
|
2430
|
+
flexDirection: "column",
|
|
2431
|
+
height: "160px",
|
|
2432
|
+
overflow: "hidden",
|
|
2433
|
+
width: "100%",
|
|
2434
|
+
boxSizing: "border-box"
|
|
2435
|
+
};
|
|
2303
2436
|
var PERSIST_NAMESPACE = "supportchat";
|
|
2304
2437
|
var PERSIST_KEY = "leave-a-message";
|
|
2438
|
+
var lamUidCounter = 0;
|
|
2305
2439
|
var LeaveAMessageLit = class extends LitElement {
|
|
2306
2440
|
constructor() {
|
|
2307
2441
|
super(...arguments);
|
|
2308
2442
|
this.message = "";
|
|
2309
2443
|
this.contextSummary = "";
|
|
2310
2444
|
this.state = "form";
|
|
2445
|
+
/** Unique per-instance id prefix so `<label for>` never collides across
|
|
2446
|
+
* more than one card mounted on the same page. */
|
|
2447
|
+
this._uid = `lam-${++lamUidCounter}`;
|
|
2311
2448
|
this._email = "";
|
|
2312
2449
|
this._reply = "";
|
|
2313
|
-
|
|
2450
|
+
/** Visitor↔operator conversation, in order — rendered as a chat
|
|
2451
|
+
* transcript once the visitor taps into the mail state (see render()'s
|
|
2452
|
+
* 'flipped' branch). Seeded with the visitor's own compose-step message
|
|
2453
|
+
* in `_submitMessage`. */
|
|
2454
|
+
this._transcript = [];
|
|
2455
|
+
/** Paint our own focus ring from the theme. The border now lives on the
|
|
2456
|
+
* field SHELL (`data-lam-field-wrap`), not the borderless inner
|
|
2457
|
+
* textarea/input, so the ring targets that ancestor via `closest()`. */
|
|
2458
|
+
this._focusOn = (e) => {
|
|
2459
|
+
const field = e.target;
|
|
2460
|
+
const target = field.closest("[data-lam-field-wrap]") ?? field;
|
|
2461
|
+
target.style.outline = "2px solid var(--sc-color-primary, currentColor)";
|
|
2462
|
+
target.style.outlineOffset = "1px";
|
|
2463
|
+
};
|
|
2464
|
+
this._focusOff = (e) => {
|
|
2465
|
+
const field = e.target;
|
|
2466
|
+
const target = field.closest("[data-lam-field-wrap]") ?? field;
|
|
2467
|
+
target.style.outline = "none";
|
|
2468
|
+
};
|
|
2314
2469
|
this._onReply = (text) => {
|
|
2315
|
-
this.
|
|
2470
|
+
this._transcript = [...this._transcript, { role: "operator", text }];
|
|
2316
2471
|
if (this.state !== "flipped") {
|
|
2317
2472
|
this.state = "mail";
|
|
2318
2473
|
this.runtime?.events.publish("supportchat:reply_received", { text });
|
|
@@ -2328,12 +2483,37 @@ var LeaveAMessageLit = class extends LitElement {
|
|
|
2328
2483
|
this._persist();
|
|
2329
2484
|
this.requestUpdate();
|
|
2330
2485
|
};
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2486
|
+
/** Compose step → email step. Delivers the message immediately; email
|
|
2487
|
+
* capture is a SEPARATE, later, optional step (owner redesign). Seeds
|
|
2488
|
+
* the chat transcript with the visitor's OWN plain message text (not
|
|
2489
|
+
* the context-prefixed string sent to the bridge — that prefix is
|
|
2490
|
+
* internal plumbing for the human agent, not something the visitor
|
|
2491
|
+
* should see echoed back at themselves). */
|
|
2492
|
+
this._submitMessage = () => {
|
|
2493
|
+
if (!this.bridge || !this.message.trim()) return;
|
|
2334
2494
|
const context = this.contextSummary ? `[Site assistant context: ${this.contextSummary}]
|
|
2335
2495
|
` : "";
|
|
2336
2496
|
this.bridge.sendMessage(`${context}${this.message}`);
|
|
2497
|
+
this._transcript = [...this._transcript, { role: "visitor", text: this.message.trim() }];
|
|
2498
|
+
this.state = "email";
|
|
2499
|
+
this._persist();
|
|
2500
|
+
};
|
|
2501
|
+
/** Email step → sent. Blank email is a valid submission (the field is
|
|
2502
|
+
* optional) and simply skips `setVisitorEmail`; an invalid non-blank
|
|
2503
|
+
* email blocks advancing so a mistyped address doesn't silently vanish. */
|
|
2504
|
+
this._submitEmail = () => {
|
|
2505
|
+
if (!this.bridge) return;
|
|
2506
|
+
const trimmed = this._email.trim();
|
|
2507
|
+
if (trimmed && !EMAIL_RE.test(trimmed)) return;
|
|
2508
|
+
if (trimmed) this.bridge.setVisitorEmail(trimmed);
|
|
2509
|
+
this.state = "sent";
|
|
2510
|
+
this._persist();
|
|
2511
|
+
};
|
|
2512
|
+
/** Explicit decline — advances regardless of whatever is typed, without
|
|
2513
|
+
* ever calling `setVisitorEmail`. Distinct from submitting a blank
|
|
2514
|
+
* field only in that it discards partial input the visitor may not
|
|
2515
|
+
* have meant to send. */
|
|
2516
|
+
this._skipEmail = () => {
|
|
2337
2517
|
this.state = "sent";
|
|
2338
2518
|
this._persist();
|
|
2339
2519
|
};
|
|
@@ -2343,8 +2523,11 @@ var LeaveAMessageLit = class extends LitElement {
|
|
|
2343
2523
|
};
|
|
2344
2524
|
this._sendReply = () => {
|
|
2345
2525
|
if (!this.bridge || !this._reply.trim()) return;
|
|
2346
|
-
this.
|
|
2526
|
+
const text = this._reply.trim();
|
|
2527
|
+
this.bridge.sendMessage(text);
|
|
2528
|
+
this._transcript = [...this._transcript, { role: "visitor", text }];
|
|
2347
2529
|
this._reply = "";
|
|
2530
|
+
this._persist();
|
|
2348
2531
|
this.requestUpdate();
|
|
2349
2532
|
};
|
|
2350
2533
|
}
|
|
@@ -2369,25 +2552,25 @@ var LeaveAMessageLit = class extends LitElement {
|
|
|
2369
2552
|
_persistStore() {
|
|
2370
2553
|
return this.runtime?.state?.user?.ns?.(PERSIST_NAMESPACE);
|
|
2371
2554
|
}
|
|
2372
|
-
/** Hydrate {state,
|
|
2555
|
+
/** Hydrate {state, transcript, email} from a prior page's mount. */
|
|
2373
2556
|
_loadPersisted() {
|
|
2374
2557
|
const store = this._persistStore();
|
|
2375
2558
|
if (!store) return;
|
|
2376
2559
|
const saved = store.get(PERSIST_KEY);
|
|
2377
2560
|
if (!saved) return;
|
|
2378
2561
|
if (saved.state) this.state = saved.state;
|
|
2379
|
-
if (Array.isArray(saved.
|
|
2562
|
+
if (Array.isArray(saved.transcript)) this._transcript = saved.transcript;
|
|
2380
2563
|
if (typeof saved.email === "string") this._email = saved.email;
|
|
2381
2564
|
}
|
|
2382
|
-
/** Snapshot {state,
|
|
2383
|
-
*
|
|
2565
|
+
/** Snapshot {state, transcript, email} so the NEXT mount (a fresh page
|
|
2566
|
+
* in the same session) can pick the thread back up. */
|
|
2384
2567
|
_persist() {
|
|
2385
2568
|
const store = this._persistStore();
|
|
2386
2569
|
if (!store) return;
|
|
2387
2570
|
const state = this.state;
|
|
2388
|
-
const
|
|
2571
|
+
const transcript = this._transcript;
|
|
2389
2572
|
const email = this._email;
|
|
2390
|
-
const snapshot = { state,
|
|
2573
|
+
const snapshot = { state, transcript, email };
|
|
2391
2574
|
store.set(PERSIST_KEY, snapshot);
|
|
2392
2575
|
}
|
|
2393
2576
|
/**
|
|
@@ -2419,65 +2602,164 @@ var LeaveAMessageLit = class extends LitElement {
|
|
|
2419
2602
|
console.warn("supportChat.widget: reply toast failed", err);
|
|
2420
2603
|
}
|
|
2421
2604
|
}
|
|
2605
|
+
/** Maps this card's OWN `_transcript` (never the concierge's) to the
|
|
2606
|
+
* shape `<adaptive-chat-trail>` renders. `visitor` → `'user'` (right-
|
|
2607
|
+
* aligned, branded) and `operator` → `'assistant'` (left-aligned,
|
|
2608
|
+
* neutral) purely for the trail's existing visual treatment — no
|
|
2609
|
+
* claim that a human Crisp operator IS the AI assistant. Freshly
|
|
2610
|
+
* computed on every render from local state; nothing here reads from
|
|
2611
|
+
* or writes to `chatSession`. */
|
|
2612
|
+
_trailMessages() {
|
|
2613
|
+
return this._transcript.map((entry, i) => ({
|
|
2614
|
+
id: `lam-${this._uid}-${i}`,
|
|
2615
|
+
role: entry.role === "visitor" ? "user" : "assistant",
|
|
2616
|
+
text: entry.text,
|
|
2617
|
+
status: "complete"
|
|
2618
|
+
}));
|
|
2619
|
+
}
|
|
2422
2620
|
render() {
|
|
2423
2621
|
if (!this.bridge || !this.bridge.detect()) return nothing;
|
|
2622
|
+
const copy = this.copy;
|
|
2424
2623
|
if (this.state === "form") {
|
|
2624
|
+
const messageId = `${this._uid}-message`;
|
|
2625
|
+
const canSend = this.message.trim().length > 0;
|
|
2425
2626
|
return html`<div data-lam style=${styleMap(box)}>
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2627
|
+
${copy?.framing ? html`<p data-lam-framing style=${styleMap(mutedTextStyles)}>${copy.framing}</p>` : nothing}
|
|
2628
|
+
${copy?.messageLabel ? html`<label data-lam-message-label for=${messageId} style=${styleMap(srOnlyStyles)}
|
|
2629
|
+
>${copy.messageLabel}</label
|
|
2630
|
+
>` : nothing}
|
|
2631
|
+
<div data-lam-message-wrap data-lam-field-wrap style=${styleMap(messageWrapStyles)}>
|
|
2632
|
+
<textarea
|
|
2633
|
+
data-lam-message
|
|
2634
|
+
id=${messageId}
|
|
2635
|
+
style=${styleMap(messageInnerStyles)}
|
|
2636
|
+
@focus=${this._focusOn}
|
|
2637
|
+
@blur=${this._focusOff}
|
|
2638
|
+
.value=${this.message}
|
|
2639
|
+
@input=${(e) => {
|
|
2432
2640
|
this.message = e.target.value;
|
|
2433
2641
|
}}
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2642
|
+
></textarea>
|
|
2643
|
+
${copy?.sendLabel ? html`<button
|
|
2644
|
+
type="button"
|
|
2645
|
+
data-lam-send
|
|
2646
|
+
aria-label=${copy.sendLabel}
|
|
2647
|
+
?disabled=${!canSend}
|
|
2648
|
+
style=${styleMap(
|
|
2649
|
+
canSend ? embeddedIconButtonStyles : embeddedIconButtonDisabledStyles
|
|
2650
|
+
)}
|
|
2651
|
+
@click=${this._submitMessage}
|
|
2652
|
+
>
|
|
2653
|
+
${sendIcon}
|
|
2654
|
+
</button>` : nothing}
|
|
2655
|
+
</div>
|
|
2656
|
+
</div>`;
|
|
2657
|
+
}
|
|
2658
|
+
if (this.state === "email") {
|
|
2659
|
+
const emailId = `${this._uid}-email`;
|
|
2660
|
+
return html`<div data-lam style=${styleMap(box)}>
|
|
2661
|
+
${copy?.emailPrompt ? html`<p data-lam-email-prompt style=${styleMap(mutedTextStyles)}>${copy.emailPrompt}</p>` : nothing}
|
|
2662
|
+
${copy?.emailLabel ? html`<label data-lam-email-label for=${emailId} style=${styleMap(srOnlyStyles)}
|
|
2663
|
+
>${copy.emailLabel}</label
|
|
2664
|
+
>` : nothing}
|
|
2665
|
+
<div data-lam-email-row style=${styleMap(fieldRowStyles)}>
|
|
2666
|
+
<div
|
|
2667
|
+
data-lam-email-wrap
|
|
2668
|
+
data-lam-field-wrap
|
|
2669
|
+
style=${styleMap({ ...singleLineWrapStyles, flex: "1" })}
|
|
2670
|
+
>
|
|
2671
|
+
<input
|
|
2672
|
+
data-lam-email
|
|
2673
|
+
id=${emailId}
|
|
2674
|
+
type="email"
|
|
2675
|
+
placeholder=${copy?.emailPlaceholder ?? nothing}
|
|
2676
|
+
style=${styleMap(singleLineInnerStyles)}
|
|
2677
|
+
@focus=${this._focusOn}
|
|
2678
|
+
@blur=${this._focusOff}
|
|
2679
|
+
@input=${(e) => {
|
|
2441
2680
|
this._email = e.target.value;
|
|
2442
2681
|
this.requestUpdate();
|
|
2443
2682
|
}}
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2683
|
+
/>
|
|
2684
|
+
${copy?.emailSubmitLabel ? html`<button
|
|
2685
|
+
type="button"
|
|
2686
|
+
data-lam-email-submit
|
|
2687
|
+
aria-label=${copy.emailSubmitLabel}
|
|
2688
|
+
style=${styleMap(embeddedIconButtonCenteredStyles)}
|
|
2689
|
+
@click=${this._submitEmail}
|
|
2690
|
+
>
|
|
2691
|
+
${sendIcon}
|
|
2692
|
+
</button>` : nothing}
|
|
2693
|
+
</div>
|
|
2694
|
+
${copy?.emailSkipLabel ? html`<button
|
|
2695
|
+
type="button"
|
|
2696
|
+
data-lam-email-skip
|
|
2697
|
+
style=${styleMap(skipButtonStyles)}
|
|
2698
|
+
@click=${this._skipEmail}
|
|
2699
|
+
>
|
|
2700
|
+
${copy.emailSkipLabel}
|
|
2701
|
+
</button>` : nothing}
|
|
2702
|
+
</div>
|
|
2448
2703
|
</div>`;
|
|
2449
2704
|
}
|
|
2450
2705
|
if (this.state === "sent") {
|
|
2451
2706
|
return html`<div data-lam style=${styleMap(box)}>
|
|
2452
|
-
|
|
2453
|
-
Sent. The team will reply here — or by email if you step away.
|
|
2454
|
-
</p>
|
|
2707
|
+
${copy?.sentBody ? html`<p style=${styleMap(mutedTextStyles)}>${copy.sentBody}</p>` : nothing}
|
|
2455
2708
|
</div>`;
|
|
2456
2709
|
}
|
|
2457
2710
|
if (this.state === "mail") {
|
|
2458
2711
|
return html`<div data-lam style=${styleMap(box)}>
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2712
|
+
${copy?.mailLabel ? html`<button
|
|
2713
|
+
type="button"
|
|
2714
|
+
data-lam-mail
|
|
2715
|
+
style=${styleMap(buttonStyles)}
|
|
2716
|
+
@click=${this._flip}
|
|
2717
|
+
>
|
|
2718
|
+
${copy.mailLabel}
|
|
2719
|
+
</button>` : nothing}
|
|
2462
2720
|
</div>`;
|
|
2463
2721
|
}
|
|
2722
|
+
const replyId = `${this._uid}-reply`;
|
|
2723
|
+
const canReply = this._reply.trim().length > 0;
|
|
2464
2724
|
return html`<div data-lam style=${styleMap(box)}>
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2725
|
+
<adaptive-chat-trail
|
|
2726
|
+
data-lam-trail
|
|
2727
|
+
.messages=${this._trailMessages()}
|
|
2728
|
+
.forceExpanded=${true}
|
|
2729
|
+
.hideTopBorder=${true}
|
|
2730
|
+
style=${styleMap(trailHostStyles)}
|
|
2731
|
+
></adaptive-chat-trail>
|
|
2732
|
+
${copy?.replyLabel ? html`<label data-lam-reply-label for=${replyId} style=${styleMap(srOnlyStyles)}
|
|
2733
|
+
>${copy.replyLabel}</label
|
|
2734
|
+
>` : nothing}
|
|
2735
|
+
<div data-lam-reply-wrap data-lam-field-wrap style=${styleMap(singleLineWrapStyles)}>
|
|
2736
|
+
<input
|
|
2737
|
+
data-lam-reply
|
|
2738
|
+
id=${replyId}
|
|
2739
|
+
type="text"
|
|
2740
|
+
placeholder=${copy?.replyPlaceholder ?? nothing}
|
|
2741
|
+
style=${styleMap(singleLineInnerStyles)}
|
|
2742
|
+
@focus=${this._focusOn}
|
|
2743
|
+
@blur=${this._focusOff}
|
|
2744
|
+
.value=${this._reply}
|
|
2745
|
+
@input=${(e) => {
|
|
2475
2746
|
this._reply = e.target.value;
|
|
2747
|
+
this.requestUpdate();
|
|
2476
2748
|
}}
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2749
|
+
/>
|
|
2750
|
+
${copy?.replySendLabel ? html`<button
|
|
2751
|
+
type="button"
|
|
2752
|
+
data-lam-reply-send
|
|
2753
|
+
aria-label=${copy.replySendLabel}
|
|
2754
|
+
?disabled=${!canReply}
|
|
2755
|
+
style=${styleMap(
|
|
2756
|
+
canReply ? embeddedIconButtonCenteredStyles : embeddedIconButtonCenteredDisabledStyles
|
|
2757
|
+
)}
|
|
2758
|
+
@click=${this._sendReply}
|
|
2759
|
+
>
|
|
2760
|
+
${sendIcon}
|
|
2761
|
+
</button>` : nothing}
|
|
2762
|
+
</div>
|
|
2481
2763
|
</div>`;
|
|
2482
2764
|
}
|
|
2483
2765
|
};
|
|
@@ -2487,7 +2769,8 @@ LeaveAMessageLit.properties = {
|
|
|
2487
2769
|
contextSummary: { attribute: false },
|
|
2488
2770
|
state: { type: String },
|
|
2489
2771
|
runtime: { attribute: false },
|
|
2490
|
-
replyToast: { attribute: false }
|
|
2772
|
+
replyToast: { attribute: false },
|
|
2773
|
+
copy: { attribute: false }
|
|
2491
2774
|
};
|
|
2492
2775
|
function registerLeaveAMessageLit() {
|
|
2493
2776
|
if (typeof customElements !== "undefined" && !customElements.get("syntro-leave-a-message")) {
|
|
@@ -2639,6 +2922,11 @@ var LeaveAMessageMountable = {
|
|
|
2639
2922
|
// Visitor-facing toast copy from the workspace config — see
|
|
2640
2923
|
// LeaveAMessageLit#replyToast (presentation is configuration).
|
|
2641
2924
|
replyToast: stripped.replyToast,
|
|
2925
|
+
// Every OTHER visitor-facing string on the card — see
|
|
2926
|
+
// LeaveAMessageLit#copy / LeaveAMessageCopy. Same "config carries the
|
|
2927
|
+
// words" pattern as replyToast, just covering the whole card instead
|
|
2928
|
+
// of one notification.
|
|
2929
|
+
copy: stripped.copy,
|
|
2642
2930
|
runtime: runtime2
|
|
2643
2931
|
});
|
|
2644
2932
|
container.appendChild(el);
|