@morgan-and-morgan/intake-agent 0.1.0-alpha.1 → 1.0.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -0
- package/dist/mm-intake-widget.js +49 -96
- package/package.json +12 -11
package/README.md
CHANGED
|
@@ -9,6 +9,21 @@ Load the widget with a script tag, pinning an exact version:
|
|
|
9
9
|
></script>
|
|
10
10
|
```
|
|
11
11
|
|
|
12
|
+
## Versions
|
|
13
|
+
|
|
14
|
+
semantic-release publishes on every merge that touches this package and picks
|
|
15
|
+
the version from the commit messages, so the `version` in `package.json` is a
|
|
16
|
+
placeholder, don't bump it by hand.
|
|
17
|
+
|
|
18
|
+
| Branch | Version | dist-tag |
|
|
19
|
+
| --- | --- | --- |
|
|
20
|
+
| `develop` | `x.y.z-alpha.N` | `alpha` |
|
|
21
|
+
| `release/**` | `x.y.z-beta.N` | `beta` |
|
|
22
|
+
| `main` | `x.y.z` | `latest` |
|
|
23
|
+
|
|
24
|
+
`fix:` bumps the patch, `feat:` the minor, a `BREAKING CHANGE:` footer the
|
|
25
|
+
major. Every release is tagged `intake-agent-vx.y.z`.
|
|
26
|
+
|
|
12
27
|
## Attributes
|
|
13
28
|
|
|
14
29
|
| Attribute | Default | Purpose |
|
package/dist/mm-intake-widget.js
CHANGED
|
@@ -12,30 +12,16 @@
|
|
|
12
12
|
};
|
|
13
13
|
};
|
|
14
14
|
const OPEN_STATE_KEY = "mm-intake-widget-open";
|
|
15
|
-
const
|
|
16
|
-
const readFlag = (key, storage) => {
|
|
15
|
+
const readOpenState = (storage = sessionStorage) => {
|
|
17
16
|
try {
|
|
18
|
-
return storage.getItem(
|
|
17
|
+
return storage.getItem(OPEN_STATE_KEY) === "true";
|
|
19
18
|
} catch {
|
|
20
19
|
return false;
|
|
21
20
|
}
|
|
22
21
|
};
|
|
23
|
-
const
|
|
22
|
+
const writeOpenState = (isOpen, storage = sessionStorage) => {
|
|
24
23
|
try {
|
|
25
|
-
storage.setItem(
|
|
26
|
-
} catch {
|
|
27
|
-
}
|
|
28
|
-
};
|
|
29
|
-
const readOpenState = (storage = sessionStorage) => readFlag(OPEN_STATE_KEY, storage);
|
|
30
|
-
const writeOpenState = (isOpen, storage = sessionStorage) => writeFlag(OPEN_STATE_KEY, isOpen, storage);
|
|
31
|
-
const readUnreadState = (storage = sessionStorage) => readFlag(UNREAD_STATE_KEY, storage);
|
|
32
|
-
const writeUnreadState = (hasUnread, storage = sessionStorage) => {
|
|
33
|
-
if (hasUnread) {
|
|
34
|
-
writeFlag(UNREAD_STATE_KEY, true, storage);
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
try {
|
|
38
|
-
storage.removeItem(UNREAD_STATE_KEY);
|
|
24
|
+
storage.setItem(OPEN_STATE_KEY, String(isOpen));
|
|
39
25
|
} catch {
|
|
40
26
|
}
|
|
41
27
|
};
|
|
@@ -60,10 +46,10 @@
|
|
|
60
46
|
// belongs to the focused field, so losing it means the keyboard is already
|
|
61
47
|
// leaving — which the host's own visual viewport only admits ~500ms later.
|
|
62
48
|
CARET_STATE: "mm:intake:caret-state",
|
|
63
|
-
// Chat tells the host an inbound AI or operator message just landed
|
|
64
|
-
//
|
|
65
|
-
//
|
|
66
|
-
// the panel was closed at the time.
|
|
49
|
+
// Chat tells the host an inbound AI or operator message just landed. Kept in
|
|
50
|
+
// the protocol for a future unread affordance; the TEXT US sticky has no badge
|
|
51
|
+
// today. Payload-free: only the chat knows a message arrived while only the
|
|
52
|
+
// host knows whether the panel was closed at the time.
|
|
67
53
|
MESSAGE_RECEIVED: "mm:intake:message-received"
|
|
68
54
|
});
|
|
69
55
|
const isRecord = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
@@ -131,85 +117,56 @@
|
|
|
131
117
|
"circle-check": '<circle cx="12" cy="12" r="10"/><path d="m9 12 2 2 4-4"/>',
|
|
132
118
|
"chevron-down": '<path d="m6 9 6 6 6-6"/>'
|
|
133
119
|
};
|
|
120
|
+
const BUTTON_TEXT_US = "data:image/png;base64,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";
|
|
134
121
|
const FULL_PAGE_PANEL_QUERY = "(max-width:600px),(max-height:500px)";
|
|
135
122
|
const lucideIcon = (name, className, strokeWidth = 2) => `<svg class="${className}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="${String(strokeWidth)}" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false">${LUCIDE_ICON_PATHS[name]}</svg>`;
|
|
136
|
-
const CHAT_ICON = lucideIcon("message-circle", "mm-icon mm-icon-chat");
|
|
137
123
|
const OPEN_CLOSE_ICON = lucideIcon("x", "mm-icon mm-icon-close");
|
|
138
124
|
const WIDGET_STYLES = [
|
|
139
125
|
':host{all:initial;color-scheme:light;--mm-yellow:#fdeb01;--mm-yellow-hover:#f5de00;--mm-yellow-pressed:#e6cc00;--mm-blue:#115099;--mm-blue-hover:#0b3568;--mm-ink:#111;--mm-white:#fff;--mm-surface-blue:#f3f8ff;--mm-chrome:#e8eef2;--mm-line:#e2e8f0;--mm-muted:#545454;--mm-green:#0f9d58;--mm-font:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif}',
|
|
140
126
|
"*,*::before,*::after{box-sizing:border-box}",
|
|
141
127
|
"button{font:inherit}",
|
|
142
|
-
"@keyframes mm-launcher-in{from{opacity:0;transform:
|
|
128
|
+
"@keyframes mm-launcher-in{from{opacity:0;transform:translate(8px,-50%) scale(.94)}to{opacity:1;transform:translateY(-50%) scale(1)}}",
|
|
129
|
+
"@keyframes mm-close-in{from{opacity:0;transform:scale(.85)}to{opacity:1;transform:scale(1)}}",
|
|
143
130
|
"@keyframes mm-panel-in{from{opacity:0;transform:translateY(10px) scale(.98)}to{opacity:1;transform:none}}",
|
|
144
131
|
"@keyframes mm-panel-out{from{opacity:1;transform:none}to{opacity:0;transform:translateY(10px) scale(.98)}}",
|
|
145
|
-
"@keyframes mm-ping{0%{transform:scale(1);opacity:.55}70%,100%{transform:scale(2.4);opacity:0}}",
|
|
146
|
-
// Same register as the chat's own typing dots (typing-indicator.tsx): rest at
|
|
147
|
-
// .4 opacity, pulse to full with a 1.2x scale, each dot a beat behind the last.
|
|
148
132
|
"@keyframes mm-dot{0%,100%{opacity:.4;transform:scale(1)}50%{opacity:1;transform:scale(1.2)}}",
|
|
149
|
-
//
|
|
150
|
-
//
|
|
151
|
-
|
|
133
|
+
// Closed: LivePerson TEXT US sticky under the chat layer. Open: swap for a
|
|
134
|
+
// blue X disc above the chat so there is always a clear close control.
|
|
135
|
+
// Site sticky sits a few px in from the viewport edge, not flush.
|
|
136
|
+
// Against the host page the near-max z-index is only the fallback for
|
|
137
|
+
// browsers without the Popover API — everywhere else the mount rides the top
|
|
138
|
+
// layer (widget.ts) and outranks any host z-index.
|
|
139
|
+
".mm-launcher{position:fixed;right:10px;top:42%;z-index:2147482999;display:grid;place-items:center;width:auto;height:auto;padding:0;border:0;border-radius:0;outline:none;background:transparent;color:var(--mm-ink);box-shadow:none;cursor:pointer;user-select:none;-webkit-user-select:none;-webkit-user-drag:none;transform:translateY(-50%);animation:mm-launcher-in .28s cubic-bezier(.23,1,.32,1) both;transition:transform .15s cubic-bezier(.23,1,.32,1),filter .15s ease,background-color .15s ease}",
|
|
152
140
|
".mm-launcher *{user-select:none;-webkit-user-select:none;-webkit-user-drag:none}",
|
|
153
|
-
".mm-launcher:hover{
|
|
154
|
-
".mm-launcher:active{
|
|
141
|
+
".mm-launcher:hover{transform:translateY(-50%) translateX(-2px);filter:drop-shadow(0 4px 10px rgba(17,17,17,.18))}",
|
|
142
|
+
".mm-launcher:active{transform:translateY(-50%) translateX(0);filter:none}",
|
|
155
143
|
".mm-launcher:focus-visible{outline:3px solid var(--mm-blue);outline-offset:3px}",
|
|
156
|
-
".mm-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
'.mm-launcher[aria-expanded="true"]
|
|
144
|
+
".mm-text-us{display:block;width:38px;height:auto;pointer-events:none}",
|
|
145
|
+
".mm-icon{position:absolute;top:50%;left:50%;display:none;width:22px;height:22px;pointer-events:none;transform:translate(-50%,-50%)}",
|
|
146
|
+
// Open on desktop: X sits on the chat's top-right corner (chat is bottom:24,
|
|
147
|
+
// height min(640px, 100vh - 48px)).
|
|
148
|
+
'.mm-launcher[aria-expanded="true"]{top:calc(100vh - 24px - min(640px,100vh - 48px) + 12px);right:36px;bottom:auto;z-index:2147483001;width:44px;height:44px;border-radius:999px;background:var(--mm-blue);color:var(--mm-white);box-shadow:0 4px 14px rgba(17,17,17,.2);transform:none;animation:mm-close-in .2s cubic-bezier(.23,1,.32,1) both;filter:none}',
|
|
149
|
+
'.mm-launcher[aria-expanded="true"]:hover,.mm-launcher[aria-expanded="true"]:active{transform:none;filter:none;background:var(--mm-blue-hover)}',
|
|
150
|
+
'.mm-launcher[aria-expanded="true"] .mm-text-us{display:none}',
|
|
161
151
|
'.mm-launcher[aria-expanded="true"] .mm-icon-close{display:block}',
|
|
162
|
-
|
|
163
|
-
// tint. Measured on iOS 26: while the panel is full-page, Safari takes the
|
|
164
|
-
// colour of its own status-bar and URL-bar bands straight off this background
|
|
165
|
-
// — ahead of the host page's `theme-color` and root background, which it
|
|
166
|
-
// ignores outright once the chat frame has committed a navigation. So this is
|
|
167
|
-
// the lever that decides what the bands look like, and the bands sit right
|
|
168
|
-
// against the chat's header and trust line.
|
|
169
|
-
// Two flat halves rather than one colour, because the two bands are sampled
|
|
170
|
-
// independently: the top one always sits against the chat header, while the
|
|
171
|
-
// bottom one sits against the trust line or, with a keyboard up, the composer.
|
|
172
|
-
".mm-chat{position:fixed;right:24px;bottom:100px;z-index:2147483000;display:flex;flex-direction:column;width:min(400px,calc(100vw - 32px));height:min(640px,calc(100vh - 132px));overflow:hidden;border:1px solid var(--mm-line);border-radius:20px;background:linear-gradient(to bottom,var(--mm-chrome) 0 50%,var(--mm-panel-bottom,var(--mm-chrome)) 50% 100%);box-shadow:0 5px 25px rgba(0,0,0,.2);animation:mm-panel-in .18s ease-out both;font-family:var(--mm-font)}",
|
|
173
|
-
// Keyboard up, the chat drops its trust line and the composer becomes the
|
|
174
|
-
// bottom-most surface, so the bottom band has to follow the composer. Only
|
|
175
|
-
// the bottom: the header is still up there against the top one.
|
|
152
|
+
".mm-chat{position:fixed;right:24px;bottom:24px;z-index:2147483000;display:flex;flex-direction:column;width:min(400px,calc(100vw - 32px));height:min(640px,calc(100vh - 48px));overflow:hidden;border:1px solid var(--mm-line);border-radius:20px;background:linear-gradient(to bottom,var(--mm-chrome) 0 50%,var(--mm-panel-bottom,var(--mm-chrome)) 50% 100%);box-shadow:0 5px 25px rgba(0,0,0,.2);animation:mm-panel-in .18s ease-out both;font-family:var(--mm-font)}",
|
|
176
153
|
'.mm-chat[data-keyboard="open"]{--mm-panel-bottom:var(--mm-surface-blue)}',
|
|
177
154
|
'.mm-chat[data-state="closing"]{pointer-events:none;animation-name:mm-panel-out}',
|
|
178
155
|
'.mm-chat[data-state="closed"]{visibility:hidden;animation-name:none}',
|
|
179
156
|
".mm-frame-wrap{position:relative;min-height:0;flex:1;background:linear-gradient(to bottom,var(--mm-chrome) 0 50%,var(--mm-panel-bottom,var(--mm-chrome)) 50% 100%)}",
|
|
180
|
-
// A chat tone, never white: the frame paints this in the gap between the
|
|
181
|
-
// document's load event and the app's first frame, and on a phone that gap is
|
|
182
|
-
// the whole screen.
|
|
183
157
|
".mm-frame{display:block;width:100%;height:100%;border:0;background:var(--mm-chrome)}",
|
|
184
158
|
".mm-loading{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;gap:5px;background:var(--mm-chrome)}",
|
|
185
159
|
".mm-dot{width:8px;height:8px;border-radius:999px;background:var(--mm-muted);animation:mm-dot 1.2s ease-in-out infinite}",
|
|
186
160
|
".mm-dot:nth-child(2){animation-delay:.15s}",
|
|
187
161
|
".mm-dot:nth-child(3){animation-delay:.3s}",
|
|
188
162
|
"[hidden]{display:none!important}",
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
// layout viewport's top would be panned clean off the screen with it.
|
|
192
|
-
//
|
|
193
|
-
// `min-height:0` on the panel so a short landscape viewport shrinks it all the
|
|
194
|
-
// way down instead of overflowing the screen and clipping the chat's own
|
|
195
|
-
// rotate-your-phone overlay.
|
|
196
|
-
//
|
|
197
|
-
// 16px from the corner is right for a normal host site, which has nothing of
|
|
198
|
-
// its own down there. A host that mounts its own bottom chrome — the client
|
|
199
|
-
// portal and its tab bar — sets `--mm-launcher-bottom` on any ancestor of the
|
|
200
|
-
// mount (custom properties reach into the shadow tree) to lift the launcher
|
|
201
|
-
// clear of it. Only the closed launcher: open, it moves to the top corner and
|
|
202
|
-
// tracks the viewport instead.
|
|
203
|
-
`@media ${FULL_PAGE_PANEL_QUERY}{.mm-launcher{right:16px;bottom:var(--mm-launcher-bottom,16px)}.mm-launcher[aria-expanded="true"]{top:calc(var(--mm-viewport-top,0px) + 10px);right:10px;bottom:auto;width:44px;height:44px;box-shadow:0 4px 14px rgba(17,17,17,.2)}.mm-launcher[aria-expanded="true"] .mm-icon{width:22px;height:22px}.mm-chat{right:0;top:var(--mm-viewport-top,auto);bottom:0;width:100vw;height:var(--mm-viewport-height,100dvh);min-height:0;border:0;border-radius:0}}`,
|
|
204
|
-
"@media(prefers-reduced-motion:reduce){.mm-launcher,.mm-chat{animation:none;transition:none}.mm-badge::after,.mm-dot{animation:none}}"
|
|
163
|
+
`@media ${FULL_PAGE_PANEL_QUERY}{.mm-launcher[aria-expanded="true"]{top:calc(var(--mm-viewport-top,0px) + 10px);right:10px;bottom:auto;width:44px;height:44px}.mm-chat{left:0;right:0;top:var(--mm-viewport-top,auto);bottom:0;width:auto;height:var(--mm-viewport-height,100dvh);min-height:0;border:0;border-radius:0;box-shadow:0 calc(100lvh - 100svh) 0 var(--mm-panel-bottom,var(--mm-chrome))}}`,
|
|
164
|
+
"@media(prefers-reduced-motion:reduce){.mm-launcher,.mm-chat{animation:none;transition:none}.mm-dot{animation:none}}"
|
|
205
165
|
].join("");
|
|
206
166
|
const WIDGET_MARKUP = [
|
|
207
167
|
`<style>${WIDGET_STYLES}</style>`,
|
|
208
|
-
`<button class="mm-launcher" type="button" aria-label="Open intake chat" aria-expanded="false" draggable="false"
|
|
168
|
+
`<button class="mm-launcher" type="button" aria-label="Open intake chat" aria-expanded="false" draggable="false"><img class="mm-text-us" src="${BUTTON_TEXT_US}" alt="" width="38" height="146" decoding="async" />${OPEN_CLOSE_ICON}</button>`,
|
|
209
169
|
'<section class="mm-chat" role="dialog" aria-label="Morgan and Morgan intake chat" inert hidden>',
|
|
210
|
-
// Dots rather than a sentence: the panel is up for a second or two and a line
|
|
211
|
-
// of copy reads like an error the visitor has to act on. The label carries the
|
|
212
|
-
// same information for a screen reader.
|
|
213
170
|
'<div class="mm-frame-wrap"><div class="mm-loading" role="status" aria-label="Loading secure chat"><span class="mm-dot"></span><span class="mm-dot"></span><span class="mm-dot"></span></div><iframe class="mm-frame mm-chat-frame" title="Morgan and Morgan intake chat" referrerpolicy="strict-origin-when-cross-origin"></iframe></div>',
|
|
214
171
|
"</section>"
|
|
215
172
|
].join("");
|
|
@@ -226,20 +183,13 @@
|
|
|
226
183
|
chatDialog: requireElement(shadow, ".mm-chat"),
|
|
227
184
|
chatFrame: requireElement(shadow, ".mm-chat-frame"),
|
|
228
185
|
chatLoading: requireElement(shadow, ".mm-loading"),
|
|
229
|
-
launcher: requireElement(shadow, ".mm-launcher")
|
|
230
|
-
unreadBadge: requireElement(shadow, ".mm-badge")
|
|
186
|
+
launcher: requireElement(shadow, ".mm-launcher")
|
|
231
187
|
};
|
|
232
188
|
};
|
|
233
189
|
const PANEL_ANIMATION_MS = 180;
|
|
234
190
|
const CHAT_CHROME_COLOR = "#e8eef2";
|
|
235
191
|
const KEYBOARD_MIN_SHRINK_PX = 100;
|
|
236
192
|
const CHAT_READY_FALLBACK_MS = 4e3;
|
|
237
|
-
const getLauncherLabel = (isOpen, hasUnread) => {
|
|
238
|
-
if (isOpen) {
|
|
239
|
-
return "Close intake chat";
|
|
240
|
-
}
|
|
241
|
-
return hasUnread ? "Open intake chat, new message" : "Open intake chat";
|
|
242
|
-
};
|
|
243
193
|
const cleanSigningReturnUrl = () => {
|
|
244
194
|
const cleanedReturnUrl = buildSigningReturnUrl();
|
|
245
195
|
if (cleanedReturnUrl !== null) {
|
|
@@ -253,23 +203,24 @@
|
|
|
253
203
|
const shadow = mount.attachShadow({ mode: "open" });
|
|
254
204
|
const elements = renderWidgetShell(shadow);
|
|
255
205
|
document.body.append(mount);
|
|
206
|
+
if (typeof mount.showPopover === "function") {
|
|
207
|
+
mount.setAttribute("popover", "manual");
|
|
208
|
+
mount.style.cssText = "position:fixed;inset:0 auto auto 0;width:0;height:0;margin:0;border:0;padding:0;overflow:visible;background:transparent";
|
|
209
|
+
try {
|
|
210
|
+
mount.showPopover();
|
|
211
|
+
} catch {
|
|
212
|
+
}
|
|
213
|
+
}
|
|
256
214
|
const completedSigningEnvelopeId = readCompletedSigningEnvelopeId();
|
|
257
215
|
let chatHasLoaded = false;
|
|
258
216
|
let chatCloseTimer;
|
|
259
217
|
let chatReadyTimer;
|
|
260
218
|
let isKeyboardOpen = false;
|
|
261
219
|
let hasReleasedKeyboardEarly = false;
|
|
262
|
-
let hasUnread = readUnreadState();
|
|
263
|
-
const setHasUnread = (next) => {
|
|
264
|
-
hasUnread = next;
|
|
265
|
-
elements.unreadBadge.hidden = !next;
|
|
266
|
-
writeUnreadState(next);
|
|
267
|
-
syncLauncherLabel();
|
|
268
|
-
};
|
|
269
220
|
const syncLauncherLabel = () => {
|
|
270
221
|
const isOpen = elements.chatDialog.dataset.state === "open";
|
|
271
222
|
elements.launcher.setAttribute("aria-expanded", String(isOpen));
|
|
272
|
-
elements.launcher.setAttribute("aria-label",
|
|
223
|
+
elements.launcher.setAttribute("aria-label", isOpen ? "Close intake chat" : "Open intake chat");
|
|
273
224
|
};
|
|
274
225
|
const postToChat = (message) => {
|
|
275
226
|
var _a2;
|
|
@@ -338,9 +289,11 @@
|
|
|
338
289
|
let createdThemeColor = null;
|
|
339
290
|
const hostRoots = [document.documentElement, document.body];
|
|
340
291
|
let hostBackgroundColorBackup = null;
|
|
292
|
+
let hostOverflowBackup = null;
|
|
341
293
|
const borrowHostChrome = () => {
|
|
342
294
|
if (themeColorBackup === null) {
|
|
343
295
|
hostBackgroundColorBackup = hostRoots.map((root) => root.style.backgroundColor);
|
|
296
|
+
hostOverflowBackup = hostRoots.map((root) => root.style.overflow);
|
|
344
297
|
const metas = [...document.head.querySelectorAll('meta[name="theme-color"]')];
|
|
345
298
|
if (metas.length === 0) {
|
|
346
299
|
createdThemeColor = document.createElement("meta");
|
|
@@ -352,13 +305,14 @@
|
|
|
352
305
|
}
|
|
353
306
|
for (const root of hostRoots) {
|
|
354
307
|
root.style.setProperty("background-color", CHAT_CHROME_COLOR, "important");
|
|
308
|
+
root.style.setProperty("overflow", "hidden", "important");
|
|
355
309
|
}
|
|
356
310
|
for (const { meta } of themeColorBackup) {
|
|
357
311
|
meta.content = CHAT_CHROME_COLOR;
|
|
358
312
|
}
|
|
359
313
|
};
|
|
360
314
|
const restoreHostChrome = () => {
|
|
361
|
-
var _a2;
|
|
315
|
+
var _a2, _b;
|
|
362
316
|
if (themeColorBackup === null) {
|
|
363
317
|
return;
|
|
364
318
|
}
|
|
@@ -370,8 +324,10 @@
|
|
|
370
324
|
themeColorBackup = null;
|
|
371
325
|
for (const [index, root] of hostRoots.entries()) {
|
|
372
326
|
root.style.backgroundColor = (_a2 = hostBackgroundColorBackup == null ? void 0 : hostBackgroundColorBackup[index]) != null ? _a2 : "";
|
|
327
|
+
root.style.overflow = (_b = hostOverflowBackup == null ? void 0 : hostOverflowBackup[index]) != null ? _b : "";
|
|
373
328
|
}
|
|
374
329
|
hostBackgroundColorBackup = null;
|
|
330
|
+
hostOverflowBackup = null;
|
|
375
331
|
};
|
|
376
332
|
const syncHostChrome = () => {
|
|
377
333
|
if (elements.chatDialog.dataset.state !== "open") {
|
|
@@ -427,7 +383,7 @@
|
|
|
427
383
|
elements.chatDialog.dataset.state = "open";
|
|
428
384
|
elements.chatDialog.removeAttribute("aria-hidden");
|
|
429
385
|
elements.chatDialog.removeAttribute("inert");
|
|
430
|
-
|
|
386
|
+
syncLauncherLabel();
|
|
431
387
|
startViewportTracking();
|
|
432
388
|
ensureChatLoaded();
|
|
433
389
|
elements.chatFrame.focus();
|
|
@@ -484,9 +440,6 @@
|
|
|
484
440
|
return;
|
|
485
441
|
}
|
|
486
442
|
if (isEmbedProtocolMessage(message, EMBED_MESSAGE_TYPE.MESSAGE_RECEIVED)) {
|
|
487
|
-
if (elements.chatDialog.dataset.state !== "open") {
|
|
488
|
-
setHasUnread(true);
|
|
489
|
-
}
|
|
490
443
|
return;
|
|
491
444
|
}
|
|
492
445
|
if (isEmbedProtocolMessage(message, EMBED_MESSAGE_TYPE.SIGNING_REQUESTED)) {
|
|
@@ -535,7 +488,7 @@
|
|
|
535
488
|
});
|
|
536
489
|
globalThis.addEventListener("message", handleMessage);
|
|
537
490
|
document.addEventListener("keydown", handleKeydown);
|
|
538
|
-
|
|
491
|
+
syncLauncherLabel();
|
|
539
492
|
if (completedSigningEnvelopeId !== null || readOpenState()) {
|
|
540
493
|
openChat();
|
|
541
494
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@morgan-and-morgan/intake-agent",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.0.0-alpha.2",
|
|
4
4
|
"description": "Embeddable chat widget loader.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"files": [
|
|
@@ -18,20 +18,21 @@
|
|
|
18
18
|
"publishConfig": {
|
|
19
19
|
"access": "public"
|
|
20
20
|
},
|
|
21
|
-
"devDependencies": {
|
|
22
|
-
"eslint": "^9.39.1",
|
|
23
|
-
"lucide-react-native": "^0.562.0",
|
|
24
|
-
"typescript": "~5.9.3",
|
|
25
|
-
"vite": "^7.3.6",
|
|
26
|
-
"@mmcp/eslint-config": "0.1.0",
|
|
27
|
-
"@mmcp/tsconfig": "0.1.0"
|
|
28
|
-
},
|
|
29
21
|
"scripts": {
|
|
30
22
|
"build": "pnpm run build:bundle",
|
|
31
23
|
"build:bundle": "node scripts/generate-icons.mjs && vite build",
|
|
32
24
|
"generate:icons": "node scripts/generate-icons.mjs",
|
|
33
25
|
"typecheck": "tsc --noEmit",
|
|
34
26
|
"lint": "eslint \"src/**/*.ts\" --quiet",
|
|
35
|
-
"lint:fix": "eslint \"src/**/*.ts\" --quiet --fix"
|
|
27
|
+
"lint:fix": "eslint \"src/**/*.ts\" --quiet --fix",
|
|
28
|
+
"prepublishOnly": "pnpm run build:bundle"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@mmcp/eslint-config": "workspace:*",
|
|
32
|
+
"@mmcp/tsconfig": "workspace:*",
|
|
33
|
+
"eslint": "^9.39.1",
|
|
34
|
+
"lucide-react-native": "^0.562.0",
|
|
35
|
+
"typescript": "~5.9.3",
|
|
36
|
+
"vite": "^7.3.6"
|
|
36
37
|
}
|
|
37
|
-
}
|
|
38
|
+
}
|