@pocketping/widget 1.12.0 → 1.12.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/dist/index.cjs CHANGED
@@ -218,24 +218,54 @@ function styles(options) {
218
218
  left: 20px;
219
219
  }
220
220
 
221
+ /* Mobile: fullscreen widget to prevent scroll issues */
221
222
  @media (max-width: 480px) {
222
223
  .pp-window {
223
- width: calc(100vw - 20px);
224
- height: auto;
225
- min-height: 300px;
226
- max-height: calc(100vh - 40px);
227
- max-height: calc(100svh - 40px); /* svh = small viewport, excludes keyboard */
228
- bottom: 10px;
229
- right: 10px;
230
- left: 10px;
231
- border-radius: 12px;
224
+ position: fixed !important;
225
+ /* No !important on top/bottom/height - controlled by JS for keyboard handling */
226
+ top: 0;
227
+ left: 0 !important;
228
+ right: 0 !important;
229
+ bottom: auto;
230
+ width: 100vw !important;
231
+ height: 100vh;
232
+ height: 100dvh;
233
+ max-width: 100vw !important;
234
+ max-height: 100vh;
235
+ max-height: 100dvh;
236
+ min-height: 0; /* Allow shrinking for keyboard */
237
+ border-radius: 0 !important;
238
+ overflow: hidden !important;
239
+ touch-action: manipulation; /* Allow scroll and touch, prevent double-tap zoom */
240
+ margin: 0 !important;
241
+ padding: 0 !important;
242
+ box-sizing: border-box !important;
232
243
  }
233
244
 
234
- /* When keyboard is likely open (input focused), reduce height */
235
- .pp-window:has(.pp-input:focus) {
236
- max-height: calc(50vh - 20px);
237
- max-height: calc(50svh - 20px);
238
- bottom: 10px;
245
+ /* Prevent any overflow */
246
+ .pp-window *,
247
+ .pp-window *::before,
248
+ .pp-window *::after {
249
+ max-width: 100% !important;
250
+ box-sizing: border-box !important;
251
+ }
252
+
253
+ /* Ensure messages area scrolls properly */
254
+ .pp-messages {
255
+ max-width: 100vw !important;
256
+ min-height: 0 !important; /* Allow shrinking for scroll */
257
+ overflow-x: hidden !important;
258
+ overflow-y: auto !important;
259
+ touch-action: pan-y !important; /* Enable vertical scrolling */
260
+ -webkit-overflow-scrolling: touch; /* Smooth scrolling on iOS */
261
+ }
262
+
263
+ /* Allow touch on input area for typing */
264
+ .pp-input-form,
265
+ .pp-input,
266
+ .pp-send-btn,
267
+ .pp-attach-btn {
268
+ touch-action: manipulation !important;
239
269
  }
240
270
  }
241
271
 
@@ -246,6 +276,9 @@ function styles(options) {
246
276
  padding: 10px 16px;
247
277
  background: ${resolvedHeaderColor};
248
278
  color: white;
279
+ flex-shrink: 0; /* Never shrink - always visible */
280
+ position: relative;
281
+ z-index: 10; /* Stay above messages during any scroll issues */
249
282
  }
250
283
 
251
284
  .pp-header-info {
@@ -318,7 +351,9 @@ function styles(options) {
318
351
 
319
352
  .pp-messages {
320
353
  flex: 1;
354
+ min-height: 0; /* Critical: allows flex child to shrink and enable scrolling */
321
355
  overflow-y: auto;
356
+ overflow-x: hidden;
322
357
  padding: 16px 12px;
323
358
  display: flex;
324
359
  flex-direction: column;
@@ -330,6 +365,7 @@ function styles(options) {
330
365
  background-image: ${chatBgImage};
331
366
  background-size: ${chatBgSize};
332
367
  background-position: center;
368
+ touch-action: pan-y; /* Only allow vertical scrolling */
333
369
  }
334
370
 
335
371
  .pp-welcome {
@@ -342,6 +378,7 @@ function styles(options) {
342
378
  margin: 12px;
343
379
  border-radius: 8px;
344
380
  box-shadow: 0 1px 0.5px rgba(0, 0, 0, 0.13);
381
+ flex-shrink: 0;
345
382
  }
346
383
 
347
384
  .pp-date-separator {
@@ -349,6 +386,7 @@ function styles(options) {
349
386
  align-items: center;
350
387
  justify-content: center;
351
388
  margin: 12px 0;
389
+ flex-shrink: 0;
352
390
  }
353
391
 
354
392
  .pp-date-separator span {
@@ -368,8 +406,10 @@ function styles(options) {
368
406
  position: relative;
369
407
  display: flex;
370
408
  align-items: stretch;
371
- overflow: visible;
372
- touch-action: pan-y;
409
+ overflow: hidden; /* Prevent horizontal overflow */
410
+ touch-action: pan-y; /* Only vertical scroll */
411
+ max-width: 100%;
412
+ flex-shrink: 0; /* Never shrink - maintain natural size for scrolling */
373
413
  }
374
414
 
375
415
  .pp-swipe-left {
@@ -453,6 +493,7 @@ function styles(options) {
453
493
  display: block; /* Block for proper float behavior */
454
494
  will-change: transform;
455
495
  box-shadow: 0 1px 0.5px rgba(0, 0, 0, 0.13);
496
+ flex-shrink: 0; /* Never shrink - for typing indicator which is direct child */
456
497
  }
457
498
 
458
499
  .pp-message-visitor {
@@ -504,11 +545,14 @@ function styles(options) {
504
545
  }
505
546
 
506
547
  /* Add spacing between different senders */
507
- .pp-message-visitor + .pp-message-operator,
508
- .pp-message-visitor + .pp-message-ai,
509
- .pp-message-operator + .pp-message-visitor,
510
- .pp-message-ai + .pp-message-visitor {
511
- margin-top: 8px;
548
+ .pp-message-swipe-container + .pp-message-swipe-container {
549
+ margin-top: 4px;
550
+ }
551
+
552
+ /* More spacing when sender changes (visitor <-> operator/ai) */
553
+ .pp-swipe-left + .pp-swipe-right,
554
+ .pp-swipe-right + .pp-swipe-left {
555
+ margin-top: 16px;
512
556
  }
513
557
 
514
558
  .pp-message-content {
@@ -629,6 +673,7 @@ function styles(options) {
629
673
  gap: 8px;
630
674
  background: ${resolvedFooterColor};
631
675
  align-items: flex-end;
676
+ flex-shrink: 0; /* Never shrink */
632
677
  }
633
678
 
634
679
  .pp-input {
@@ -701,6 +746,7 @@ function styles(options) {
701
746
  font-size: 10px;
702
747
  color: ${isDark ? "#8696a0" : "#667781"};
703
748
  background: ${resolvedFooterColor};
749
+ flex-shrink: 0; /* Never shrink */
704
750
  }
705
751
 
706
752
  .pp-footer a {
@@ -2051,6 +2097,58 @@ function ChatWidget({ client: client2, config: initialConfig }) {
2051
2097
  setUnreadCount(0);
2052
2098
  }
2053
2099
  }, [isOpen]);
2100
+ (0, import_hooks2.useEffect)(() => {
2101
+ const isMobile = window.innerWidth <= 480;
2102
+ if (isOpen && isMobile) {
2103
+ const scrollY = window.scrollY;
2104
+ const originalStyles = {
2105
+ overflow: document.body.style.overflow,
2106
+ position: document.body.style.position,
2107
+ top: document.body.style.top,
2108
+ left: document.body.style.left,
2109
+ right: document.body.style.right,
2110
+ width: document.body.style.width
2111
+ };
2112
+ document.body.style.overflow = "hidden";
2113
+ document.body.style.position = "fixed";
2114
+ document.body.style.top = `-${scrollY}px`;
2115
+ document.body.style.left = "0";
2116
+ document.body.style.right = "0";
2117
+ document.body.style.width = "100%";
2118
+ return () => {
2119
+ document.body.style.overflow = originalStyles.overflow;
2120
+ document.body.style.position = originalStyles.position;
2121
+ document.body.style.top = originalStyles.top;
2122
+ document.body.style.left = originalStyles.left;
2123
+ document.body.style.right = originalStyles.right;
2124
+ document.body.style.width = originalStyles.width;
2125
+ window.scrollTo(0, scrollY);
2126
+ };
2127
+ }
2128
+ }, [isOpen]);
2129
+ const [viewportStyle, setViewportStyle] = (0, import_hooks2.useState)(null);
2130
+ (0, import_hooks2.useEffect)(() => {
2131
+ const isMobile = window.innerWidth <= 480;
2132
+ if (!isOpen || !isMobile) {
2133
+ setViewportStyle(null);
2134
+ return;
2135
+ }
2136
+ const vv = window.visualViewport;
2137
+ if (!vv) return;
2138
+ const handleViewportChange = () => {
2139
+ setViewportStyle({
2140
+ height: vv.height,
2141
+ top: vv.offsetTop
2142
+ });
2143
+ };
2144
+ handleViewportChange();
2145
+ vv.addEventListener("resize", handleViewportChange);
2146
+ vv.addEventListener("scroll", handleViewportChange);
2147
+ return () => {
2148
+ vv.removeEventListener("resize", handleViewportChange);
2149
+ vv.removeEventListener("scroll", handleViewportChange);
2150
+ };
2151
+ }, [isOpen]);
2054
2152
  (0, import_hooks2.useEffect)(() => {
2055
2153
  if (!isOpen && messages.length > 0) {
2056
2154
  const unread = messages.filter(
@@ -2249,9 +2347,16 @@ function ChatWidget({ client: client2, config: initialConfig }) {
2249
2347
  const touch = e.touches[0];
2250
2348
  const deltaX = touch.clientX - touchStartRef.current.x;
2251
2349
  const deltaY = touch.clientY - touchStartRef.current.y;
2252
- if (Math.abs(deltaY) > Math.abs(deltaX)) return;
2350
+ if (Math.abs(deltaY) > 10 || Math.abs(deltaX) < 15) {
2351
+ if (swipedMessageId === message.id && swipeOffset !== 0) {
2352
+ setSwipeOffset(0);
2353
+ setSwipedMessageId(null);
2354
+ }
2355
+ return;
2356
+ }
2357
+ e.preventDefault();
2253
2358
  if (deltaX < 0) {
2254
- const offset = Math.max(deltaX, -100);
2359
+ const offset = Math.max(deltaX, -80);
2255
2360
  setSwipeOffset(offset);
2256
2361
  setSwipedMessageId(message.id);
2257
2362
  }
@@ -2393,6 +2498,12 @@ function ChatWidget({ client: client2, config: initialConfig }) {
2393
2498
  "div",
2394
2499
  {
2395
2500
  class: `pp-window pp-${position} pp-theme-${theme} ${isDragging ? "pp-dragging" : ""}`,
2501
+ style: viewportStyle ? {
2502
+ height: `${viewportStyle.height}px`,
2503
+ maxHeight: `${viewportStyle.height}px`,
2504
+ top: `${viewportStyle.top}px`,
2505
+ bottom: "auto"
2506
+ } : void 0,
2396
2507
  onDragEnter: handleDragEnter,
2397
2508
  onDragOver: handleDragOver,
2398
2509
  onDragLeave: handleDragLeave,
package/dist/index.js CHANGED
@@ -177,24 +177,54 @@ function styles(options) {
177
177
  left: 20px;
178
178
  }
179
179
 
180
+ /* Mobile: fullscreen widget to prevent scroll issues */
180
181
  @media (max-width: 480px) {
181
182
  .pp-window {
182
- width: calc(100vw - 20px);
183
- height: auto;
184
- min-height: 300px;
185
- max-height: calc(100vh - 40px);
186
- max-height: calc(100svh - 40px); /* svh = small viewport, excludes keyboard */
187
- bottom: 10px;
188
- right: 10px;
189
- left: 10px;
190
- border-radius: 12px;
183
+ position: fixed !important;
184
+ /* No !important on top/bottom/height - controlled by JS for keyboard handling */
185
+ top: 0;
186
+ left: 0 !important;
187
+ right: 0 !important;
188
+ bottom: auto;
189
+ width: 100vw !important;
190
+ height: 100vh;
191
+ height: 100dvh;
192
+ max-width: 100vw !important;
193
+ max-height: 100vh;
194
+ max-height: 100dvh;
195
+ min-height: 0; /* Allow shrinking for keyboard */
196
+ border-radius: 0 !important;
197
+ overflow: hidden !important;
198
+ touch-action: manipulation; /* Allow scroll and touch, prevent double-tap zoom */
199
+ margin: 0 !important;
200
+ padding: 0 !important;
201
+ box-sizing: border-box !important;
191
202
  }
192
203
 
193
- /* When keyboard is likely open (input focused), reduce height */
194
- .pp-window:has(.pp-input:focus) {
195
- max-height: calc(50vh - 20px);
196
- max-height: calc(50svh - 20px);
197
- bottom: 10px;
204
+ /* Prevent any overflow */
205
+ .pp-window *,
206
+ .pp-window *::before,
207
+ .pp-window *::after {
208
+ max-width: 100% !important;
209
+ box-sizing: border-box !important;
210
+ }
211
+
212
+ /* Ensure messages area scrolls properly */
213
+ .pp-messages {
214
+ max-width: 100vw !important;
215
+ min-height: 0 !important; /* Allow shrinking for scroll */
216
+ overflow-x: hidden !important;
217
+ overflow-y: auto !important;
218
+ touch-action: pan-y !important; /* Enable vertical scrolling */
219
+ -webkit-overflow-scrolling: touch; /* Smooth scrolling on iOS */
220
+ }
221
+
222
+ /* Allow touch on input area for typing */
223
+ .pp-input-form,
224
+ .pp-input,
225
+ .pp-send-btn,
226
+ .pp-attach-btn {
227
+ touch-action: manipulation !important;
198
228
  }
199
229
  }
200
230
 
@@ -205,6 +235,9 @@ function styles(options) {
205
235
  padding: 10px 16px;
206
236
  background: ${resolvedHeaderColor};
207
237
  color: white;
238
+ flex-shrink: 0; /* Never shrink - always visible */
239
+ position: relative;
240
+ z-index: 10; /* Stay above messages during any scroll issues */
208
241
  }
209
242
 
210
243
  .pp-header-info {
@@ -277,7 +310,9 @@ function styles(options) {
277
310
 
278
311
  .pp-messages {
279
312
  flex: 1;
313
+ min-height: 0; /* Critical: allows flex child to shrink and enable scrolling */
280
314
  overflow-y: auto;
315
+ overflow-x: hidden;
281
316
  padding: 16px 12px;
282
317
  display: flex;
283
318
  flex-direction: column;
@@ -289,6 +324,7 @@ function styles(options) {
289
324
  background-image: ${chatBgImage};
290
325
  background-size: ${chatBgSize};
291
326
  background-position: center;
327
+ touch-action: pan-y; /* Only allow vertical scrolling */
292
328
  }
293
329
 
294
330
  .pp-welcome {
@@ -301,6 +337,7 @@ function styles(options) {
301
337
  margin: 12px;
302
338
  border-radius: 8px;
303
339
  box-shadow: 0 1px 0.5px rgba(0, 0, 0, 0.13);
340
+ flex-shrink: 0;
304
341
  }
305
342
 
306
343
  .pp-date-separator {
@@ -308,6 +345,7 @@ function styles(options) {
308
345
  align-items: center;
309
346
  justify-content: center;
310
347
  margin: 12px 0;
348
+ flex-shrink: 0;
311
349
  }
312
350
 
313
351
  .pp-date-separator span {
@@ -327,8 +365,10 @@ function styles(options) {
327
365
  position: relative;
328
366
  display: flex;
329
367
  align-items: stretch;
330
- overflow: visible;
331
- touch-action: pan-y;
368
+ overflow: hidden; /* Prevent horizontal overflow */
369
+ touch-action: pan-y; /* Only vertical scroll */
370
+ max-width: 100%;
371
+ flex-shrink: 0; /* Never shrink - maintain natural size for scrolling */
332
372
  }
333
373
 
334
374
  .pp-swipe-left {
@@ -412,6 +452,7 @@ function styles(options) {
412
452
  display: block; /* Block for proper float behavior */
413
453
  will-change: transform;
414
454
  box-shadow: 0 1px 0.5px rgba(0, 0, 0, 0.13);
455
+ flex-shrink: 0; /* Never shrink - for typing indicator which is direct child */
415
456
  }
416
457
 
417
458
  .pp-message-visitor {
@@ -463,11 +504,14 @@ function styles(options) {
463
504
  }
464
505
 
465
506
  /* Add spacing between different senders */
466
- .pp-message-visitor + .pp-message-operator,
467
- .pp-message-visitor + .pp-message-ai,
468
- .pp-message-operator + .pp-message-visitor,
469
- .pp-message-ai + .pp-message-visitor {
470
- margin-top: 8px;
507
+ .pp-message-swipe-container + .pp-message-swipe-container {
508
+ margin-top: 4px;
509
+ }
510
+
511
+ /* More spacing when sender changes (visitor <-> operator/ai) */
512
+ .pp-swipe-left + .pp-swipe-right,
513
+ .pp-swipe-right + .pp-swipe-left {
514
+ margin-top: 16px;
471
515
  }
472
516
 
473
517
  .pp-message-content {
@@ -588,6 +632,7 @@ function styles(options) {
588
632
  gap: 8px;
589
633
  background: ${resolvedFooterColor};
590
634
  align-items: flex-end;
635
+ flex-shrink: 0; /* Never shrink */
591
636
  }
592
637
 
593
638
  .pp-input {
@@ -660,6 +705,7 @@ function styles(options) {
660
705
  font-size: 10px;
661
706
  color: ${isDark ? "#8696a0" : "#667781"};
662
707
  background: ${resolvedFooterColor};
708
+ flex-shrink: 0; /* Never shrink */
663
709
  }
664
710
 
665
711
  .pp-footer a {
@@ -2010,6 +2056,58 @@ function ChatWidget({ client: client2, config: initialConfig }) {
2010
2056
  setUnreadCount(0);
2011
2057
  }
2012
2058
  }, [isOpen]);
2059
+ useEffect2(() => {
2060
+ const isMobile = window.innerWidth <= 480;
2061
+ if (isOpen && isMobile) {
2062
+ const scrollY = window.scrollY;
2063
+ const originalStyles = {
2064
+ overflow: document.body.style.overflow,
2065
+ position: document.body.style.position,
2066
+ top: document.body.style.top,
2067
+ left: document.body.style.left,
2068
+ right: document.body.style.right,
2069
+ width: document.body.style.width
2070
+ };
2071
+ document.body.style.overflow = "hidden";
2072
+ document.body.style.position = "fixed";
2073
+ document.body.style.top = `-${scrollY}px`;
2074
+ document.body.style.left = "0";
2075
+ document.body.style.right = "0";
2076
+ document.body.style.width = "100%";
2077
+ return () => {
2078
+ document.body.style.overflow = originalStyles.overflow;
2079
+ document.body.style.position = originalStyles.position;
2080
+ document.body.style.top = originalStyles.top;
2081
+ document.body.style.left = originalStyles.left;
2082
+ document.body.style.right = originalStyles.right;
2083
+ document.body.style.width = originalStyles.width;
2084
+ window.scrollTo(0, scrollY);
2085
+ };
2086
+ }
2087
+ }, [isOpen]);
2088
+ const [viewportStyle, setViewportStyle] = useState2(null);
2089
+ useEffect2(() => {
2090
+ const isMobile = window.innerWidth <= 480;
2091
+ if (!isOpen || !isMobile) {
2092
+ setViewportStyle(null);
2093
+ return;
2094
+ }
2095
+ const vv = window.visualViewport;
2096
+ if (!vv) return;
2097
+ const handleViewportChange = () => {
2098
+ setViewportStyle({
2099
+ height: vv.height,
2100
+ top: vv.offsetTop
2101
+ });
2102
+ };
2103
+ handleViewportChange();
2104
+ vv.addEventListener("resize", handleViewportChange);
2105
+ vv.addEventListener("scroll", handleViewportChange);
2106
+ return () => {
2107
+ vv.removeEventListener("resize", handleViewportChange);
2108
+ vv.removeEventListener("scroll", handleViewportChange);
2109
+ };
2110
+ }, [isOpen]);
2013
2111
  useEffect2(() => {
2014
2112
  if (!isOpen && messages.length > 0) {
2015
2113
  const unread = messages.filter(
@@ -2208,9 +2306,16 @@ function ChatWidget({ client: client2, config: initialConfig }) {
2208
2306
  const touch = e.touches[0];
2209
2307
  const deltaX = touch.clientX - touchStartRef.current.x;
2210
2308
  const deltaY = touch.clientY - touchStartRef.current.y;
2211
- if (Math.abs(deltaY) > Math.abs(deltaX)) return;
2309
+ if (Math.abs(deltaY) > 10 || Math.abs(deltaX) < 15) {
2310
+ if (swipedMessageId === message.id && swipeOffset !== 0) {
2311
+ setSwipeOffset(0);
2312
+ setSwipedMessageId(null);
2313
+ }
2314
+ return;
2315
+ }
2316
+ e.preventDefault();
2212
2317
  if (deltaX < 0) {
2213
- const offset = Math.max(deltaX, -100);
2318
+ const offset = Math.max(deltaX, -80);
2214
2319
  setSwipeOffset(offset);
2215
2320
  setSwipedMessageId(message.id);
2216
2321
  }
@@ -2352,6 +2457,12 @@ function ChatWidget({ client: client2, config: initialConfig }) {
2352
2457
  "div",
2353
2458
  {
2354
2459
  class: `pp-window pp-${position} pp-theme-${theme} ${isDragging ? "pp-dragging" : ""}`,
2460
+ style: viewportStyle ? {
2461
+ height: `${viewportStyle.height}px`,
2462
+ maxHeight: `${viewportStyle.height}px`,
2463
+ top: `${viewportStyle.top}px`,
2464
+ bottom: "auto"
2465
+ } : void 0,
2355
2466
  onDragEnter: handleDragEnter,
2356
2467
  onDragOver: handleDragOver,
2357
2468
  onDragLeave: handleDragLeave,