@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 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 |
@@ -12,30 +12,16 @@
12
12
  };
13
13
  };
14
14
  const OPEN_STATE_KEY = "mm-intake-widget-open";
15
- const UNREAD_STATE_KEY = "mm-intake-widget-unread";
16
- const readFlag = (key, storage) => {
15
+ const readOpenState = (storage = sessionStorage) => {
17
16
  try {
18
- return storage.getItem(key) === "true";
17
+ return storage.getItem(OPEN_STATE_KEY) === "true";
19
18
  } catch {
20
19
  return false;
21
20
  }
22
21
  };
23
- const writeFlag = (key, value, storage) => {
22
+ const writeOpenState = (isOpen, storage = sessionStorage) => {
24
23
  try {
25
- storage.setItem(key, String(value));
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, so the
64
- // launcher's unread dot can mean something. Payload-free: the dot is a dot,
65
- // and only the chat knows a message arrived while only the host knows whether
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:translateY(10px) scale(.85)}to{opacity:1;transform:none}}",
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
- // The launcher stacks above the chat panel: it is the only close affordance
150
- // (the panel is chrome-free), so the full-screen mobile panel must not cover it.
151
- ".mm-launcher{position:fixed;right:24px;bottom:24px;z-index:2147483001;display:grid;width:64px;height:64px;place-items:center;border:2px solid var(--mm-white);border-radius:999px;outline:none;background:var(--mm-yellow);color:var(--mm-ink);box-shadow:0 10px 28px rgba(17,17,17,.24);cursor:pointer;user-select:none;-webkit-user-select:none;-webkit-user-drag:none;animation:mm-launcher-in .25s ease-out;transition:background-color .15s ease,transform .15s ease,box-shadow .15s ease}",
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{background:var(--mm-yellow-hover);box-shadow:0 12px 32px rgba(17,17,17,.28);transform:translateY(-1px)}",
154
- ".mm-launcher:active{background:var(--mm-yellow-pressed);transform:translateY(0)}",
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-badge{position:absolute;top:-2px;right:-2px;width:16px;height:16px;border:2px solid var(--mm-white);border-radius:999px;background:var(--mm-blue)}",
157
- '.mm-badge::after{content:"";position:absolute;inset:-2px;border-radius:999px;background:var(--mm-blue);animation:mm-ping 2.4s ease-out infinite}',
158
- ".mm-icon{position:absolute;top:50%;left:50%;display:block;width:28px;height:28px;pointer-events:none;transform:translate(-50%,-50%)}",
159
- ".mm-icon-close{display:none}",
160
- '.mm-launcher[aria-expanded="true"] .mm-icon-chat{display:none}',
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
- // The panel wears the chat's header/trust-line tint, not its conversation
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
- // The close affordance rides the same tracked viewport as the panel: iOS
190
- // Safari pans the page when the keyboard opens, and a launcher pinned to the
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">${CHAT_ICON}${OPEN_CLOSE_ICON}<span class="mm-badge" aria-hidden="true" hidden></span></button>`,
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", getLauncherLabel(isOpen, hasUnread));
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
- setHasUnread(false);
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
- setHasUnread(hasUnread);
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": "0.1.0-alpha.1",
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
+ }