@bravophone/webphone 0.1.2 → 0.2.1

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.
Files changed (84) hide show
  1. package/README.md +64 -5
  2. package/dist/bravophone.mjs +419 -302
  3. package/dist/bravophone.umd.js +66 -7
  4. package/host/_locales/pt_BR/messages.json +1430 -0
  5. package/host/allowed-origins.json +8 -0
  6. package/host/css/bravophoneContactDialer.css +385 -0
  7. package/host/css/dark-theme.css +116 -0
  8. package/host/favicon.ico +0 -0
  9. package/host/fonts/Audiowide-Regular.ttf +0 -0
  10. package/host/fonts/Seguiemj.ttf +0 -0
  11. package/host/images/answer-gray.png +0 -0
  12. package/host/images/answer.png +0 -0
  13. package/host/images/auto-answer-off.png +0 -0
  14. package/host/images/auto-answer-on.png +0 -0
  15. package/host/images/avatar.png +0 -0
  16. package/host/images/bravophone-logo.svg +39 -0
  17. package/host/images/bravotech_Bravotech_logo.png +0 -0
  18. package/host/images/circle-green.png +0 -0
  19. package/host/images/circle-orange.png +0 -0
  20. package/host/images/circle-red.png +0 -0
  21. package/host/images/dialer-button-down.png +0 -0
  22. package/host/images/dialer-button.png +0 -0
  23. package/host/images/gateways/activecampaign.png +0 -0
  24. package/host/images/gateways/agendor.png +0 -0
  25. package/host/images/gateways/appfacilita.png +0 -0
  26. package/host/images/gateways/call-in.png +0 -0
  27. package/host/images/gateways/click-to-call.png +0 -0
  28. package/host/images/gateways/clickup.png +0 -0
  29. package/host/images/gateways/exactsales.png +0 -0
  30. package/host/images/gateways/go-high-lvl.png +0 -0
  31. package/host/images/gateways/groner.png +0 -0
  32. package/host/images/gateways/hubspot.png +0 -0
  33. package/host/images/gateways/kommo.png +0 -0
  34. package/host/images/gateways/moskit.png +0 -0
  35. package/host/images/gateways/nectar.png +0 -0
  36. package/host/images/gateways/pipedrive.png +0 -0
  37. package/host/images/gateways/pipefy.png +0 -0
  38. package/host/images/gateways/piperun.png +0 -0
  39. package/host/images/gateways/ploomes.png +0 -0
  40. package/host/images/gateways/rdstation-crm.png +0 -0
  41. package/host/images/gateways/salesforce.png +0 -0
  42. package/host/images/gateways/sharpspring.png +0 -0
  43. package/host/images/gateways/sunhub.png +0 -0
  44. package/host/images/gateways/vendfly.png +0 -0
  45. package/host/images/gateways/zendesk.png +0 -0
  46. package/host/images/gateways/zoho.png +0 -0
  47. package/host/images/hangup.png +0 -0
  48. package/host/images/hold.png +0 -0
  49. package/host/images/icons/logo-128-christmas-celebration.png +0 -0
  50. package/host/images/icons/logo-128.png +0 -0
  51. package/host/images/icons/logo-16-christmas-celebration.png +0 -0
  52. package/host/images/icons/logo-16.png +0 -0
  53. package/host/images/icons/logo-24-christmas-celebration.png +0 -0
  54. package/host/images/icons/logo-24.png +0 -0
  55. package/host/images/icons/logo-32-christmas-celebration.png +0 -0
  56. package/host/images/icons/logo-32.png +0 -0
  57. package/host/images/icons/logo-48-christmas-celebration.png +0 -0
  58. package/host/images/icons/logo-48.png +0 -0
  59. package/host/images/loading.gif +0 -0
  60. package/host/images/logo-bravotech-white.png +0 -0
  61. package/host/images/logo-bravotech.png +0 -0
  62. package/host/images/logo-inline-christmas-celebration.png +0 -0
  63. package/host/images/logo-inline.png +0 -0
  64. package/host/images/mic-off.png +0 -0
  65. package/host/images/mic-on.png +0 -0
  66. package/host/images/play.png +0 -0
  67. package/host/images/transfer.png +0 -0
  68. package/host/index.html +34 -0
  69. package/host/js/bravophone-noise-suppressor.js +418 -0
  70. package/host/js/bravophone-route-selector.js +1099 -0
  71. package/host/js/libwebphone.js +20 -0
  72. package/host/js/noise/LICENSE-web-noise-suppressor.txt +21 -0
  73. package/host/js/noise/rnnoise-worklet.js +13 -0
  74. package/host/js/noise/rnnoise.wasm +0 -0
  75. package/host/js/noise/rnnoise_simd.wasm +0 -0
  76. package/host/mock-webphone.js +195 -0
  77. package/host/mock.html +54 -0
  78. package/host/popup.js +23 -0
  79. package/host/shim/chrome-shim.js +287 -0
  80. package/host/shim/guest-bridge.js +353 -0
  81. package/host/shim/messages.js +13 -0
  82. package/host/styles/theme-fixes.css +98 -0
  83. package/package.json +4 -2
  84. package/types/index.d.ts +30 -2
@@ -1,31 +1,31 @@
1
- const K = 'stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"', be = `<svg viewBox="0 0 24 24" fill="none" ${K} aria-hidden="true">
1
+ const Z = 'stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"', fe = `<svg viewBox="0 0 24 24" fill="none" ${Z} aria-hidden="true">
2
2
  <path class="bp-i-body" d="M15.6 12.8a11 11 0 0 1-4.4-4.4l1-1a1.6 1.6 0 0 0 .3-1.7c-.2-.7-.4-1.4-.5-2.2A1.6 1.6 0 0 0 10.4 2H7.9a1.6 1.6 0 0 0-1.6 1.8 15.8 15.8 0 0 0 2.4 6.9 15.6 15.6 0 0 0 4.8 4.8 15.8 15.8 0 0 0 6.9 2.4 1.6 1.6 0 0 0 1.7-1.6v-2.5a1.6 1.6 0 0 0-1.4-1.6c-.8-.1-1.5-.3-2.2-.5a1.6 1.6 0 0 0-1.7.4z"/>
3
3
  <path class="bp-i-wave bp-i-wave-1" d="M14.5 6.2a4 4 0 0 1 3.3 3.3"/>
4
4
  <path class="bp-i-wave bp-i-wave-2" d="M14.1 2.6a7.6 7.6 0 0 1 7.3 7.3"/>
5
- </svg>`, ue = `<svg viewBox="0 0 24 24" fill="none" ${K} aria-hidden="true">
5
+ </svg>`, xe = `<svg viewBox="0 0 24 24" fill="none" ${Z} aria-hidden="true">
6
6
  <path class="bp-i-bar bp-i-bar-1" d="M4 10v4"/>
7
7
  <path class="bp-i-bar bp-i-bar-2" d="M8.7 6.5v11"/>
8
8
  <path class="bp-i-bar bp-i-bar-3" d="M12 3.5v17"/>
9
9
  <path class="bp-i-bar bp-i-bar-4" d="M15.3 6.5v11"/>
10
10
  <path class="bp-i-bar bp-i-bar-5" d="M20 10v4"/>
11
- </svg>`, ge = `<svg viewBox="0 0 24 24" fill="none" ${K} aria-hidden="true">
11
+ </svg>`, we = `<svg viewBox="0 0 24 24" fill="none" ${Z} aria-hidden="true">
12
12
  <path class="bp-i-body" d="M4 13v-1a8 8 0 0 1 16 0v1"/>
13
13
  <path class="bp-i-body" d="M20 14.5v2a3.5 3.5 0 0 1-3.5 3.5H13"/>
14
14
  <rect class="bp-i-cup" x="1.6" y="12.6" width="4.4" height="6.4" rx="1.8"/>
15
15
  <rect class="bp-i-cup" x="18" y="12.6" width="4.4" height="6.4" rx="1.8"/>
16
- </svg>`, me = `<svg viewBox="0 0 24 24" fill="none" ${K} aria-hidden="true">
16
+ </svg>`, ye = `<svg viewBox="0 0 24 24" fill="none" ${Z} aria-hidden="true">
17
17
  <path class="bp-i-body" d="M21 11.5a8.4 8.4 0 0 1-9 8.4 9 9 0 0 1-2.9-.5L3 21.5l1.5-4.6A8.4 8.4 0 0 1 12 3.1a8.4 8.4 0 0 1 9 8.4z"/>
18
18
  <path class="bp-i-hand" d="M14.6 14.4a6.5 6.5 0 0 1-3.2-3.2l.7-.7a1 1 0 0 0 .2-1.1 6 6 0 0 1-.3-1.2 1 1 0 0 0-1-.8H9.6a1 1 0 0 0-1 1.1 9.6 9.6 0 0 0 4.8 7.2 1 1 0 0 0 1.4-.9v-1.2a1 1 0 0 0-.8-1z"/>
19
- </svg>`, fe = `<svg viewBox="0 0 10 16" width="10" height="16" fill="currentColor" aria-hidden="true">
19
+ </svg>`, ve = `<svg viewBox="0 0 10 16" width="10" height="16" fill="currentColor" aria-hidden="true">
20
20
  <circle cx="2.6" cy="2.6" r="1.35"/><circle cx="7.4" cy="2.6" r="1.35"/>
21
21
  <circle cx="2.6" cy="8" r="1.35"/><circle cx="7.4" cy="8" r="1.35"/>
22
22
  <circle cx="2.6" cy="13.4" r="1.35"/><circle cx="7.4" cy="13.4" r="1.35"/>
23
- </svg>`, j = {
24
- "phone-waves": be,
25
- waveform: ue,
26
- headset: ge,
27
- "chat-phone": me
28
- }, Q = "phone-waves", xe = `
23
+ </svg>`, J = {
24
+ "phone-waves": fe,
25
+ waveform: xe,
26
+ headset: we,
27
+ "chat-phone": ye
28
+ }, ae = "phone-waves", ke = `
29
29
  .bp-launcher-icon svg { width: 100%; height: 100%; display: block; overflow: visible; }
30
30
 
31
31
  /* Ponto de status no canto do ícone — verde registrado, cinza sem linha. */
@@ -95,7 +95,7 @@ const K = 'stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-
95
95
  .bp-i-wave, .bp-i-body, .bp-i-hand, .bp-i-bar { animation: none !important; }
96
96
  .bp-launcher-icon { transition: none; }
97
97
  }
98
- `, we = `
98
+ `, Me = `
99
99
  :host { all: initial; }
100
100
  * { box-sizing: border-box; }
101
101
 
@@ -227,6 +227,21 @@ const K = 'stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-
227
227
  /* Uma janela docada nao se redimensiona pelas bordas coladas na viewport. */
228
228
  .bp-root.bp-docked { border-radius: 0; }
229
229
 
230
+ /* ---- destaque: "a janela esta aqui" ----
231
+ Disparado ao clicar na aba com o webphone ja aberto. Um halo que cresce e
232
+ some, no lugar de um shake: em interface, tremer significa erro ou acao
233
+ negada (senha errada), e aqui nada deu errado. */
234
+ @keyframes bp-attention {
235
+ 0% { box-shadow: 0 12px 40px rgba(0,0,0,.45), 0 0 0 0 rgba(124,108,245,.55); }
236
+ 55% { box-shadow: 0 12px 40px rgba(0,0,0,.45), 0 0 0 12px rgba(124,108,245,0); }
237
+ 100% { box-shadow: 0 12px 40px rgba(0,0,0,.45), 0 0 0 0 rgba(124,108,245,0); }
238
+ }
239
+ .bp-root.bp-attention { animation: bp-attention .85s ease-out 2; }
240
+
241
+ @media (prefers-reduced-motion: reduce) {
242
+ .bp-root.bp-attention { animation: none; outline: 2px solid #7c6cf5; outline-offset: 2px; }
243
+ }
244
+
230
245
  /* ---- previa de encaixe (docking) ----
231
246
  Fantasma que mostra onde a janela vai parar antes de soltar. */
232
247
  .bp-preview {
@@ -244,7 +259,9 @@ const K = 'stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-
244
259
  .bp-launcher {
245
260
  position: fixed;
246
261
  top: 50%;
247
- z-index: 2147482999;
262
+ /* Acima da janela (2147483000): a aba nunca some, e uma janela docada na
263
+ mesma borda a esconderia. */
264
+ z-index: 2147483001;
248
265
  display: flex;
249
266
  align-items: center;
250
267
  gap: 0;
@@ -341,25 +358,25 @@ const K = 'stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-
341
358
  .bp-launcher[data-badge]:not([data-badge=""]) { animation: none; }
342
359
  }
343
360
 
344
- ${xe}
345
- `, pe = "bravophone:widget:geometry", q = 28, J = 32;
346
- function ye(e) {
361
+ ${ke}
362
+ `, ge = "bravophone:widget:geometry", V = 28, X = 32;
363
+ function Le(e) {
347
364
  try {
348
- const a = localStorage.getItem(pe);
365
+ const a = localStorage.getItem(ge);
349
366
  if (!a) return { ...e };
350
- const i = JSON.parse(a);
351
- return i.dock ? { ...e, ...i, ...F(i.dock, i) } : { ...e, ...i };
367
+ const n = JSON.parse(a);
368
+ return n.dock ? { ...e, ...n, ...U(n.dock, n) } : { ...e, ...n };
352
369
  } catch (a) {
353
370
  return { ...e };
354
371
  }
355
372
  }
356
- function X(e) {
373
+ function K(e) {
357
374
  try {
358
- localStorage.setItem(pe, JSON.stringify(e));
375
+ localStorage.setItem(ge, JSON.stringify(e));
359
376
  } catch (a) {
360
377
  }
361
378
  }
362
- function se(e) {
379
+ function he(e) {
363
380
  return {
364
381
  minWidth: e.minWidth,
365
382
  minHeight: e.minHeight,
@@ -370,107 +387,107 @@ function se(e) {
370
387
  };
371
388
  }
372
389
  function R(e) {
373
- const a = Math.max(0, window.innerWidth - e.width), i = Math.max(0, window.innerHeight - 40);
390
+ const a = Math.max(0, window.innerWidth - e.width), n = Math.max(0, window.innerHeight - 40);
374
391
  return {
375
392
  ...e,
376
393
  x: Math.min(Math.max(0, e.x), a),
377
- y: Math.min(Math.max(0, e.y), i)
394
+ y: Math.min(Math.max(0, e.y), n)
378
395
  };
379
396
  }
380
- function F(e, a) {
381
- const i = window.innerWidth, r = window.innerHeight, o = Math.round(i / 2), s = Math.round(r / 2), u = Math.min(a.width, i);
397
+ function U(e, a) {
398
+ const n = window.innerWidth, o = window.innerHeight, i = Math.round(n / 2), d = Math.round(o / 2), u = Math.min(a.width, n);
382
399
  switch (e) {
383
400
  case "left":
384
- return { x: 0, y: 0, width: u, height: r };
401
+ return { x: 0, y: 0, width: u, height: o };
385
402
  case "right":
386
- return { x: i - u, y: 0, width: u, height: r };
403
+ return { x: n - u, y: 0, width: u, height: o };
387
404
  case "left-half":
388
- return { x: 0, y: 0, width: o, height: r };
405
+ return { x: 0, y: 0, width: i, height: o };
389
406
  case "right-half":
390
- return { x: i - o, y: 0, width: o, height: r };
407
+ return { x: n - i, y: 0, width: i, height: o };
391
408
  case "top":
392
- return { x: a.x, y: 0, width: u, height: s };
409
+ return { x: a.x, y: 0, width: u, height: d };
393
410
  case "bottom":
394
- return { x: a.x, y: r - s, width: u, height: s };
411
+ return { x: a.x, y: o - d, width: u, height: d };
395
412
  case "top-half":
396
- return { x: 0, y: 0, width: i, height: s };
413
+ return { x: 0, y: 0, width: n, height: d };
397
414
  case "bottom-half":
398
- return { x: 0, y: r - s, width: i, height: s };
415
+ return { x: 0, y: o - d, width: n, height: d };
399
416
  case "max":
400
- return { x: 0, y: 0, width: i, height: r };
417
+ return { x: 0, y: 0, width: n, height: o };
401
418
  default:
402
419
  return { x: a.x, y: a.y, width: a.width, height: a.height };
403
420
  }
404
421
  }
405
- function ve(e, a, i) {
406
- const r = window.innerWidth, o = window.innerHeight, s = e <= q, u = e >= r - q, f = a <= q, t = a >= o - q;
407
- return (f || t) && s ? "left-half" : (f || t) && u ? "right-half" : f ? i || "max" : t ? "bottom-half" : s ? "left" : u ? "right" : null;
422
+ function ze(e, a, n) {
423
+ const o = window.innerWidth, i = window.innerHeight, d = e <= V, u = e >= o - V, f = a <= V, t = a >= i - V;
424
+ return (f || t) && d ? "left-half" : (f || t) && u ? "right-half" : f ? n || "max" : t ? "bottom-half" : d ? "left" : u ? "right" : null;
408
425
  }
409
- function ke({ root: e, handle: a, handles: i, preview: r, geometry: o, limits: s, topDock: u, onChange: f }) {
410
- let t = { ...o }, g = null, p = "", d = null, h = null, w = null, y = null;
426
+ function Se({ root: e, handle: a, handles: n, preview: o, geometry: i, limits: d, topDock: u, onChange: f }) {
427
+ let t = { ...i }, g = null, p = "", c = null, h = null, x = null, w = null;
411
428
  const z = () => {
412
429
  e.style.left = `${t.x}px`, e.style.top = `${t.y}px`, e.style.width = `${t.width}px`, e.style.height = `${t.height}px`, e.classList.toggle("bp-docked", !!t.dock), f == null || f(t);
413
- }, C = (n) => {
414
- if (r) {
415
- if (!n) {
416
- r.hidden = !0;
430
+ }, C = (r) => {
431
+ if (o) {
432
+ if (!r) {
433
+ o.hidden = !0;
417
434
  return;
418
435
  }
419
- r.hidden = !1, r.style.left = `${n.x}px`, r.style.top = `${n.y}px`, r.style.width = `${n.width}px`, r.style.height = `${n.height}px`;
436
+ o.hidden = !1, o.style.left = `${r.x}px`, o.style.top = `${r.y}px`, o.style.width = `${r.width}px`, o.style.height = `${r.height}px`;
420
437
  }
421
- }, D = (n, b) => {
422
- const l = se(s);
423
- let { x: S, y: m, width: k, height: H } = d;
424
- p.includes("e") && (k = d.width + n), p.includes("w") && (k = d.width - n), p.includes("s") && (H = d.height + b), p.includes("n") && (H = d.height - b), k = Math.min(l.maxWidth, Math.max(l.minWidth, k)), H = Math.min(l.maxHeight, Math.max(l.minHeight, H)), p.includes("w") && (S = d.x + (d.width - k)), p.includes("n") && (m = d.y + (d.height - H)), p.includes("e") && Math.abs(S + k - window.innerWidth) <= J && (k = window.innerWidth - S), p.includes("w") && Math.abs(S) <= J && (k += S, S = 0), p.includes("s") && Math.abs(m + H - window.innerHeight) <= J && (H = window.innerHeight - m), p.includes("n") && Math.abs(m) <= J && (H += m, m = 0), t = { ...t, x: S, y: m, width: k, height: H, dock: null }, z();
425
- }, $ = (n, b, l, S) => {
438
+ }, $ = (r, b) => {
439
+ const l = he(d);
440
+ let { x: v, y: S, width: E, height: H } = c;
441
+ p.includes("e") && (E = c.width + r), p.includes("w") && (E = c.width - r), p.includes("s") && (H = c.height + b), p.includes("n") && (H = c.height - b), E = Math.min(l.maxWidth, Math.max(l.minWidth, E)), H = Math.min(l.maxHeight, Math.max(l.minHeight, H)), p.includes("w") && (v = c.x + (c.width - E)), p.includes("n") && (S = c.y + (c.height - H)), p.includes("e") && Math.abs(v + E - window.innerWidth) <= X && (E = window.innerWidth - v), p.includes("w") && Math.abs(v) <= X && (E += v, v = 0), p.includes("s") && Math.abs(S + H - window.innerHeight) <= X && (H = window.innerHeight - S), p.includes("n") && Math.abs(S) <= X && (H += S, S = 0), t = { ...t, x: v, y: S, width: E, height: H, dock: null }, z();
442
+ }, j = (r, b, l, v) => {
426
443
  if (t.dock) {
427
- const m = y || { width: s.width, height: s.height }, k = h.x / Math.max(1, t.width);
428
- t = { ...t, ...m, dock: null }, h = { x: Math.round(m.width * k), y: Math.min(h.y, 32) }, d = {
429
- ...d,
444
+ const S = w || { width: d.width, height: d.height }, E = h.x / Math.max(1, t.width);
445
+ t = { ...t, ...S, dock: null }, h = { x: Math.round(S.width * E), y: Math.min(h.y, 32) }, c = {
446
+ ...c,
430
447
  x: l - h.x,
431
- y: S - h.y,
432
- px: d.px + n,
433
- py: d.py + b
434
- }, n = 0, b = 0;
448
+ y: v - h.y,
449
+ px: c.px + r,
450
+ py: c.py + b
451
+ }, r = 0, b = 0;
435
452
  }
436
- t = R({ ...t, x: d.x + n, y: d.y + b }), z(), w = ve(l, S, u), C(w ? F(w, t) : null);
437
- }, O = () => {
438
- w && (y = y || { width: t.width, height: t.height }, t = { ...t, ...F(w, t), dock: w }, z());
439
- }, P = (n, b) => (l) => {
440
- l.button === 0 && (n === "drag" && l.target.closest(".bp-btn") || (g = n, p = b || "", d = { px: l.clientX, py: l.clientY, ...t }, h = { x: l.clientX - t.x, y: l.clientY - t.y }, t.dock || (y = { width: t.width, height: t.height }), e.classList.add(n === "drag" ? "bp-dragging" : "bp-resizing"), l.currentTarget.setPointerCapture(l.pointerId), l.preventDefault()));
441
- }, U = (n) => {
442
- if (!g || !d) return;
443
- const b = n.clientX - d.px, l = n.clientY - d.py;
444
- g === "drag" ? $(b, l, n.clientX, n.clientY) : D(b, l);
445
- }, B = (n) => {
453
+ t = R({ ...t, x: c.x + r, y: c.y + b }), z(), x = ze(l, v, u), C(x ? U(x, t) : null);
454
+ }, _ = () => {
455
+ x && (w = w || { width: t.width, height: t.height }, t = { ...t, ...U(x, t), dock: x }, z());
456
+ }, F = (r, b) => (l) => {
457
+ l.button === 0 && (r === "drag" && l.target.closest(".bp-btn") || (g = r, p = b || "", c = { px: l.clientX, py: l.clientY, ...t }, h = { x: l.clientX - t.x, y: l.clientY - t.y }, t.dock || (w = { width: t.width, height: t.height }), e.classList.add(r === "drag" ? "bp-dragging" : "bp-resizing"), l.currentTarget.setPointerCapture(l.pointerId), l.preventDefault()));
458
+ }, D = (r) => {
459
+ if (!g || !c) return;
460
+ const b = r.clientX - c.px, l = r.clientY - c.py;
461
+ g === "drag" ? j(b, l, r.clientX, r.clientY) : $(b, l);
462
+ }, A = (r) => {
446
463
  if (g) {
447
- e.classList.remove("bp-dragging", "bp-resizing"), C(null), g === "drag" && O(), g = null, p = "", d = null, w = null;
464
+ e.classList.remove("bp-dragging", "bp-resizing"), C(null), g === "drag" && _(), g = null, p = "", c = null, x = null;
448
465
  try {
449
- n.currentTarget.releasePointerCapture(n.pointerId);
466
+ r.currentTarget.releasePointerCapture(r.pointerId);
450
467
  } catch (b) {
451
468
  }
452
- X(t);
469
+ K(t);
453
470
  }
454
471
  };
455
- a.addEventListener("pointerdown", P("drag")), a.addEventListener("pointermove", U), a.addEventListener("pointerup", B), a.addEventListener("pointercancel", B), (i || []).forEach(({ el: n, dir: b }) => {
456
- n.addEventListener("pointerdown", P("resize", b)), n.addEventListener("pointermove", U), n.addEventListener("pointerup", B), n.addEventListener("pointercancel", B);
472
+ a.addEventListener("pointerdown", F("drag")), a.addEventListener("pointermove", D), a.addEventListener("pointerup", A), a.addEventListener("pointercancel", A), (n || []).forEach(({ el: r, dir: b }) => {
473
+ r.addEventListener("pointerdown", F("resize", b)), r.addEventListener("pointermove", D), r.addEventListener("pointerup", A), r.addEventListener("pointercancel", A);
457
474
  });
458
- const V = () => {
459
- t = t.dock ? { ...t, ...F(t.dock, t) } : R(t), z();
475
+ const N = () => {
476
+ t = t.dock ? { ...t, ...U(t.dock, t) } : R(t), z();
460
477
  };
461
- window.addEventListener("resize", V);
478
+ window.addEventListener("resize", N);
462
479
  const G = {
463
- start(n) {
480
+ start(r) {
464
481
  var b, l;
465
- g = "drag", d = { px: n.x, py: n.y, ...t }, h = { x: (b = n.cx) != null ? b : t.width / 2, y: (l = n.cy) != null ? l : 20 }, t.dock || (y = { width: t.width, height: t.height }), e.classList.add("bp-dragging");
482
+ g = "drag", c = { px: r.x, py: r.y, ...t }, h = { x: (b = r.cx) != null ? b : t.width / 2, y: (l = r.cy) != null ? l : 20 }, t.dock || (w = { width: t.width, height: t.height }), e.classList.add("bp-dragging");
466
483
  },
467
- move(n) {
468
- if (g !== "drag" || !d) return;
469
- const b = n.x - d.px, l = n.y - d.py;
470
- $(b, l, d.x + b + h.x, d.y + l + h.y);
484
+ move(r) {
485
+ if (g !== "drag" || !c) return;
486
+ const b = r.x - c.px, l = r.y - c.py;
487
+ j(b, l, c.x + b + h.x, c.y + l + h.y);
471
488
  },
472
489
  end() {
473
- g === "drag" && (e.classList.remove("bp-dragging"), C(null), O(), g = null, d = null, w = null, X(t));
490
+ g === "drag" && (e.classList.remove("bp-dragging"), C(null), _(), g = null, c = null, x = null, K(t));
474
491
  }
475
492
  };
476
493
  return z(), {
@@ -478,136 +495,186 @@ function ke({ root: e, handle: a, handles: i, preview: r, geometry: o, limits: s
478
495
  get geometry() {
479
496
  return { ...t };
480
497
  },
481
- set(n) {
482
- const b = se(s), l = { ...t, ...n, dock: null };
483
- l.width = Math.min(b.maxWidth, Math.max(b.minWidth, l.width)), l.height = Math.min(b.maxHeight, Math.max(b.minHeight, l.height)), t = R(l), z(), X(t);
498
+ set(r) {
499
+ const b = he(d), l = { ...t, ...r, dock: null };
500
+ l.width = Math.min(b.maxWidth, Math.max(b.minWidth, l.width)), l.height = Math.min(b.maxHeight, Math.max(b.minHeight, l.height)), t = R(l), z(), K(t);
484
501
  },
485
502
  /** 'left' | 'right' | 'left-half' | 'right-half' | 'max' | 'float' */
486
- dock(n) {
487
- if (!n || n === "float") {
488
- const b = y || { width: s.width, height: s.height };
503
+ dock(r) {
504
+ if (!r || r === "float") {
505
+ const b = w || { width: d.width, height: d.height };
489
506
  t = R({ ...t, ...b, dock: null });
490
507
  } else
491
- t.dock || (y = { width: t.width, height: t.height }), t = { ...t, ...F(n, t), dock: n };
492
- z(), X(t);
508
+ t.dock || (w = { width: t.width, height: t.height }), t = { ...t, ...U(r, t), dock: r };
509
+ z(), K(t);
493
510
  },
494
511
  destroy() {
495
- window.removeEventListener("resize", V);
512
+ window.removeEventListener("resize", N);
496
513
  }
497
514
  };
498
515
  }
499
- const de = "bravophone/v1";
500
- function Me({ frame: e, origin: a, onEvent: i }) {
501
- const r = /* @__PURE__ */ new Map();
502
- let o = 0, s = !1;
516
+ const be = "bravophone/v1";
517
+ function Ee({ frame: e, origin: a, onEvent: n }) {
518
+ const o = /* @__PURE__ */ new Map();
519
+ let i = 0, d = !1;
503
520
  const u = [], f = (g) => {
504
- var d;
521
+ var c;
505
522
  if (g.origin !== a || g.source !== e.contentWindow) return;
506
523
  const p = g.data;
507
- if (!(!p || p.protocol !== de)) {
524
+ if (!(!p || p.protocol !== be)) {
508
525
  if (p.type === "ready") {
509
- for (s = !0; u.length; ) u.shift()();
510
- i == null || i("ready", (d = p.payload) != null ? d : {});
526
+ for (d = !0; u.length; ) u.shift()();
527
+ n == null || n("ready", (c = p.payload) != null ? c : {});
511
528
  return;
512
529
  }
513
530
  if (p.type === "reply") {
514
- const h = r.get(p.id);
531
+ const h = o.get(p.id);
515
532
  if (!h) return;
516
- r.delete(p.id), clearTimeout(h.timer), p.error ? h.reject(new Error(p.error)) : h.resolve(p.payload);
533
+ o.delete(p.id), clearTimeout(h.timer), p.error ? h.reject(new Error(p.error)) : h.resolve(p.payload);
517
534
  return;
518
535
  }
519
- p.type === "event" && (i == null || i(p.name, p.payload));
536
+ p.type === "event" && (n == null || n(p.name, p.payload));
520
537
  }
521
538
  };
522
539
  window.addEventListener("message", f);
523
- function t(g, p, { timeout: d = 15e3 } = {}) {
524
- return new Promise((h, w) => {
525
- const y = `${Date.now()}-${++o}`, z = () => {
526
- var D;
540
+ function t(g, p, { timeout: c = 15e3 } = {}) {
541
+ return new Promise((h, x) => {
542
+ const w = `${Date.now()}-${++i}`, z = () => {
543
+ var $;
527
544
  const C = setTimeout(() => {
528
- r.delete(y), w(new Error(`Bravophone: timeout no comando "${g}"`));
529
- }, d);
530
- r.set(y, { resolve: h, reject: w, timer: C }), (D = e.contentWindow) == null || D.postMessage(
531
- { protocol: de, type: "command", id: y, command: g, payload: p },
545
+ o.delete(w), x(new Error(`Bravophone: timeout no comando "${g}"`));
546
+ }, c);
547
+ o.set(w, { resolve: h, reject: x, timer: C }), ($ = e.contentWindow) == null || $.postMessage(
548
+ { protocol: be, type: "command", id: w, command: g, payload: p },
532
549
  a
533
550
  );
534
551
  };
535
- s ? z() : u.push(z);
552
+ d ? z() : u.push(z);
536
553
  });
537
554
  }
538
555
  return {
539
556
  call: t,
540
557
  get ready() {
541
- return s;
558
+ return d;
542
559
  },
543
560
  destroy() {
544
- window.removeEventListener("message", f), r.forEach(({ reject: g, timer: p }) => {
561
+ window.removeEventListener("message", f), o.forEach(({ reject: g, timer: p }) => {
545
562
  clearTimeout(p), g(new Error("Bravophone: widget destruído"));
546
- }), r.clear();
563
+ }), o.clear();
547
564
  }
548
565
  };
549
566
  }
550
- const he = "bravophone:launcher", ze = 4, ee = 8;
551
- function Le(e) {
567
+ const me = "bravophone:launcher", He = 4, ie = 8;
568
+ function Te(e) {
552
569
  try {
553
- const a = localStorage.getItem(he);
570
+ const a = localStorage.getItem(me);
554
571
  return a ? { ...e, ...JSON.parse(a) } : { ...e };
555
572
  } catch (a) {
556
573
  return { ...e };
557
574
  }
558
575
  }
559
- function te(e) {
576
+ function ne(e) {
560
577
  try {
561
- localStorage.setItem(he, JSON.stringify(e));
578
+ localStorage.setItem(me, JSON.stringify(e));
562
579
  } catch (a) {
563
580
  }
564
581
  }
565
- function Y(e, a) {
566
- const i = Math.max(ee, window.innerHeight - a - ee);
567
- return Math.min(Math.max(ee, e), i);
582
+ function q(e, a) {
583
+ const n = Math.max(ie, window.innerHeight - a - ie);
584
+ return Math.min(Math.max(ie, e), n);
568
585
  }
569
- function Ee({ el: e, side: a, y: i, onOpen: r }) {
570
- let o = { side: a, y: Y(i, e.offsetHeight || 48) }, s = null, u = !1;
586
+ function $e({ el: e, side: a, y: n, onOpen: o }) {
587
+ let i = { side: a, y: q(n, e.offsetHeight || 48) }, d = null, u = !1;
571
588
  const f = () => {
572
- e.dataset.side = o.side, e.style.top = `${o.y}px`, e.style.right = o.side === "right" ? "0px" : "auto", e.style.left = o.side === "left" ? "0px" : "auto";
589
+ e.dataset.side = i.side, e.style.top = `${i.y}px`, e.style.right = i.side === "right" ? "0px" : "auto", e.style.left = i.side === "left" ? "0px" : "auto";
573
590
  }, t = (h) => {
574
- h.button === 0 && (s = { py: h.clientY, y: o.y }, u = !1, e.setPointerCapture(h.pointerId));
591
+ h.button === 0 && (d = { py: h.clientY, y: i.y }, u = !1, e.setPointerCapture(h.pointerId));
575
592
  }, g = (h) => {
576
- if (!s) return;
577
- const w = h.clientY - s.py;
578
- !u && Math.abs(w) < ze || (u || (u = !0, e.classList.add("bp-launcher-dragging")), o.y = Y(s.y + w, e.offsetHeight), f());
593
+ if (!d) return;
594
+ const x = h.clientY - d.py;
595
+ !u && Math.abs(x) < He || (u || (u = !0, e.classList.add("bp-launcher-dragging")), i.y = q(d.y + x, e.offsetHeight), f());
579
596
  }, p = (h) => {
580
- if (!s) return;
581
- const w = u;
582
- s = null, u = !1, e.classList.remove("bp-launcher-dragging");
597
+ if (!d) return;
598
+ const x = u;
599
+ d = null, u = !1, e.classList.remove("bp-launcher-dragging");
583
600
  try {
584
601
  e.releasePointerCapture(h.pointerId);
585
- } catch (y) {
602
+ } catch (w) {
586
603
  }
587
- w ? te(o) : r == null || r();
604
+ x ? ne(i) : o == null || o();
588
605
  };
589
606
  e.addEventListener("pointerdown", t), e.addEventListener("pointermove", g), e.addEventListener("pointerup", p), e.addEventListener("pointercancel", p), e.addEventListener("keydown", (h) => {
590
- (h.key === "Enter" || h.key === " ") && (h.preventDefault(), r == null || r());
607
+ (h.key === "Enter" || h.key === " ") && (h.preventDefault(), o == null || o());
591
608
  });
592
- const d = () => {
593
- o.y = Y(o.y, e.offsetHeight), f();
609
+ const c = () => {
610
+ i.y = q(i.y, e.offsetHeight), f();
594
611
  };
595
- return window.addEventListener("resize", d), f(), {
612
+ return window.addEventListener("resize", c), f(), {
596
613
  get state() {
597
- return { ...o };
614
+ return { ...i };
598
615
  },
599
616
  setSide(h) {
600
- o.side = h, f(), te(o);
617
+ i.side = h, f(), ne(i);
601
618
  },
602
619
  moveTo(h) {
603
- o.y = Y(h, e.offsetHeight), f(), te(o);
620
+ i.y = q(h, e.offsetHeight), f(), ne(i);
604
621
  },
605
622
  destroy() {
606
- window.removeEventListener("resize", d);
623
+ window.removeEventListener("resize", c);
607
624
  }
608
625
  };
609
626
  }
610
- const ce = {
627
+ const Ie = "https://cdn.jsdelivr.net/npm";
628
+ function Oe(e, a = "@bravophone/webphone") {
629
+ return `${Ie}/${a}@${e}/host/`;
630
+ }
631
+ function We({ version: e, parentOrigin: a, token: n, base: o }) {
632
+ const i = o || Oe(e), d = JSON.stringify({ parentOrigin: a, token: n || null }).replace(/</g, "\\u003c");
633
+ return `<!doctype html>
634
+ <html lang="pt-BR">
635
+ <head>
636
+ <meta charset="UTF-8">
637
+ <meta name="viewport" content="width=device-width,initial-scale=1">
638
+ <title>Webphone BRAVOPHONE</title>
639
+ <!-- CRÍTICO no modo srcdoc. O bundle referencia as imagens por caminho
640
+ RELATIVO (src="images/answer.png"), fora do public_path. Sem <base>,
641
+ elas resolvem contra a página do integrador — o documento herda o
642
+ baseURI do pai — e somem todas: logo, atender, desligar, mudo, hold,
643
+ transferir. Com <base>, resolvem contra o CDN. -->
644
+ <base href="${i}">
645
+ <link rel="stylesheet" href="${i}css/dark-theme.css">
646
+ <link rel="stylesheet" href="${i}styles/theme-fixes.css">
647
+ <style>
648
+ html, body { margin: 0; height: 100%; background: #10131c; overflow: hidden; }
649
+ #app { height: 100%; }
650
+ </style>
651
+ <script>
652
+ (function () {
653
+ var cfg = ${d};
654
+ // O guest-bridge lê daqui: em srcdoc não há query string para carregar a
655
+ // origem do pai.
656
+ window.__bpParentOrigin = cfg.parentOrigin;
657
+ if (cfg.token) {
658
+ // Grava onde o bundle procura, antes dele avaliar, para a sessão já subir
659
+ // autenticada em vez de piscar a tela de login.
660
+ try { localStorage.setItem('bp.local.vxToken', JSON.stringify(cfg.token)); } catch (e) {}
661
+ }
662
+ })();
663
+ <\/script>
664
+ <script src="${i}shim/messages.js"><\/script>
665
+ <script src="${i}shim/chrome-shim.js"><\/script>
666
+ <script src="${i}js/libwebphone.js"><\/script>
667
+ <script src="${i}js/bravophone-route-selector.js"><\/script>
668
+ <script defer src="${i}popup.js"><\/script>
669
+ <script defer src="${i}shim/guest-bridge.js"><\/script>
670
+ </head>
671
+ <body>
672
+ <noscript><strong>O webphone precisa de JavaScript habilitado.</strong></noscript>
673
+ <div id="app"></div>
674
+ </body>
675
+ </html>`;
676
+ }
677
+ const ue = {
611
678
  // 380x640 é a geometria da janela nativa da extensão — o layout do
612
679
  // webphone é calibrado para ela, então é o ponto de partida aqui também.
613
680
  width: 380,
@@ -620,196 +687,231 @@ const ce = {
620
687
  maxHeight: 1400,
621
688
  margin: 24
622
689
  };
623
- function v(e, a = {}, i = []) {
624
- const r = document.createElement(e);
625
- for (const [o, s] of Object.entries(a))
626
- o === "class" ? r.className = s : o === "text" ? r.textContent = s : s != null && r.setAttribute(o, s);
627
- return i.forEach((o) => r.appendChild(o)), r;
690
+ function y(e, a = {}, n = []) {
691
+ const o = document.createElement(e);
692
+ for (const [i, d] of Object.entries(a))
693
+ i === "class" ? o.className = d : i === "text" ? o.textContent = d : d != null && o.setAttribute(i, d);
694
+ return n.forEach((i) => o.appendChild(i)), o;
628
695
  }
629
- function Se(e) {
696
+ function Ce(e) {
630
697
  const {
631
698
  hostUrl: a,
632
- token: i,
633
- position: r = "bottom-right",
634
- open: o = !1,
635
- launcher: s = !0,
699
+ token: n,
700
+ position: o = "bottom-right",
701
+ open: i = !1,
702
+ launcher: d = !0,
636
703
  title: u = "BRAVOPHONE",
637
- // 'none' preserva 100% da UI do webphone: sem barra de titulo, o arraste
638
- // vem de dentro do iframe. 'bar' adiciona a barra com titulo e controles.
639
- frame: f = "none",
704
+ // 'bar' por padrão: título, indicador de estado e controles visíveis.
705
+ // 'none' preserva 100% da UI do webphone sem barra, o arraste vem de
706
+ // dentro do iframe e só um botão de fechar aparece no hover.
707
+ frame: f = "bar",
640
708
  // O que arrastar até a borda de cima faz. 'max' é o gesto universal;
641
709
  // troque para 'top-half' se preferir as metades verticais no topo.
642
710
  dockTop: t = "max",
643
711
  // Lado da viewport em que a aba de abertura fica colada.
644
712
  launcherSide: g = "right",
645
713
  // Desenho da aba: 'phone-waves' | 'waveform' | 'headset' | 'chat-phone'
646
- launcherIcon: p = Q,
647
- emit: d
648
- } = e, h = new URL(a), w = h.origin, y = v("div", { "data-bravophone": "root" });
649
- y.style.cssText = "all:initial;position:static";
650
- const z = y.attachShadow({ mode: "open" });
651
- z.appendChild(v("style", { text: we }));
652
- const C = (() => {
653
- var oe;
654
- const { width: c, height: E, margin: I } = ce, N = window.innerWidth - c - I, ie = window.innerHeight - E - I, re = {
655
- "bottom-right": { x: N, y: ie },
656
- "bottom-left": { x: I, y: ie },
657
- "top-right": { x: N, y: I },
658
- "top-left": { x: I, y: I }
714
+ launcherIcon: p = ae,
715
+ // 'hosted' — o iframe navega para hostUrl (padrão)
716
+ // 'srcdoc' o iframe roda na origem do site e busca o conteúdo no CDN
717
+ mode: c = "hosted",
718
+ // Base dos assets no modo srcdoc. Padrão: o CDN travado nesta versão.
719
+ // Serve para desenvolvimento (localhost) e para quem espelhar os assets.
720
+ hostBase: h,
721
+ version: x,
722
+ emit: w
723
+ } = e, z = c === "srcdoc", C = z ? window.location.origin : new URL(a).origin, $ = y("div", { "data-bravophone": "root" });
724
+ $.style.cssText = "all:initial;position:static";
725
+ const j = $.attachShadow({ mode: "open" });
726
+ j.appendChild(y("style", { text: Me }));
727
+ const _ = (() => {
728
+ var le;
729
+ const { width: s, height: M, margin: W } = ue, P = window.innerWidth - s - W, ce = window.innerHeight - M - W, pe = {
730
+ "bottom-right": { x: P, y: ce },
731
+ "bottom-left": { x: W, y: ce },
732
+ "top-right": { x: P, y: W },
733
+ "top-left": { x: W, y: W }
659
734
  };
660
- return R({ ...(oe = re[r]) != null ? oe : re["bottom-right"], width: c, height: E });
661
- })(), D = R(ye(C)), $ = v("span", { class: "bp-status", "data-state": "connecting" }), O = v("button", { class: "bp-btn bp-btn-min", title: "Minimizar", text: "—" }), P = v("button", { class: "bp-btn bp-btn-close", title: "Fechar", text: "×" }), U = v("div", { class: "bp-header" }, [
662
- $,
663
- v("span", { class: "bp-title", text: u }),
664
- O,
665
- P
666
- ]), B = v("iframe", {
735
+ return R({ ...(le = pe[o]) != null ? le : pe["bottom-right"], width: s, height: M });
736
+ })(), F = R(Le(_)), D = y("span", { class: "bp-status", "data-state": "connecting" }), A = y("button", { class: "bp-btn bp-btn-min", title: "Minimizar", text: "—" }), N = y("button", { class: "bp-btn bp-btn-close", title: "Fechar", text: "×" }), G = y("div", { class: "bp-header" }, [
737
+ D,
738
+ y("span", { class: "bp-title", text: u }),
739
+ A,
740
+ N
741
+ ]), r = y("iframe", {
667
742
  class: "bp-frame",
668
- src: He(h, { token: i, embed: "1", parent: location.origin }),
743
+ // allow= é obrigatório no modo hospedado (cross-origin). Em srcdoc o
744
+ // microfone já é herdado do topo, mas declarar não custa e documenta.
669
745
  allow: "microphone; autoplay; clipboard-write; speaker-selection",
670
746
  title: "Webphone BRAVOPHONE"
671
- }), G = ["n", "s", "w", "e", "nw", "ne", "sw", "se"].map((c) => ({
672
- el: v("div", { class: `bp-h bp-h-${c}` }),
673
- dir: c
674
- })), n = v("div", { class: "bp-preview" });
675
- n.hidden = !0;
676
- const b = v("button", { class: "bp-btn bp-btn-close", title: "Fechar", text: "×" }), l = v("div", { class: "bp-overlay" }, [b]), S = v("div", { class: "bp-body" }, [B, l]), m = v("div", { class: "bp-root" }, [U, S, ...G.map((c) => c.el)]);
677
- f !== "bar" && m.classList.add("bp-chromeless"), m.hidden = !o;
678
- const k = v("span", { class: "bp-launcher-icon" });
679
- k.innerHTML = j[p] || j[Q];
680
- const H = v("span", { class: "bp-launcher-grip", "aria-hidden": "true" });
681
- H.innerHTML = fe;
682
- const L = v("div", {
747
+ });
748
+ z ? r.setAttribute(
749
+ "srcdoc",
750
+ We({ version: x, parentOrigin: C, token: n, base: h })
751
+ ) : r.setAttribute(
752
+ "src",
753
+ Ae(new URL(a), { token: n, embed: "1", parent: location.origin })
754
+ );
755
+ const l = ["n", "s", "w", "e", "nw", "ne", "sw", "se"].map((s) => ({
756
+ el: y("div", { class: `bp-h bp-h-${s}` }),
757
+ dir: s
758
+ })), v = y("div", { class: "bp-preview" });
759
+ v.hidden = !0;
760
+ const S = y("button", { class: "bp-btn bp-btn-close", title: "Fechar", text: "×" }), E = y("div", { class: "bp-overlay" }, [S]), H = y("div", { class: "bp-body" }, [r, E]), k = y("div", { class: "bp-root" }, [G, H, ...l.map((s) => s.el)]);
761
+ f !== "bar" && k.classList.add("bp-chromeless"), k.hidden = !i;
762
+ const Q = y("span", { class: "bp-launcher-icon" });
763
+ Q.innerHTML = J[p] || J[ae];
764
+ const oe = y("span", { class: "bp-launcher-grip", "aria-hidden": "true" });
765
+ oe.innerHTML = ve;
766
+ const T = y("div", {
683
767
  class: "bp-launcher",
684
768
  role: "button",
685
769
  tabindex: "0",
686
770
  title: "Abrir webphone",
687
771
  "aria-label": "Abrir webphone"
688
772
  }, [
689
- H,
690
- k,
691
- v("span", { class: "bp-badge" })
773
+ oe,
774
+ Q,
775
+ y("span", { class: "bp-badge" })
692
776
  ]);
693
- L.dataset.state = "connecting", L.hidden = !s || o, z.append(n, m, L), document.body.appendChild(y);
694
- const ae = Le({
777
+ T.dataset.state = "connecting", T.hidden = !d, j.append(v, k, T), document.body.appendChild($);
778
+ const se = Te({
695
779
  side: g,
696
780
  y: Math.round(window.innerHeight / 2 - 24)
697
- }), ne = Ee({
698
- el: L,
699
- side: ae.side,
700
- y: Y(ae.y, 48),
701
- onOpen: () => T.show()
702
- }), W = ke({
703
- root: m,
704
- handle: U,
705
- handles: G,
706
- preview: n,
707
- geometry: D,
708
- limits: ce,
781
+ }), de = $e({
782
+ el: T,
783
+ side: se.side,
784
+ y: q(se.y, 48),
785
+ // A aba nunca some, então o clique tem dois papéis: abrir quando fechada,
786
+ // e localizar quando já aberta.
787
+ onOpen: () => O.reveal()
788
+ }), I = Se({
789
+ root: k,
790
+ handle: G,
791
+ handles: l,
792
+ preview: v,
793
+ geometry: F,
794
+ limits: ue,
709
795
  topDock: t,
710
- onChange: (c) => d("resize", { width: c.width, height: c.height, dock: c.dock || null })
711
- }), Z = Me({
712
- frame: B,
713
- origin: w,
714
- onEvent: (c, E) => {
715
- var I;
716
- if (c === "ready" && ($.dataset.state = "ready", L.dataset.state = "ready", i && Z.call("auth", { token: i }).catch(() => {
717
- })), c === "state") {
718
- const N = (I = E == null ? void 0 : E.state) != null ? I : "ready";
719
- $.dataset.state = N, L.dataset.state = N;
796
+ onChange: (s) => w("resize", { width: s.width, height: s.height, dock: s.dock || null })
797
+ }), ee = Ee({
798
+ frame: r,
799
+ origin: C,
800
+ onEvent: (s, M) => {
801
+ var W;
802
+ if (s === "ready" && (D.dataset.state = "ready", T.dataset.state = "ready", n && ee.call("auth", { token: n }).catch(() => {
803
+ })), s === "state") {
804
+ const P = (W = M == null ? void 0 : M.state) != null ? W : "ready";
805
+ D.dataset.state = P, T.dataset.state = P;
720
806
  }
721
- if (c === "call:incoming" && (T.show(), L.dataset.badge = "1", L.dataset.state = "ringing"), c === "call:answered" && (L.dataset.state = "incall"), (c === "call:ended" || c === "call:failed") && (delete L.dataset.badge, L.dataset.state = "ready"), c === "drag:start") {
722
- W.external.start(E);
807
+ if (s === "call:incoming" && (O.show(), T.dataset.badge = "1", T.dataset.state = "ringing"), s === "call:answered" && (T.dataset.state = "incall"), s === "call:ended" && (delete T.dataset.badge, T.dataset.state = "ready"), s === "drag:start") {
808
+ I.external.start(M);
723
809
  return;
724
810
  }
725
- if (c === "drag:move") {
726
- W.external.move(E);
811
+ if (s === "drag:move") {
812
+ I.external.move(M);
727
813
  return;
728
814
  }
729
- if (c === "drag:end") {
730
- W.external.end();
815
+ if (s === "drag:end") {
816
+ I.external.end();
731
817
  return;
732
818
  }
733
- d(c, E);
819
+ w(s, M);
734
820
  }
735
821
  });
736
- let _ = !1;
737
- const T = {
738
- el: y,
739
- bridge: Z,
822
+ let Y = !1, te = null;
823
+ const O = {
824
+ el: $,
825
+ bridge: ee,
740
826
  show() {
741
- m.hidden = !1, L.hidden = !0, d("open");
827
+ k.hidden = !1, w("open");
742
828
  },
743
829
  hide() {
744
- m.hidden = !0, s && (L.hidden = !1), d("close");
830
+ k.hidden = !0, w("close");
745
831
  },
746
832
  toggle() {
747
- m.hidden ? T.show() : T.hide();
833
+ k.hidden ? O.show() : O.hide();
834
+ },
835
+ /**
836
+ * Traz a janela para a atenção do usuário.
837
+ * Fechada: abre. Aberta e fora de vista: traz de volta. Aberta e
838
+ * visível: um halo curto, para o olho encontrá-la.
839
+ */
840
+ reveal() {
841
+ if (k.hidden) {
842
+ O.show();
843
+ return;
844
+ }
845
+ const s = I.geometry;
846
+ (s.x + s.width < 40 || s.x > window.innerWidth - 40 || s.y > window.innerHeight - 40) && I.set({
847
+ x: Math.round((window.innerWidth - s.width) / 2),
848
+ y: Math.round((window.innerHeight - s.height) / 2)
849
+ }), k.classList.remove("bp-attention"), k.offsetWidth, k.classList.add("bp-attention"), clearTimeout(te), te = setTimeout(() => k.classList.remove("bp-attention"), 1800), w("reveal");
748
850
  },
749
851
  get isOpen() {
750
- return !m.hidden;
852
+ return !k.hidden;
751
853
  },
752
- minimize(c) {
854
+ minimize(s) {
753
855
  if (f !== "bar") {
754
- T.hide();
856
+ O.hide();
755
857
  return;
756
858
  }
757
- _ = c != null ? c : !_, m.classList.toggle("bp-minimized", _), O.textContent = _ ? "▢" : "—";
859
+ Y = s != null ? s : !Y, k.classList.toggle("bp-minimized", Y), A.textContent = Y ? "▢" : "—";
758
860
  },
759
- move(c, E) {
760
- W.set({ x: c, y: E });
861
+ move(s, M) {
862
+ I.set({ x: s, y: M });
761
863
  },
762
- resize(c, E) {
763
- W.set({ width: c, height: E });
864
+ resize(s, M) {
865
+ I.set({ width: s, height: M });
764
866
  },
765
- dock(c) {
766
- W.dock(c);
867
+ dock(s) {
868
+ I.dock(s);
767
869
  },
768
- setLauncherSide(c) {
769
- ne.setSide(c);
870
+ setLauncherSide(s) {
871
+ de.setSide(s);
770
872
  },
771
- setLauncherIcon(c) {
772
- k.innerHTML = j[c] || j[Q];
873
+ setLauncherIcon(s) {
874
+ Q.innerHTML = J[s] || J[ae];
773
875
  },
774
876
  get geometry() {
775
- return W.geometry;
877
+ return I.geometry;
776
878
  },
777
879
  destroy() {
778
- Z.destroy(), W.destroy(), ne.destroy(), n.remove(), y.remove();
880
+ clearTimeout(te), ee.destroy(), I.destroy(), de.destroy(), v.remove(), $.remove();
779
881
  }
780
882
  };
781
- return P.addEventListener("click", () => T.hide()), O.addEventListener("click", () => T.minimize()), b.addEventListener("click", () => T.hide()), T;
782
- }
783
- function He(e, a) {
784
- const i = new URL(e.href);
785
- for (const [r, o] of Object.entries(a))
786
- o != null && o !== "" && i.searchParams.set(r, o);
787
- return a.token && (i.searchParams.delete("token"), i.hash = `token=${encodeURIComponent(a.token)}`), i.href;
788
- }
789
- const Te = "https://webphone.bravophone.com/embed/";
790
- let M = null;
791
- const A = /* @__PURE__ */ new Map();
792
- function Ie(e, a) {
793
- var i, r;
794
- (i = A.get(e)) == null || i.forEach((o) => {
883
+ return N.addEventListener("click", () => O.hide()), A.addEventListener("click", () => O.minimize()), S.addEventListener("click", () => O.hide()), O;
884
+ }
885
+ function Ae(e, a) {
886
+ const n = new URL(e.href);
887
+ for (const [o, i] of Object.entries(a))
888
+ i != null && i !== "" && n.searchParams.set(o, i);
889
+ return a.token && (n.searchParams.delete("token"), n.hash = `token=${encodeURIComponent(a.token)}`), n.href;
890
+ }
891
+ const Be = "https://webphone.bravophone.com/embed/";
892
+ let L = null;
893
+ const B = /* @__PURE__ */ new Map();
894
+ function De(e, a) {
895
+ var n, o;
896
+ (n = B.get(e)) == null || n.forEach((i) => {
795
897
  try {
796
- o(a);
797
- } catch (s) {
798
- console.error("[Bravophone] listener falhou:", s);
898
+ i(a);
899
+ } catch (d) {
900
+ console.error("[Bravophone] listener falhou:", d);
799
901
  }
800
- }), (r = A.get("*")) == null || r.forEach((o) => {
902
+ }), (o = B.get("*")) == null || o.forEach((i) => {
801
903
  try {
802
- o({ event: e, payload: a });
803
- } catch (s) {
804
- console.error("[Bravophone] listener falhou:", s);
904
+ i({ event: e, payload: a });
905
+ } catch (d) {
906
+ console.error("[Bravophone] listener falhou:", d);
805
907
  }
806
908
  });
807
909
  }
808
- function x() {
809
- if (!M) throw new Error("Bravophone: chame Bravophone.init() antes.");
810
- return M;
910
+ function m() {
911
+ if (!L) throw new Error("Bravophone: chame Bravophone.init() antes.");
912
+ return L;
811
913
  }
812
- const le = {
914
+ const re = {
813
915
  /**
814
916
  * Monta o webphone na página.
815
917
  * @param {object} opts
@@ -817,102 +919,117 @@ const le = {
817
919
  * @param {string} [opts.token] Token de sessão do usuário (SSO do integrador).
818
920
  * @param {'bottom-right'|'bottom-left'|'top-right'|'top-left'} [opts.position]
819
921
  * @param {boolean} [opts.open] Abrir já visível (padrão: false, só o launcher).
820
- * @param {boolean} [opts.launcher] Exibir o botão flutuante (padrão: true).
922
+ * @param {boolean} [opts.launcher] Exibir a aba de abertura (padrão: true).
923
+ * @param {'hosted'|'srcdoc'} [opts.mode]
924
+ * 'hosted' (padrão): o iframe navega para `hostUrl`. Uma origem fixa para
925
+ * o CORS dos backends, mas é um iframe de terceiro.
926
+ * 'srcdoc': o iframe roda na origem do próprio site e busca o webphone no
927
+ * CDN. Some o iframe de terceiro — em troca, a origem do integrador
928
+ * precisa estar na allowlist de CORS dos backends.
821
929
  */
822
930
  init(e = {}) {
823
- if (M) return M;
931
+ if (L) return L;
824
932
  if (typeof window == "undefined" || !document.body)
825
933
  throw new Error("Bravophone: init() precisa rodar no browser, após o <body> existir.");
826
- return location.protocol !== "https:" && location.hostname !== "localhost" && console.warn("[Bravophone] Contexto inseguro: o microfone exige HTTPS ou localhost."), M = Se({ hostUrl: Te, ...e, emit: Ie }), M;
934
+ return location.protocol !== "https:" && location.hostname !== "localhost" && console.warn("[Bravophone] Contexto inseguro: o microfone exige HTTPS ou localhost."), L = Ce({
935
+ hostUrl: Be,
936
+ version: re.version,
937
+ ...e,
938
+ emit: De
939
+ }), L;
827
940
  },
828
941
  // ---- Controle da janela ----
829
942
  show() {
830
- x().show();
943
+ m().show();
831
944
  },
832
945
  hide() {
833
- x().hide();
946
+ m().hide();
834
947
  },
835
948
  toggle() {
836
- x().toggle();
949
+ m().toggle();
950
+ },
951
+ /** Abre a janela; se já estiver aberta, traz para a vista e destaca. */
952
+ reveal() {
953
+ m().reveal();
837
954
  },
838
955
  minimize(e) {
839
- x().minimize(e);
956
+ m().minimize(e);
840
957
  },
841
958
  move(e, a) {
842
- x().move(e, a);
959
+ m().move(e, a);
843
960
  },
844
961
  resize(e, a) {
845
- x().resize(e, a);
962
+ m().resize(e, a);
846
963
  },
847
964
  /** 'left' | 'right' | 'left-half' | 'right-half' | 'max' | 'float' */
848
965
  dock(e) {
849
- x().dock(e);
966
+ m().dock(e);
850
967
  },
851
968
  /** Move a aba de abertura para o outro lado da viewport. */
852
969
  setLauncherSide(e) {
853
- x().setLauncherSide(e);
970
+ m().setLauncherSide(e);
854
971
  },
855
972
  /** 'phone-waves' | 'waveform' | 'headset' | 'chat-phone' */
856
973
  setLauncherIcon(e) {
857
- x().setLauncherIcon(e);
974
+ m().setLauncherIcon(e);
858
975
  },
859
976
  get isOpen() {
860
- return M ? M.isOpen : !1;
977
+ return L ? L.isOpen : !1;
861
978
  },
862
979
  get geometry() {
863
- return M ? M.geometry : null;
980
+ return L ? L.geometry : null;
864
981
  },
865
982
  // ---- Telefonia ----
866
983
  /** Disca um número. Aceita formato livre; a normalização é a mesma da extensão. */
867
984
  call(e, a) {
868
- return x().bridge.call("call", { number: e, meta: a });
985
+ return m().bridge.call("call", { number: e, meta: a });
869
986
  },
870
987
  hangup() {
871
- return x().bridge.call("hangup");
988
+ return m().bridge.call("hangup");
872
989
  },
873
990
  answer() {
874
- return x().bridge.call("answer");
991
+ return m().bridge.call("answer");
875
992
  },
876
993
  /** Alterna o mudo — o bundle só expõe toggle, não aceita estado alvo. */
877
994
  mute() {
878
- return x().bridge.call("mute");
995
+ return m().bridge.call("mute");
879
996
  },
880
997
  /** Alterna a espera. Também toggle. */
881
998
  hold() {
882
- return x().bridge.call("hold");
999
+ return m().bridge.call("hold");
883
1000
  },
884
1001
  sendDTMF(e) {
885
- return x().bridge.call("dtmf", { tone: e });
1002
+ return m().bridge.call("dtmf", { tone: e });
886
1003
  },
887
1004
  transfer(e) {
888
- return x().bridge.call("transfer", { to: e });
1005
+ return m().bridge.call("transfer", { to: e });
889
1006
  },
890
1007
  getStatus() {
891
- return x().bridge.call("status");
1008
+ return m().bridge.call("status");
892
1009
  },
893
1010
  setAuth(e) {
894
- return x().bridge.call("auth", { token: e });
1011
+ return m().bridge.call("auth", { token: e });
895
1012
  },
896
1013
  logout() {
897
- return x().bridge.call("logout");
1014
+ return m().bridge.call("logout");
898
1015
  },
899
1016
  // ---- Eventos ----
900
1017
  /** Eventos: ready, state, call:dialing, call:incoming, call:answered,
901
1018
  * call:ended, call:failed, resize, open, close, error. */
902
1019
  on(e, a) {
903
- return A.has(e) || A.set(e, /* @__PURE__ */ new Set()), A.get(e).add(a), () => le.off(e, a);
1020
+ return B.has(e) || B.set(e, /* @__PURE__ */ new Set()), B.get(e).add(a), () => re.off(e, a);
904
1021
  },
905
1022
  off(e, a) {
906
- var i;
907
- (i = A.get(e)) == null || i.delete(a);
1023
+ var n;
1024
+ (n = B.get(e)) == null || n.delete(a);
908
1025
  },
909
1026
  destroy() {
910
- M == null || M.destroy(), M = null, A.clear();
1027
+ L == null || L.destroy(), L = null, B.clear();
911
1028
  },
912
1029
  // Substituída em build time pelo valor do package.json (ver vite.config.js).
913
- version: "0.1.2"
1030
+ version: "0.2.1"
914
1031
  };
915
- typeof window != "undefined" && (window.Bravophone = le);
1032
+ typeof window != "undefined" && (window.Bravophone = re);
916
1033
  export {
917
- le as default
1034
+ re as default
918
1035
  };