@morgan-and-morgan/intake-agent 1.0.0-alpha.18 → 1.0.0-alpha.19

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
@@ -52,6 +52,19 @@ modal is about to appear; the launcher and chat remain available. Set suppressio
52
52
  before loading the embed when using a zero-second delay, so the first display
53
53
  check sees the intended setting.
54
54
 
55
+ ## Chat launcher design
56
+
57
+ The [Figma launcher](https://www.figma.com/design/0SxWl42gdhx08KFe2ldpd8/MM-Design-System-v4.0?node-id=21250-170681)
58
+ is displayed at roughly 70% size as a 45 × 140 px tab on the right edge. It uses
59
+ live HTML text and an accessible button name, with Nunito Sans loaded through the
60
+ existing shared font registration.
61
+ The original 199 × 64 px layout, typography, and spacing stay intact. One transform
62
+ rotates and scales the content; `LAUNCHER_SCALE` also determines the rounded button
63
+ dimensions so the click target and focus outline fit the visible tab.
64
+ `launcher-chat.svg` is the original 48 × 48 vector export from node `21252:170716`,
65
+ so it stays sharp at 3× and higher pixel densities. Keep the CDN and portal copies
66
+ identical. Retain `button-text-us.png` for older deployed widget versions.
67
+
55
68
  ## Consultation prompt design
56
69
 
57
70
  The responsive prompt follows the [desktop and mobile Figma layouts](https://www.figma.com/design/0SxWl42gdhx08KFe2ldpd8/MM-Design-System-v4.0?node-id=21250-169311).
@@ -0,0 +1,23 @@
1
+ <svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <g id="chat 1" clip-path="url(#clip0_0_4)">
3
+ <path id="Vector" d="M43.8261 40.2077C46.5258 37.3111 47.9976 33.7303 47.9976 29.9994C47.9976 25.3311 45.6915 21.1034 41.9982 18.1037C41.9138 28.7995 31.8555 37.4986 19.5005 37.4986H11.1388C14.3729 42.8325 20.9441 46.4977 28.4995 46.4977H46.4977C47.107 46.4977 47.6507 46.1321 47.8851 45.5697C48.1194 45.0072 47.9882 44.3604 47.557 43.9386L43.8261 40.2077Z" fill="url(#paint0_linear_0_4)"/>
4
+ <path id="Vector_2" d="M19.5005 1.50228C8.74842 1.50228 0.00243725 8.89841 0.00243725 18.0006C0.00243725 21.7315 1.47416 25.303 4.17389 28.2089L0.443018 31.9398C0.0118113 32.371 -0.119425 33.0178 0.114926 33.5709C0.349277 34.1333 0.892972 34.4989 1.50228 34.4989H19.5005C30.2525 34.4989 38.9985 27.1028 38.9985 18.0006C38.9985 8.89841 30.2525 1.50228 19.5005 1.50228Z" fill="url(#paint1_linear_0_4)"/>
5
+ <g id="Group">
6
+ <path id="Vector_3" d="M28.4995 13.5011H10.5014C9.67645 13.5011 9.00152 14.176 9.00152 15.0009C9.00152 15.8258 9.67645 16.5008 10.5014 16.5008H28.4995C29.3245 16.5008 29.9994 15.8258 29.9994 15.0009C29.9994 14.176 29.3245 13.5011 28.4995 13.5011Z" fill="white"/>
7
+ <path id="Vector_4" d="M22.5002 19.5005H10.5014C9.67645 19.5005 9.00152 20.1754 9.00152 21.0003C9.00152 21.8252 9.67645 22.5002 10.5014 22.5002H22.5002C23.3251 22.5002 24 21.8252 24 21.0003C24 20.1754 23.3251 19.5005 22.5002 19.5005Z" fill="white"/>
8
+ </g>
9
+ </g>
10
+ <defs>
11
+ <linearGradient id="paint0_linear_0_4" x1="29.5694" y1="18.1037" x2="29.5694" y2="46.4977" gradientUnits="userSpaceOnUse">
12
+ <stop offset="0.418269" stop-color="#FFEC00"/>
13
+ <stop offset="1" stop-color="#E2D100"/>
14
+ </linearGradient>
15
+ <linearGradient id="paint1_linear_0_4" x1="-2.52862e-06" y1="18.0006" x2="38.9985" y2="18.0006" gradientUnits="userSpaceOnUse">
16
+ <stop stop-color="#0163D2"/>
17
+ <stop offset="1" stop-color="#4C9FFD"/>
18
+ </linearGradient>
19
+ <clipPath id="clip0_0_4">
20
+ <rect width="48" height="48" fill="white"/>
21
+ </clipPath>
22
+ </defs>
23
+ </svg>
@@ -161,7 +161,7 @@
161
161
  // leaving — which the host's own visual viewport only admits ~500ms later.
162
162
  CARET_STATE: "mm:intake:caret-state",
163
163
  // Chat tells the host an inbound AI or operator message just landed. Kept in
164
- // the protocol for a future unread affordance; the TEXT US sticky has no badge
164
+ // the protocol for a future unread affordance; the chat launcher has no badge
165
165
  // today. Payload-free: only the chat knows a message arrived while only the
166
166
  // host knows whether the panel was closed at the time.
167
167
  MESSAGE_RECEIVED: "mm:intake:message-received",
@@ -236,8 +236,16 @@
236
236
  const designSystemColors = {
237
237
  // Colors/Base/black
238
238
  "base-black": "#000000",
239
+ // Colors/Base/white
240
+ "base-white": "#ffffff",
241
+ // Colors/Neutral/500
242
+ "neutral-500": "#737373",
243
+ // Colors/Neutral/900
244
+ "neutral-900": "#171717",
239
245
  // Colors/Primary/100
240
246
  "primary-100": "#f3f8ff",
247
+ // Colors/Primary/600
248
+ "primary-600": "#135ebf",
241
249
  // Colors/Primary/800
242
250
  "primary-800": "#132a4e",
243
251
  // Colors/Primary/900
@@ -245,7 +253,9 @@
245
253
  // Colors/Secondary/500
246
254
  "secondary-500": "#ffec00",
247
255
  // Colors/Secondary/700
248
- "secondary-700": "#e2d100"
256
+ "secondary-700": "#e2d100",
257
+ // Component colors/Alpha/alpha-black-20
258
+ "alpha-black-20": "#00000033"
249
259
  };
250
260
  const PROMPT_FONTS = [
251
261
  {
@@ -377,6 +387,9 @@
377
387
  const FULL_PAGE_PANEL_QUERY = "(max-width:600px),(max-height:500px)";
378
388
  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>`;
379
389
  const OPEN_CLOSE_ICON = lucideIcon("x", "mm-icon mm-icon-close");
390
+ const LAUNCHER_SCALE = 0.7;
391
+ const LAUNCHER_WIDTH = Math.ceil(64 * LAUNCHER_SCALE);
392
+ const LAUNCHER_HEIGHT = Math.ceil(199 * LAUNCHER_SCALE);
380
393
  const WIDGET_STYLES = [
381
394
  ':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}',
382
395
  "*,*::before,*::after{box-sizing:border-box}",
@@ -388,26 +401,26 @@
388
401
  "@keyframes mm-prompt-backdrop-in{from{opacity:0}to{opacity:1}}",
389
402
  "@keyframes mm-prompt-card-in{from{opacity:0;transform:scale(.96)}to{opacity:1;transform:none}}",
390
403
  "@keyframes mm-dot{0%,100%{opacity:.4;transform:scale(1)}50%{opacity:1;transform:scale(1.2)}}",
391
- // Closed: LivePerson TEXT US sticky under the chat layer. Open: swap for a
392
- // blue X disc above the chat so there is always a clear close control.
393
- // Same asset as forthepeople.com (button-text-us-white-bg), already rotated
394
- // 90deg CW like GTM. Placement matches #messaging_gbm: top 42%, ~38px thick,
395
- // no translateY(-50%). right:10px keeps a small inset from the viewport edge.
396
- // Against the host page the near-max z-index is only the fallback for
397
- // browsers without the Popover API — everywhere else the mount rides the top
398
- // layer (widget.ts) and outranks any host z-index.
399
- ".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:none;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}",
404
+ // The same button becomes the close control while the chat is open.
405
+ `.mm-launcher{position:fixed;right:0;top:42%;top:max(0px,min(42%,calc(100dvh - ${String(LAUNCHER_HEIGHT + 8)}px)));z-index:2147482999;display:grid;place-items:center;width:${String(LAUNCHER_WIDTH)}px;height:${String(LAUNCHER_HEIGHT)}px;padding:0;border:0;border-radius:${String(16 * LAUNCHER_SCALE)}px 0 0 ${String(16 * LAUNCHER_SCALE)}px;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:none;animation:mm-launcher-in .28s cubic-bezier(.23,1,.32,1) both;transition:filter .15s ease,background-color .15s ease}`,
400
406
  ".mm-launcher *{user-select:none;-webkit-user-select:none;-webkit-user-drag:none}",
401
- ".mm-launcher:hover{transform:translateX(-2px);filter:drop-shadow(0 4px 10px rgba(17,17,17,.18))}",
402
- ".mm-launcher:active{transform:none;filter:none}",
403
- ".mm-launcher:focus-visible{outline:3px solid var(--mm-blue);outline-offset:3px}",
404
- ".mm-text-us{display:block;width:38px;height:auto;pointer-events:none}",
407
+ ".mm-launcher:hover{filter:brightness(.97)}",
408
+ ".mm-launcher:active{filter:none}",
409
+ ".mm-launcher:focus-visible{outline:3px solid var(--mm-blue);outline-offset:-3px}",
410
+ // Keep Figma's original horizontal layout; rotate and scale it as one unit.
411
+ `.mm-launcher-content{position:absolute;top:50%;left:50%;display:flex;align-items:center;gap:12px;width:199px;height:64px;padding:8px 12px 8px 8px;transform:translate(-50%,-50%) rotate(90deg) scale(${String(LAUNCHER_SCALE)});border-radius:0 0 16px 16px;background:${designSystemColors["base-white"]};box-shadow:0 0 0 .5px ${designSystemColors["neutral-500"]},inset 0 0 0 .5px ${designSystemColors["neutral-500"]},0 4px 12px ${designSystemColors["alpha-black-20"]};pointer-events:none}`,
412
+ ".mm-launcher-chat-icon{display:block;flex:none;width:48px;height:48px}",
413
+ `.mm-launcher-copy{display:flex;flex:none;flex-direction:column;width:119px;height:46px;text-align:left;white-space:nowrap;font-family:"MMIntakeNunitoSans",var(--mm-font);font-weight:700;font-variation-settings:"YTLC" 500,"wdth" 100;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;color:${designSystemColors["neutral-900"]}}`,
414
+ ".mm-launcher-title{font-size:20px;line-height:27px;margin-bottom:-2px}",
415
+ `.mm-launcher-subtitle{font-size:14px;line-height:21px;color:${designSystemColors["primary-600"]}}`,
416
+ "@media(forced-colors:active){.mm-launcher-content{outline:1px solid ButtonText}.mm-launcher:focus-visible{outline-color:Highlight}}",
405
417
  ".mm-icon{position:absolute;top:50%;left:50%;display:none;width:22px;height:22px;pointer-events:none;transform:translate(-50%,-50%)}",
406
418
  // Open on desktop: X sits on the chat's top-right corner (chat is bottom:24,
407
419
  // height min(640px, 100vh - 48px)).
408
420
  '.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}',
409
421
  '.mm-launcher[aria-expanded="true"]:hover,.mm-launcher[aria-expanded="true"]:active{transform:none;filter:none;background:var(--mm-blue-hover)}',
410
- '.mm-launcher[aria-expanded="true"] .mm-text-us{display:none}',
422
+ '.mm-launcher[aria-expanded="true"]:focus-visible{outline-offset:3px}',
423
+ '.mm-launcher[aria-expanded="true"] .mm-launcher-content{display:none}',
411
424
  '.mm-launcher[aria-expanded="true"] .mm-icon-close{display:block}',
412
425
  ".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)}",
413
426
  '.mm-chat[data-keyboard="open"]{--mm-panel-bottom:var(--mm-surface-blue)}',
@@ -426,7 +439,7 @@
426
439
  ].join("");
427
440
  const widgetMarkup = (assetUrl) => [
428
441
  `<style>${WIDGET_STYLES}</style>`,
429
- `<button class="mm-launcher" type="button" aria-label="Open intake chat" aria-expanded="false" draggable="false"><img class="mm-text-us" src="${assetUrl("button-text-us.png")}" alt="" width="38" height="147" decoding="async" />${OPEN_CLOSE_ICON}</button>`,
442
+ `<button class="mm-launcher" type="button" aria-label="Chat now, see if you qualify" aria-expanded="false" draggable="false"><span class="mm-launcher-content" aria-hidden="true"><img class="mm-launcher-chat-icon" src="${assetUrl("launcher-chat.svg")}" alt="" width="48" height="48" decoding="async" /><span class="mm-launcher-copy"><span class="mm-launcher-title">CHAT NOW</span><span class="mm-launcher-subtitle">See if you qualify</span></span></span>${OPEN_CLOSE_ICON}</button>`,
430
443
  '<section class="mm-chat" role="dialog" aria-label="Morgan and Morgan intake chat" inert hidden>',
431
444
  '<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>',
432
445
  "</section>",
@@ -526,7 +539,7 @@
526
539
  const syncLauncherLabel = () => {
527
540
  const isOpen = elements.chatDialog.dataset.state === "open";
528
541
  elements.launcher.setAttribute("aria-expanded", String(isOpen));
529
- elements.launcher.setAttribute("aria-label", isOpen ? "Close intake chat" : "Open intake chat");
542
+ elements.launcher.setAttribute("aria-label", isOpen ? "Close intake chat" : "Chat now, see if you qualify");
530
543
  };
531
544
  const postToChat = (message) => {
532
545
  var _a2;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@morgan-and-morgan/intake-agent",
3
- "version": "1.0.0-alpha.18",
3
+ "version": "1.0.0-alpha.19",
4
4
  "description": "Embeddable chat widget loader.",
5
5
  "license": "UNLICENSED",
6
6
  "files": [