@morgan-and-morgan/intake-agent 0.1.0-alpha.1 → 1.0.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/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 |
@@ -28,17 +28,14 @@
28
28
  };
29
29
  const readOpenState = (storage = sessionStorage) => readFlag(OPEN_STATE_KEY, storage);
30
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
- }
31
+ const readUnreadState = (storage = sessionStorage) => {
37
32
  try {
38
- storage.removeItem(UNREAD_STATE_KEY);
33
+ return storage.getItem(UNREAD_STATE_KEY) !== "false";
39
34
  } catch {
35
+ return false;
40
36
  }
41
37
  };
38
+ const writeUnreadState = (hasUnread, storage = sessionStorage) => writeFlag(UNREAD_STATE_KEY, hasUnread, storage);
42
39
  const EMBED_PROTOCOL_VERSION = 1;
43
40
  const EMBED_MESSAGE_TYPE = Object.freeze({
44
41
  HOST_READY: "mm:intake:host-ready",
@@ -200,7 +197,18 @@
200
197
  // mount (custom properties reach into the shadow tree) to lift the launcher
201
198
  // clear of it. Only the closed launcher: open, it moves to the top corner and
202
199
  // 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}}`,
200
+ // `left:0;right:0` rather than `width:100vw`: `100vw` counts the classic
201
+ // scrollbar the host page still has behind us, so a right-anchored panel that
202
+ // wide starts a scrollbar's width off the left edge and clips its own header.
203
+ //
204
+ // The shadow fills the strip below the panel. Safari's bottom bar is
205
+ // translucent once it collapses — scrolled down, or any time the keyboard is
206
+ // up — and `visualViewport.height` stops short of it, so the host page shows
207
+ // through underneath the chat. `lvh - svh` is exactly that bar's height, and
208
+ // it is 0 wherever the browser has no collapsing bar, so this costs nothing
209
+ // there. A shadow rather than extra height: the trust line and composer must
210
+ // stay above the bar, not slide under it.
211
+ `@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{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))}}`,
204
212
  "@media(prefers-reduced-motion:reduce){.mm-launcher,.mm-chat{animation:none;transition:none}.mm-badge::after,.mm-dot{animation:none}}"
205
213
  ].join("");
206
214
  const WIDGET_MARKUP = [
@@ -260,11 +268,14 @@
260
268
  let isKeyboardOpen = false;
261
269
  let hasReleasedKeyboardEarly = false;
262
270
  let hasUnread = readUnreadState();
271
+ const loadUnreadIndicator = () => {
272
+ elements.unreadBadge.hidden = !hasUnread;
273
+ syncLauncherLabel();
274
+ };
263
275
  const setHasUnread = (next) => {
264
276
  hasUnread = next;
265
- elements.unreadBadge.hidden = !next;
266
277
  writeUnreadState(next);
267
- syncLauncherLabel();
278
+ loadUnreadIndicator();
268
279
  };
269
280
  const syncLauncherLabel = () => {
270
281
  const isOpen = elements.chatDialog.dataset.state === "open";
@@ -338,9 +349,11 @@
338
349
  let createdThemeColor = null;
339
350
  const hostRoots = [document.documentElement, document.body];
340
351
  let hostBackgroundColorBackup = null;
352
+ let hostOverflowBackup = null;
341
353
  const borrowHostChrome = () => {
342
354
  if (themeColorBackup === null) {
343
355
  hostBackgroundColorBackup = hostRoots.map((root) => root.style.backgroundColor);
356
+ hostOverflowBackup = hostRoots.map((root) => root.style.overflow);
344
357
  const metas = [...document.head.querySelectorAll('meta[name="theme-color"]')];
345
358
  if (metas.length === 0) {
346
359
  createdThemeColor = document.createElement("meta");
@@ -352,13 +365,14 @@
352
365
  }
353
366
  for (const root of hostRoots) {
354
367
  root.style.setProperty("background-color", CHAT_CHROME_COLOR, "important");
368
+ root.style.setProperty("overflow", "hidden", "important");
355
369
  }
356
370
  for (const { meta } of themeColorBackup) {
357
371
  meta.content = CHAT_CHROME_COLOR;
358
372
  }
359
373
  };
360
374
  const restoreHostChrome = () => {
361
- var _a2;
375
+ var _a2, _b;
362
376
  if (themeColorBackup === null) {
363
377
  return;
364
378
  }
@@ -370,8 +384,10 @@
370
384
  themeColorBackup = null;
371
385
  for (const [index, root] of hostRoots.entries()) {
372
386
  root.style.backgroundColor = (_a2 = hostBackgroundColorBackup == null ? void 0 : hostBackgroundColorBackup[index]) != null ? _a2 : "";
387
+ root.style.overflow = (_b = hostOverflowBackup == null ? void 0 : hostOverflowBackup[index]) != null ? _b : "";
373
388
  }
374
389
  hostBackgroundColorBackup = null;
390
+ hostOverflowBackup = null;
375
391
  };
376
392
  const syncHostChrome = () => {
377
393
  if (elements.chatDialog.dataset.state !== "open") {
@@ -535,7 +551,7 @@
535
551
  });
536
552
  globalThis.addEventListener("message", handleMessage);
537
553
  document.addEventListener("keydown", handleKeydown);
538
- setHasUnread(hasUnread);
554
+ loadUnreadIndicator();
539
555
  if (completedSigningEnvelopeId !== null || readOpenState()) {
540
556
  openChat();
541
557
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@morgan-and-morgan/intake-agent",
3
- "version": "0.1.0-alpha.1",
3
+ "version": "1.0.0",
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
+ }