@syntrologie/adapt-chatbot 2.39.0 → 2.41.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/LeaveAMessageLit.d.ts +128 -10
- 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 +312 -78
- package/dist/runtime.js.map +2 -2
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +4 -0
- package/dist/schema.js.map +2 -2
- 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 {
|
|
@@ -2297,70 +2297,177 @@ var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
|
2297
2297
|
var box = {
|
|
2298
2298
|
display: "flex",
|
|
2299
2299
|
flexDirection: "column",
|
|
2300
|
-
gap: "
|
|
2300
|
+
gap: "10px",
|
|
2301
2301
|
fontFamily: "var(--sc-font-family, system-ui)",
|
|
2302
|
-
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"
|
|
2303
2308
|
};
|
|
2304
|
-
var
|
|
2305
|
-
|
|
2309
|
+
var fieldWrapStyles = {
|
|
2310
|
+
position: "relative",
|
|
2306
2311
|
borderRadius: "var(--sc-content-border-radius, 8px)",
|
|
2307
2312
|
border: "var(--sc-content-bubble-border, 1px solid currentColor)",
|
|
2308
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",
|
|
2309
2332
|
color: "inherit",
|
|
2310
2333
|
font: "inherit",
|
|
2311
|
-
// The browser's default focus ring is a loud blue on a black-and-white
|
|
2312
|
-
// brand — the one saturated pixel on the card. Suppress it and paint our
|
|
2313
|
-
// own from the theme in the focus/blur handlers below.
|
|
2314
|
-
outline: "none",
|
|
2315
2334
|
width: "100%",
|
|
2335
|
+
height: "100%",
|
|
2316
2336
|
boxSizing: "border-box",
|
|
2317
|
-
// The drag grabber pokes out of the card's bottom-right corner and lets
|
|
2318
|
-
// the visitor break the tile frame — the card owns its own geometry.
|
|
2319
2337
|
resize: "none"
|
|
2320
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"
|
|
2392
|
+
};
|
|
2321
2393
|
var buttonStyles = {
|
|
2322
2394
|
padding: "11px 14px",
|
|
2323
2395
|
borderRadius: "var(--sc-border-radius, 8px)",
|
|
2324
2396
|
border: "none",
|
|
2325
2397
|
background: "var(--sc-color-primary, #000000)",
|
|
2326
|
-
color: "var(--sc-
|
|
2398
|
+
color: "var(--sc-launcher-color, #ffffff)",
|
|
2327
2399
|
fontWeight: "600",
|
|
2328
2400
|
cursor: "pointer",
|
|
2329
2401
|
font: "inherit",
|
|
2330
2402
|
width: "100%",
|
|
2331
2403
|
boxSizing: "border-box"
|
|
2332
2404
|
};
|
|
2333
|
-
var
|
|
2334
|
-
|
|
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"
|
|
2335
2422
|
};
|
|
2336
2423
|
var mutedTextStyles = {
|
|
2337
2424
|
margin: "0",
|
|
2338
2425
|
// No opacity token exists in any publishable section — plain constant.
|
|
2339
2426
|
opacity: "0.8"
|
|
2340
2427
|
};
|
|
2428
|
+
var trailHostStyles = {
|
|
2429
|
+
display: "flex",
|
|
2430
|
+
flexDirection: "column",
|
|
2431
|
+
height: "160px",
|
|
2432
|
+
overflow: "hidden",
|
|
2433
|
+
width: "100%",
|
|
2434
|
+
boxSizing: "border-box"
|
|
2435
|
+
};
|
|
2341
2436
|
var PERSIST_NAMESPACE = "supportchat";
|
|
2342
2437
|
var PERSIST_KEY = "leave-a-message";
|
|
2438
|
+
var lamUidCounter = 0;
|
|
2343
2439
|
var LeaveAMessageLit = class extends LitElement {
|
|
2344
2440
|
constructor() {
|
|
2345
2441
|
super(...arguments);
|
|
2346
2442
|
this.message = "";
|
|
2347
2443
|
this.contextSummary = "";
|
|
2348
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}`;
|
|
2349
2448
|
this._email = "";
|
|
2350
2449
|
this._reply = "";
|
|
2351
|
-
|
|
2352
|
-
|
|
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()`. */
|
|
2353
2458
|
this._focusOn = (e) => {
|
|
2354
|
-
const
|
|
2355
|
-
|
|
2356
|
-
|
|
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";
|
|
2357
2463
|
};
|
|
2358
2464
|
this._focusOff = (e) => {
|
|
2359
|
-
const
|
|
2360
|
-
|
|
2465
|
+
const field = e.target;
|
|
2466
|
+
const target = field.closest("[data-lam-field-wrap]") ?? field;
|
|
2467
|
+
target.style.outline = "none";
|
|
2361
2468
|
};
|
|
2362
2469
|
this._onReply = (text) => {
|
|
2363
|
-
this.
|
|
2470
|
+
this._transcript = [...this._transcript, { role: "operator", text }];
|
|
2364
2471
|
if (this.state !== "flipped") {
|
|
2365
2472
|
this.state = "mail";
|
|
2366
2473
|
this.runtime?.events.publish("supportchat:reply_received", { text });
|
|
@@ -2376,12 +2483,37 @@ var LeaveAMessageLit = class extends LitElement {
|
|
|
2376
2483
|
this._persist();
|
|
2377
2484
|
this.requestUpdate();
|
|
2378
2485
|
};
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
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;
|
|
2382
2494
|
const context = this.contextSummary ? `[Site assistant context: ${this.contextSummary}]
|
|
2383
2495
|
` : "";
|
|
2384
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 = () => {
|
|
2385
2517
|
this.state = "sent";
|
|
2386
2518
|
this._persist();
|
|
2387
2519
|
};
|
|
@@ -2391,8 +2523,11 @@ var LeaveAMessageLit = class extends LitElement {
|
|
|
2391
2523
|
};
|
|
2392
2524
|
this._sendReply = () => {
|
|
2393
2525
|
if (!this.bridge || !this._reply.trim()) return;
|
|
2394
|
-
this.
|
|
2526
|
+
const text = this._reply.trim();
|
|
2527
|
+
this.bridge.sendMessage(text);
|
|
2528
|
+
this._transcript = [...this._transcript, { role: "visitor", text }];
|
|
2395
2529
|
this._reply = "";
|
|
2530
|
+
this._persist();
|
|
2396
2531
|
this.requestUpdate();
|
|
2397
2532
|
};
|
|
2398
2533
|
}
|
|
@@ -2417,25 +2552,25 @@ var LeaveAMessageLit = class extends LitElement {
|
|
|
2417
2552
|
_persistStore() {
|
|
2418
2553
|
return this.runtime?.state?.user?.ns?.(PERSIST_NAMESPACE);
|
|
2419
2554
|
}
|
|
2420
|
-
/** Hydrate {state,
|
|
2555
|
+
/** Hydrate {state, transcript, email} from a prior page's mount. */
|
|
2421
2556
|
_loadPersisted() {
|
|
2422
2557
|
const store = this._persistStore();
|
|
2423
2558
|
if (!store) return;
|
|
2424
2559
|
const saved = store.get(PERSIST_KEY);
|
|
2425
2560
|
if (!saved) return;
|
|
2426
2561
|
if (saved.state) this.state = saved.state;
|
|
2427
|
-
if (Array.isArray(saved.
|
|
2562
|
+
if (Array.isArray(saved.transcript)) this._transcript = saved.transcript;
|
|
2428
2563
|
if (typeof saved.email === "string") this._email = saved.email;
|
|
2429
2564
|
}
|
|
2430
|
-
/** Snapshot {state,
|
|
2431
|
-
*
|
|
2565
|
+
/** Snapshot {state, transcript, email} so the NEXT mount (a fresh page
|
|
2566
|
+
* in the same session) can pick the thread back up. */
|
|
2432
2567
|
_persist() {
|
|
2433
2568
|
const store = this._persistStore();
|
|
2434
2569
|
if (!store) return;
|
|
2435
2570
|
const state = this.state;
|
|
2436
|
-
const
|
|
2571
|
+
const transcript = this._transcript;
|
|
2437
2572
|
const email = this._email;
|
|
2438
|
-
const snapshot = { state,
|
|
2573
|
+
const snapshot = { state, transcript, email };
|
|
2439
2574
|
store.set(PERSIST_KEY, snapshot);
|
|
2440
2575
|
}
|
|
2441
2576
|
/**
|
|
@@ -2467,71 +2602,164 @@ var LeaveAMessageLit = class extends LitElement {
|
|
|
2467
2602
|
console.warn("supportChat.widget: reply toast failed", err);
|
|
2468
2603
|
}
|
|
2469
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
|
+
}
|
|
2470
2620
|
render() {
|
|
2471
2621
|
if (!this.bridge || !this.bridge.detect()) return nothing;
|
|
2622
|
+
const copy = this.copy;
|
|
2472
2623
|
if (this.state === "form") {
|
|
2624
|
+
const messageId = `${this._uid}-message`;
|
|
2625
|
+
const canSend = this.message.trim().length > 0;
|
|
2473
2626
|
return html`<div data-lam style=${styleMap(box)}>
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
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) => {
|
|
2640
|
+
this.message = e.target.value;
|
|
2641
|
+
}}
|
|
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) => {
|
|
2482
2680
|
this._email = e.target.value;
|
|
2483
2681
|
this.requestUpdate();
|
|
2484
2682
|
}}
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
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>
|
|
2500
2703
|
</div>`;
|
|
2501
2704
|
}
|
|
2502
2705
|
if (this.state === "sent") {
|
|
2503
2706
|
return html`<div data-lam style=${styleMap(box)}>
|
|
2504
|
-
|
|
2505
|
-
Sent. The team will reply here — or by email if you step away.
|
|
2506
|
-
</p>
|
|
2707
|
+
${copy?.sentBody ? html`<p style=${styleMap(mutedTextStyles)}>${copy.sentBody}</p>` : nothing}
|
|
2507
2708
|
</div>`;
|
|
2508
2709
|
}
|
|
2509
2710
|
if (this.state === "mail") {
|
|
2510
2711
|
return html`<div data-lam style=${styleMap(box)}>
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
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}
|
|
2514
2720
|
</div>`;
|
|
2515
2721
|
}
|
|
2722
|
+
const replyId = `${this._uid}-reply`;
|
|
2723
|
+
const canReply = this._reply.trim().length > 0;
|
|
2516
2724
|
return html`<div data-lam style=${styleMap(box)}>
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
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) => {
|
|
2529
2746
|
this._reply = e.target.value;
|
|
2747
|
+
this.requestUpdate();
|
|
2530
2748
|
}}
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
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>
|
|
2535
2763
|
</div>`;
|
|
2536
2764
|
}
|
|
2537
2765
|
};
|
|
@@ -2541,7 +2769,8 @@ LeaveAMessageLit.properties = {
|
|
|
2541
2769
|
contextSummary: { attribute: false },
|
|
2542
2770
|
state: { type: String },
|
|
2543
2771
|
runtime: { attribute: false },
|
|
2544
|
-
replyToast: { attribute: false }
|
|
2772
|
+
replyToast: { attribute: false },
|
|
2773
|
+
copy: { attribute: false }
|
|
2545
2774
|
};
|
|
2546
2775
|
function registerLeaveAMessageLit() {
|
|
2547
2776
|
if (typeof customElements !== "undefined" && !customElements.get("syntro-leave-a-message")) {
|
|
@@ -2693,6 +2922,11 @@ var LeaveAMessageMountable = {
|
|
|
2693
2922
|
// Visitor-facing toast copy from the workspace config — see
|
|
2694
2923
|
// LeaveAMessageLit#replyToast (presentation is configuration).
|
|
2695
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,
|
|
2696
2930
|
runtime: runtime2
|
|
2697
2931
|
});
|
|
2698
2932
|
container.appendChild(el);
|