@bootdesk/chat-widget-bridge 0.3.3 → 0.3.5

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
@@ -129,6 +129,8 @@ Via a `<script>` tag:
129
129
  ### Behavior
130
130
 
131
131
  - Exposes `window.ChatSDK.initialize()` to create a floating chat button, overlay, and iframe
132
+ - Exposes `window.ChatSDK.destroy()` to remove all DOM elements and event listeners
133
+ - Waits for `DOMContentLoaded` before creating elements if script runs in `<head>`
132
134
  - On click, opens a panel with the iframe (slide + fade animation)
133
135
  - On small screens (<800px) the iframe goes fullscreen and the overlay is hidden
134
136
  - Reads `localStorage` key `chat-theme` and passes it to the iframe via `chat-config`
@@ -147,6 +149,18 @@ Via a `<script>` tag:
147
149
  | `buttonStyle` | `object` | Default button styles | CSS overrides for the button |
148
150
  | `overlayStyle` | `object` | Default overlay styles | CSS overrides for the overlay |
149
151
 
152
+ ### Cleanup
153
+
154
+ Call `ChatSDK.destroy()` to remove all DOM elements (button, iframe, overlay, style) and event listeners:
155
+
156
+ ```js
157
+ // Module import
158
+ import "@bootdesk/chat-widget-bridge/embed-chat";
159
+ ChatSDK.initialize({ iframeSrc: "/chat" });
160
+ // later...
161
+ ChatSDK.destroy();
162
+ ```
163
+
150
164
  ## License
151
165
 
152
166
  MIT
@@ -41,8 +41,10 @@
41
41
  button: null,
42
42
  iframe: null,
43
43
  overlay: null,
44
+ styleEl: null,
44
45
  isOpen: false,
45
- originalViewport: void 0
46
+ originalViewport: void 0,
47
+ initialized: false
46
48
  };
47
49
  function mergeStyles(base, overrides) {
48
50
  var result = {};
@@ -119,15 +121,16 @@
119
121
  } catch {
120
122
  }
121
123
  state.iframe.contentWindow.postMessage(
122
- { type: "chat-config", title: opts.title, placeholder: opts.placeholder, theme: { mode: savedTheme } },
124
+ {
125
+ type: "chat-config",
126
+ title: opts.title,
127
+ placeholder: opts.placeholder,
128
+ theme: { mode: savedTheme }
129
+ },
123
130
  "*"
124
131
  );
125
132
  });
126
133
  }
127
- function close() {
128
- if (!state.isOpen) return;
129
- toggle();
130
- }
131
134
  function toggle() {
132
135
  state.isOpen = !state.isOpen;
133
136
  var open = state.isOpen;
@@ -150,7 +153,7 @@
150
153
  console.log("[Embed Chat] Message:", data.text);
151
154
  }
152
155
  if (data.type === "chat-close") {
153
- close();
156
+ toggle();
154
157
  }
155
158
  if (data.type === "chat-viewport-config") {
156
159
  var meta = document.querySelector('meta[name="viewport"]');
@@ -167,7 +170,18 @@
167
170
  }
168
171
  }
169
172
  }
170
- function initialize(opts) {
173
+ function destroy() {
174
+ if (!state.initialized) return;
175
+ if (state.button && state.button.parentNode) state.button.parentNode.removeChild(state.button);
176
+ if (state.iframe && state.iframe.parentNode) state.iframe.parentNode.removeChild(state.iframe);
177
+ if (state.overlay && state.overlay.parentNode)
178
+ state.overlay.parentNode.removeChild(state.overlay);
179
+ if (state.styleEl && state.styleEl.parentNode)
180
+ state.styleEl.parentNode.removeChild(state.styleEl);
181
+ window.removeEventListener("message", handleMessage);
182
+ state.initialized = false;
183
+ }
184
+ function _initialize(opts) {
171
185
  if (document.querySelector("[data-embed-chat-btn]")) return;
172
186
  state.opts = {};
173
187
  for (var key in DEFAULTS) {
@@ -185,11 +199,22 @@
185
199
  var style = document.createElement("style");
186
200
  style.textContent = "@media (max-width: 799px) { [data-embed-chat-iframe] { width: 100dvw !important; height: 100dvh !important; bottom: 0 !important; right: 0 !important; max-width: none !important; max-height: none !important; border-radius: 0 !important; } [data-embed-chat-overlay] { display: none !important; } }";
187
201
  document.head.appendChild(style);
202
+ state.styleEl = style;
188
203
  createOverlay();
189
204
  createIframe();
190
205
  createButton();
191
206
  window.addEventListener("message", handleMessage);
207
+ state.initialized = true;
208
+ }
209
+ function initialize(opts) {
210
+ if (document.readyState === "loading") {
211
+ document.addEventListener("DOMContentLoaded", function() {
212
+ _initialize(opts);
213
+ });
214
+ } else {
215
+ _initialize(opts);
216
+ }
192
217
  }
193
- window.ChatSDK = { initialize };
218
+ window.ChatSDK = { initialize, destroy };
194
219
  })();
195
220
  //# sourceMappingURL=embed-chat.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/embed-chat.js"],"sourcesContent":["(function () {\n \"use strict\";\n\n var DEFAULTS = {\n iframeSrc: \"/chat-iframe\",\n title: \"Chat\",\n placeholder: \"Type a message...\",\n buttonInnerHtml:\n '<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"/></svg>',\n buttonStyle: {\n position: \"fixed\",\n bottom: \"24px\",\n right: \"24px\",\n width: \"56px\",\n height: \"56px\",\n borderRadius: \"50%\",\n border: \"none\",\n background: \"var(--chat-primary, #6366f1)\",\n color: \"#fff\",\n cursor: \"pointer\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n boxShadow: \"0 4px 16px rgba(0,0,0,0.2)\",\n zIndex: \"2147483646\",\n transition: \"transform 0.2s, opacity 0.2s\",\n },\n overlayStyle: {\n position: \"fixed\",\n inset: \"0\",\n background: \"rgba(0,0,0,0.3)\",\n zIndex: \"2147483646\",\n opacity: \"0\",\n transition: \"opacity 0.2s\",\n pointerEvents: \"none\",\n },\n };\n\n var state = {\n opts: null,\n button: null,\n iframe: null,\n overlay: null,\n isOpen: false,\n originalViewport: undefined,\n };\n\n function mergeStyles(base, overrides) {\n var result = {};\n for (var key in base) result[key] = base[key];\n if (overrides) {\n for (var k in overrides) result[k] = overrides[k];\n }\n return result;\n }\n\n function createButton() {\n var opts = state.opts;\n state.button = document.createElement(\"button\");\n state.button.setAttribute(\"data-embed-chat-btn\", \"\");\n state.button.setAttribute(\"aria-label\", \"Open chat\");\n state.button.setAttribute(\"aria-expanded\", \"false\");\n state.button.innerHTML = opts.buttonInnerHtml;\n Object.assign(state.button.style, mergeStyles(DEFAULTS.buttonStyle, opts.buttonStyle));\n state.button.addEventListener(\"mouseenter\", function () {\n state.button.style.transform = \"scale(1.05)\";\n });\n state.button.addEventListener(\"mouseleave\", function () {\n state.button.style.transform = \"\";\n });\n state.button.addEventListener(\"click\", toggle);\n state.button.addEventListener(\"keydown\", function (e) {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n toggle();\n }\n });\n document.body.appendChild(state.button);\n }\n\n function createOverlay() {\n var opts = state.opts;\n state.overlay = document.createElement(\"div\");\n state.overlay.setAttribute(\"data-embed-chat-overlay\", \"\");\n Object.assign(state.overlay.style, mergeStyles(DEFAULTS.overlayStyle, opts.overlayStyle));\n state.overlay.addEventListener(\"click\", toggle);\n document.body.appendChild(state.overlay);\n }\n\n function createIframe() {\n var opts = state.opts;\n state.iframe = document.createElement(\"iframe\");\n state.iframe.setAttribute(\"data-embed-chat-iframe\", \"\");\n state.iframe.setAttribute(\"title\", \"Chat Widget\");\n state.iframe.setAttribute(\"role\", \"dialog\");\n state.iframe.setAttribute(\"aria-modal\", \"true\");\n state.iframe.setAttribute(\"allow\", \"clipboard-write; microphone\");\n state.iframe.src = opts.iframeSrc;\n Object.assign(state.iframe.style, {\n position: \"fixed\",\n bottom: \"96px\",\n right: \"24px\",\n width: \"420px\",\n height: \"600px\",\n maxWidth: \"calc(100dvw - 48px)\",\n maxHeight: \"calc(100dvh - 120px)\",\n border: \"none\",\n borderRadius: \"16px\",\n boxShadow: \"0 8px 32px rgba(0,0,0,0.15)\",\n zIndex: \"2147483647\",\n opacity: \"0\",\n transform: \"translateY(16px) scale(0.96)\",\n transition: \"opacity 0.2s, transform 0.25s\",\n pointerEvents: \"none\",\n background: \"#fff\",\n });\n document.body.appendChild(state.iframe);\n\n state.iframe.addEventListener(\"load\", function () {\n var savedTheme = \"auto\";\n try {\n var stored = localStorage.getItem(\"chat-theme\");\n if (stored === \"light\" || stored === \"dark\" || stored === \"auto\") savedTheme = stored;\n } catch { /* unavailable */ }\n state.iframe.contentWindow.postMessage(\n { type: \"chat-config\", title: opts.title, placeholder: opts.placeholder, theme: { mode: savedTheme } },\n \"*\",\n );\n });\n }\n\n function close() {\n if (!state.isOpen) return;\n toggle();\n }\n\n function toggle() {\n state.isOpen = !state.isOpen;\n var open = state.isOpen;\n\n state.button.setAttribute(\"aria-expanded\", String(open));\n state.iframe.style.opacity = open ? \"1\" : \"0\";\n state.iframe.style.transform = open ? \"translateY(0) scale(1)\" : \"translateY(16px) scale(0.96)\";\n state.iframe.style.pointerEvents = open ? \"auto\" : \"none\";\n\n state.overlay.style.opacity = open ? \"1\" : \"0\";\n state.overlay.style.pointerEvents = open ? \"auto\" : \"none\";\n\n state.button.style.transform = open ? \"scale(0)\" : \"\";\n state.button.style.opacity = open ? \"0\" : \"1\";\n state.button.style.pointerEvents = open ? \"none\" : \"auto\";\n\n document.body.style.overflow = open ? \"hidden\" : \"\";\n\n if (open) state.iframe.focus();\n }\n\n function handleMessage(event) {\n if (!state.iframe || event.source !== state.iframe.contentWindow) return;\n var data = event.data || {};\n if (data.type === \"chat-message\") {\n console.log(\"[Embed Chat] Message:\", data.text);\n }\n if (data.type === \"chat-close\") {\n close();\n }\n if (data.type === \"chat-viewport-config\") {\n var meta = document.querySelector('meta[name=\"viewport\"]');\n if (!meta) return;\n var current = meta.getAttribute(\"content\") || \"\";\n if (data.content) {\n if (state.originalViewport === undefined) state.originalViewport = current;\n if (!current.includes(data.content)) {\n meta.setAttribute(\"content\", current + (current ? \", \" : \"\") + data.content);\n }\n } else {\n meta.setAttribute(\"content\", state.originalViewport ?? current);\n state.originalViewport = undefined;\n }\n }\n }\n\n function initialize(opts) {\n if (document.querySelector(\"[data-embed-chat-btn]\")) return;\n\n state.opts = {};\n for (var key in DEFAULTS) {\n state.opts[key] = DEFAULTS[key];\n }\n if (opts) {\n for (var k in opts) {\n if (k === \"buttonStyle\" || k === \"overlayStyle\") {\n state.opts[k] = mergeStyles(state.opts[k] || {}, opts[k]);\n } else if (opts[k] !== undefined) {\n state.opts[k] = opts[k];\n }\n }\n }\n\n var style = document.createElement(\"style\");\n style.textContent =\n '@media (max-width: 799px) { [data-embed-chat-iframe] { width: 100dvw !important; height: 100dvh !important; bottom: 0 !important; right: 0 !important; max-width: none !important; max-height: none !important; border-radius: 0 !important; } [data-embed-chat-overlay] { display: none !important; } }';\n document.head.appendChild(style);\n\n createOverlay();\n createIframe();\n createButton();\n window.addEventListener(\"message\", handleMessage);\n }\n\n window.ChatSDK = { initialize: initialize };\n})();\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/embed-chat.js"],"sourcesContent":["(function () {\n \"use strict\";\n\n var DEFAULTS = {\n iframeSrc: \"/chat-iframe\",\n title: \"Chat\",\n placeholder: \"Type a message...\",\n buttonInnerHtml:\n '<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"/></svg>',\n buttonStyle: {\n position: \"fixed\",\n bottom: \"24px\",\n right: \"24px\",\n width: \"56px\",\n height: \"56px\",\n borderRadius: \"50%\",\n border: \"none\",\n background: \"var(--chat-primary, #6366f1)\",\n color: \"#fff\",\n cursor: \"pointer\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n boxShadow: \"0 4px 16px rgba(0,0,0,0.2)\",\n zIndex: \"2147483646\",\n transition: \"transform 0.2s, opacity 0.2s\",\n },\n overlayStyle: {\n position: \"fixed\",\n inset: \"0\",\n background: \"rgba(0,0,0,0.3)\",\n zIndex: \"2147483646\",\n opacity: \"0\",\n transition: \"opacity 0.2s\",\n pointerEvents: \"none\",\n },\n };\n\n var state = {\n opts: null,\n button: null,\n iframe: null,\n overlay: null,\n styleEl: null,\n isOpen: false,\n originalViewport: undefined,\n initialized: false,\n };\n\n function mergeStyles(base, overrides) {\n var result = {};\n for (var key in base) result[key] = base[key];\n if (overrides) {\n for (var k in overrides) result[k] = overrides[k];\n }\n return result;\n }\n\n function createButton() {\n var opts = state.opts;\n state.button = document.createElement(\"button\");\n state.button.setAttribute(\"data-embed-chat-btn\", \"\");\n state.button.setAttribute(\"aria-label\", \"Open chat\");\n state.button.setAttribute(\"aria-expanded\", \"false\");\n state.button.innerHTML = opts.buttonInnerHtml;\n Object.assign(state.button.style, mergeStyles(DEFAULTS.buttonStyle, opts.buttonStyle));\n state.button.addEventListener(\"mouseenter\", function () {\n state.button.style.transform = \"scale(1.05)\";\n });\n state.button.addEventListener(\"mouseleave\", function () {\n state.button.style.transform = \"\";\n });\n state.button.addEventListener(\"click\", toggle);\n state.button.addEventListener(\"keydown\", function (e) {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n toggle();\n }\n });\n document.body.appendChild(state.button);\n }\n\n function createOverlay() {\n var opts = state.opts;\n state.overlay = document.createElement(\"div\");\n state.overlay.setAttribute(\"data-embed-chat-overlay\", \"\");\n Object.assign(state.overlay.style, mergeStyles(DEFAULTS.overlayStyle, opts.overlayStyle));\n state.overlay.addEventListener(\"click\", toggle);\n document.body.appendChild(state.overlay);\n }\n\n function createIframe() {\n var opts = state.opts;\n state.iframe = document.createElement(\"iframe\");\n state.iframe.setAttribute(\"data-embed-chat-iframe\", \"\");\n state.iframe.setAttribute(\"title\", \"Chat Widget\");\n state.iframe.setAttribute(\"role\", \"dialog\");\n state.iframe.setAttribute(\"aria-modal\", \"true\");\n state.iframe.setAttribute(\"allow\", \"clipboard-write; microphone\");\n state.iframe.src = opts.iframeSrc;\n Object.assign(state.iframe.style, {\n position: \"fixed\",\n bottom: \"96px\",\n right: \"24px\",\n width: \"420px\",\n height: \"600px\",\n maxWidth: \"calc(100dvw - 48px)\",\n maxHeight: \"calc(100dvh - 120px)\",\n border: \"none\",\n borderRadius: \"16px\",\n boxShadow: \"0 8px 32px rgba(0,0,0,0.15)\",\n zIndex: \"2147483647\",\n opacity: \"0\",\n transform: \"translateY(16px) scale(0.96)\",\n transition: \"opacity 0.2s, transform 0.25s\",\n pointerEvents: \"none\",\n background: \"#fff\",\n });\n document.body.appendChild(state.iframe);\n\n state.iframe.addEventListener(\"load\", function () {\n var savedTheme = \"auto\";\n try {\n var stored = localStorage.getItem(\"chat-theme\");\n if (stored === \"light\" || stored === \"dark\" || stored === \"auto\") savedTheme = stored;\n } catch {\n /* unavailable */\n }\n state.iframe.contentWindow.postMessage(\n {\n type: \"chat-config\",\n title: opts.title,\n placeholder: opts.placeholder,\n theme: { mode: savedTheme },\n },\n \"*\",\n );\n });\n }\n\n function toggle() {\n state.isOpen = !state.isOpen;\n var open = state.isOpen;\n\n state.button.setAttribute(\"aria-expanded\", String(open));\n state.iframe.style.opacity = open ? \"1\" : \"0\";\n state.iframe.style.transform = open ? \"translateY(0) scale(1)\" : \"translateY(16px) scale(0.96)\";\n state.iframe.style.pointerEvents = open ? \"auto\" : \"none\";\n\n state.overlay.style.opacity = open ? \"1\" : \"0\";\n state.overlay.style.pointerEvents = open ? \"auto\" : \"none\";\n\n state.button.style.transform = open ? \"scale(0)\" : \"\";\n state.button.style.opacity = open ? \"0\" : \"1\";\n state.button.style.pointerEvents = open ? \"none\" : \"auto\";\n\n document.body.style.overflow = open ? \"hidden\" : \"\";\n\n if (open) state.iframe.focus();\n }\n\n function handleMessage(event) {\n if (!state.iframe || event.source !== state.iframe.contentWindow) return;\n var data = event.data || {};\n if (data.type === \"chat-message\") {\n console.log(\"[Embed Chat] Message:\", data.text);\n }\n if (data.type === \"chat-close\") {\n toggle();\n }\n if (data.type === \"chat-viewport-config\") {\n var meta = document.querySelector('meta[name=\"viewport\"]');\n if (!meta) return;\n var current = meta.getAttribute(\"content\") || \"\";\n if (data.content) {\n if (state.originalViewport === undefined) state.originalViewport = current;\n if (!current.includes(data.content)) {\n meta.setAttribute(\"content\", current + (current ? \", \" : \"\") + data.content);\n }\n } else {\n meta.setAttribute(\"content\", state.originalViewport ?? current);\n state.originalViewport = undefined;\n }\n }\n }\n\n function destroy() {\n if (!state.initialized) return;\n if (state.button && state.button.parentNode) state.button.parentNode.removeChild(state.button);\n if (state.iframe && state.iframe.parentNode) state.iframe.parentNode.removeChild(state.iframe);\n if (state.overlay && state.overlay.parentNode)\n state.overlay.parentNode.removeChild(state.overlay);\n if (state.styleEl && state.styleEl.parentNode)\n state.styleEl.parentNode.removeChild(state.styleEl);\n window.removeEventListener(\"message\", handleMessage);\n state.initialized = false;\n }\n\n function _initialize(opts) {\n if (document.querySelector(\"[data-embed-chat-btn]\")) return;\n\n state.opts = {};\n for (var key in DEFAULTS) {\n state.opts[key] = DEFAULTS[key];\n }\n if (opts) {\n for (var k in opts) {\n if (k === \"buttonStyle\" || k === \"overlayStyle\") {\n state.opts[k] = mergeStyles(state.opts[k] || {}, opts[k]);\n } else if (opts[k] !== undefined) {\n state.opts[k] = opts[k];\n }\n }\n }\n\n var style = document.createElement(\"style\");\n style.textContent =\n \"@media (max-width: 799px) { [data-embed-chat-iframe] { width: 100dvw !important; height: 100dvh !important; bottom: 0 !important; right: 0 !important; max-width: none !important; max-height: none !important; border-radius: 0 !important; } [data-embed-chat-overlay] { display: none !important; } }\";\n document.head.appendChild(style);\n state.styleEl = style;\n\n createOverlay();\n createIframe();\n createButton();\n window.addEventListener(\"message\", handleMessage);\n state.initialized = true;\n }\n\n function initialize(opts) {\n if (document.readyState === \"loading\") {\n document.addEventListener(\"DOMContentLoaded\", function () {\n _initialize(opts);\n });\n } else {\n _initialize(opts);\n }\n }\n\n window.ChatSDK = { initialize: initialize, destroy: destroy };\n})();\n"],"mappings":"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","names":[]}
@@ -39,8 +39,10 @@
39
39
  button: null,
40
40
  iframe: null,
41
41
  overlay: null,
42
+ styleEl: null,
42
43
  isOpen: false,
43
- originalViewport: void 0
44
+ originalViewport: void 0,
45
+ initialized: false
44
46
  };
45
47
  function mergeStyles(base, overrides) {
46
48
  var result = {};
@@ -117,15 +119,16 @@
117
119
  } catch {
118
120
  }
119
121
  state.iframe.contentWindow.postMessage(
120
- { type: "chat-config", title: opts.title, placeholder: opts.placeholder, theme: { mode: savedTheme } },
122
+ {
123
+ type: "chat-config",
124
+ title: opts.title,
125
+ placeholder: opts.placeholder,
126
+ theme: { mode: savedTheme }
127
+ },
121
128
  "*"
122
129
  );
123
130
  });
124
131
  }
125
- function close() {
126
- if (!state.isOpen) return;
127
- toggle();
128
- }
129
132
  function toggle() {
130
133
  state.isOpen = !state.isOpen;
131
134
  var open = state.isOpen;
@@ -148,7 +151,7 @@
148
151
  console.log("[Embed Chat] Message:", data.text);
149
152
  }
150
153
  if (data.type === "chat-close") {
151
- close();
154
+ toggle();
152
155
  }
153
156
  if (data.type === "chat-viewport-config") {
154
157
  var meta = document.querySelector('meta[name="viewport"]');
@@ -165,7 +168,18 @@
165
168
  }
166
169
  }
167
170
  }
168
- function initialize(opts) {
171
+ function destroy() {
172
+ if (!state.initialized) return;
173
+ if (state.button && state.button.parentNode) state.button.parentNode.removeChild(state.button);
174
+ if (state.iframe && state.iframe.parentNode) state.iframe.parentNode.removeChild(state.iframe);
175
+ if (state.overlay && state.overlay.parentNode)
176
+ state.overlay.parentNode.removeChild(state.overlay);
177
+ if (state.styleEl && state.styleEl.parentNode)
178
+ state.styleEl.parentNode.removeChild(state.styleEl);
179
+ window.removeEventListener("message", handleMessage);
180
+ state.initialized = false;
181
+ }
182
+ function _initialize(opts) {
169
183
  if (document.querySelector("[data-embed-chat-btn]")) return;
170
184
  state.opts = {};
171
185
  for (var key in DEFAULTS) {
@@ -183,11 +197,22 @@
183
197
  var style = document.createElement("style");
184
198
  style.textContent = "@media (max-width: 799px) { [data-embed-chat-iframe] { width: 100dvw !important; height: 100dvh !important; bottom: 0 !important; right: 0 !important; max-width: none !important; max-height: none !important; border-radius: 0 !important; } [data-embed-chat-overlay] { display: none !important; } }";
185
199
  document.head.appendChild(style);
200
+ state.styleEl = style;
186
201
  createOverlay();
187
202
  createIframe();
188
203
  createButton();
189
204
  window.addEventListener("message", handleMessage);
205
+ state.initialized = true;
206
+ }
207
+ function initialize(opts) {
208
+ if (document.readyState === "loading") {
209
+ document.addEventListener("DOMContentLoaded", function() {
210
+ _initialize(opts);
211
+ });
212
+ } else {
213
+ _initialize(opts);
214
+ }
190
215
  }
191
- window.ChatSDK = { initialize };
216
+ window.ChatSDK = { initialize, destroy };
192
217
  })();
193
218
  //# sourceMappingURL=embed-chat.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/embed-chat.js"],"sourcesContent":["(function () {\n \"use strict\";\n\n var DEFAULTS = {\n iframeSrc: \"/chat-iframe\",\n title: \"Chat\",\n placeholder: \"Type a message...\",\n buttonInnerHtml:\n '<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"/></svg>',\n buttonStyle: {\n position: \"fixed\",\n bottom: \"24px\",\n right: \"24px\",\n width: \"56px\",\n height: \"56px\",\n borderRadius: \"50%\",\n border: \"none\",\n background: \"var(--chat-primary, #6366f1)\",\n color: \"#fff\",\n cursor: \"pointer\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n boxShadow: \"0 4px 16px rgba(0,0,0,0.2)\",\n zIndex: \"2147483646\",\n transition: \"transform 0.2s, opacity 0.2s\",\n },\n overlayStyle: {\n position: \"fixed\",\n inset: \"0\",\n background: \"rgba(0,0,0,0.3)\",\n zIndex: \"2147483646\",\n opacity: \"0\",\n transition: \"opacity 0.2s\",\n pointerEvents: \"none\",\n },\n };\n\n var state = {\n opts: null,\n button: null,\n iframe: null,\n overlay: null,\n isOpen: false,\n originalViewport: undefined,\n };\n\n function mergeStyles(base, overrides) {\n var result = {};\n for (var key in base) result[key] = base[key];\n if (overrides) {\n for (var k in overrides) result[k] = overrides[k];\n }\n return result;\n }\n\n function createButton() {\n var opts = state.opts;\n state.button = document.createElement(\"button\");\n state.button.setAttribute(\"data-embed-chat-btn\", \"\");\n state.button.setAttribute(\"aria-label\", \"Open chat\");\n state.button.setAttribute(\"aria-expanded\", \"false\");\n state.button.innerHTML = opts.buttonInnerHtml;\n Object.assign(state.button.style, mergeStyles(DEFAULTS.buttonStyle, opts.buttonStyle));\n state.button.addEventListener(\"mouseenter\", function () {\n state.button.style.transform = \"scale(1.05)\";\n });\n state.button.addEventListener(\"mouseleave\", function () {\n state.button.style.transform = \"\";\n });\n state.button.addEventListener(\"click\", toggle);\n state.button.addEventListener(\"keydown\", function (e) {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n toggle();\n }\n });\n document.body.appendChild(state.button);\n }\n\n function createOverlay() {\n var opts = state.opts;\n state.overlay = document.createElement(\"div\");\n state.overlay.setAttribute(\"data-embed-chat-overlay\", \"\");\n Object.assign(state.overlay.style, mergeStyles(DEFAULTS.overlayStyle, opts.overlayStyle));\n state.overlay.addEventListener(\"click\", toggle);\n document.body.appendChild(state.overlay);\n }\n\n function createIframe() {\n var opts = state.opts;\n state.iframe = document.createElement(\"iframe\");\n state.iframe.setAttribute(\"data-embed-chat-iframe\", \"\");\n state.iframe.setAttribute(\"title\", \"Chat Widget\");\n state.iframe.setAttribute(\"role\", \"dialog\");\n state.iframe.setAttribute(\"aria-modal\", \"true\");\n state.iframe.setAttribute(\"allow\", \"clipboard-write; microphone\");\n state.iframe.src = opts.iframeSrc;\n Object.assign(state.iframe.style, {\n position: \"fixed\",\n bottom: \"96px\",\n right: \"24px\",\n width: \"420px\",\n height: \"600px\",\n maxWidth: \"calc(100dvw - 48px)\",\n maxHeight: \"calc(100dvh - 120px)\",\n border: \"none\",\n borderRadius: \"16px\",\n boxShadow: \"0 8px 32px rgba(0,0,0,0.15)\",\n zIndex: \"2147483647\",\n opacity: \"0\",\n transform: \"translateY(16px) scale(0.96)\",\n transition: \"opacity 0.2s, transform 0.25s\",\n pointerEvents: \"none\",\n background: \"#fff\",\n });\n document.body.appendChild(state.iframe);\n\n state.iframe.addEventListener(\"load\", function () {\n var savedTheme = \"auto\";\n try {\n var stored = localStorage.getItem(\"chat-theme\");\n if (stored === \"light\" || stored === \"dark\" || stored === \"auto\") savedTheme = stored;\n } catch { /* unavailable */ }\n state.iframe.contentWindow.postMessage(\n { type: \"chat-config\", title: opts.title, placeholder: opts.placeholder, theme: { mode: savedTheme } },\n \"*\",\n );\n });\n }\n\n function close() {\n if (!state.isOpen) return;\n toggle();\n }\n\n function toggle() {\n state.isOpen = !state.isOpen;\n var open = state.isOpen;\n\n state.button.setAttribute(\"aria-expanded\", String(open));\n state.iframe.style.opacity = open ? \"1\" : \"0\";\n state.iframe.style.transform = open ? \"translateY(0) scale(1)\" : \"translateY(16px) scale(0.96)\";\n state.iframe.style.pointerEvents = open ? \"auto\" : \"none\";\n\n state.overlay.style.opacity = open ? \"1\" : \"0\";\n state.overlay.style.pointerEvents = open ? \"auto\" : \"none\";\n\n state.button.style.transform = open ? \"scale(0)\" : \"\";\n state.button.style.opacity = open ? \"0\" : \"1\";\n state.button.style.pointerEvents = open ? \"none\" : \"auto\";\n\n document.body.style.overflow = open ? \"hidden\" : \"\";\n\n if (open) state.iframe.focus();\n }\n\n function handleMessage(event) {\n if (!state.iframe || event.source !== state.iframe.contentWindow) return;\n var data = event.data || {};\n if (data.type === \"chat-message\") {\n console.log(\"[Embed Chat] Message:\", data.text);\n }\n if (data.type === \"chat-close\") {\n close();\n }\n if (data.type === \"chat-viewport-config\") {\n var meta = document.querySelector('meta[name=\"viewport\"]');\n if (!meta) return;\n var current = meta.getAttribute(\"content\") || \"\";\n if (data.content) {\n if (state.originalViewport === undefined) state.originalViewport = current;\n if (!current.includes(data.content)) {\n meta.setAttribute(\"content\", current + (current ? \", \" : \"\") + data.content);\n }\n } else {\n meta.setAttribute(\"content\", state.originalViewport ?? current);\n state.originalViewport = undefined;\n }\n }\n }\n\n function initialize(opts) {\n if (document.querySelector(\"[data-embed-chat-btn]\")) return;\n\n state.opts = {};\n for (var key in DEFAULTS) {\n state.opts[key] = DEFAULTS[key];\n }\n if (opts) {\n for (var k in opts) {\n if (k === \"buttonStyle\" || k === \"overlayStyle\") {\n state.opts[k] = mergeStyles(state.opts[k] || {}, opts[k]);\n } else if (opts[k] !== undefined) {\n state.opts[k] = opts[k];\n }\n }\n }\n\n var style = document.createElement(\"style\");\n style.textContent =\n '@media (max-width: 799px) { [data-embed-chat-iframe] { width: 100dvw !important; height: 100dvh !important; bottom: 0 !important; right: 0 !important; max-width: none !important; max-height: none !important; border-radius: 0 !important; } [data-embed-chat-overlay] { display: none !important; } }';\n document.head.appendChild(style);\n\n createOverlay();\n createIframe();\n createButton();\n window.addEventListener(\"message\", handleMessage);\n }\n\n window.ChatSDK = { initialize: initialize };\n})();\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/embed-chat.js"],"sourcesContent":["(function () {\n \"use strict\";\n\n var DEFAULTS = {\n iframeSrc: \"/chat-iframe\",\n title: \"Chat\",\n placeholder: \"Type a message...\",\n buttonInnerHtml:\n '<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"/></svg>',\n buttonStyle: {\n position: \"fixed\",\n bottom: \"24px\",\n right: \"24px\",\n width: \"56px\",\n height: \"56px\",\n borderRadius: \"50%\",\n border: \"none\",\n background: \"var(--chat-primary, #6366f1)\",\n color: \"#fff\",\n cursor: \"pointer\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n boxShadow: \"0 4px 16px rgba(0,0,0,0.2)\",\n zIndex: \"2147483646\",\n transition: \"transform 0.2s, opacity 0.2s\",\n },\n overlayStyle: {\n position: \"fixed\",\n inset: \"0\",\n background: \"rgba(0,0,0,0.3)\",\n zIndex: \"2147483646\",\n opacity: \"0\",\n transition: \"opacity 0.2s\",\n pointerEvents: \"none\",\n },\n };\n\n var state = {\n opts: null,\n button: null,\n iframe: null,\n overlay: null,\n styleEl: null,\n isOpen: false,\n originalViewport: undefined,\n initialized: false,\n };\n\n function mergeStyles(base, overrides) {\n var result = {};\n for (var key in base) result[key] = base[key];\n if (overrides) {\n for (var k in overrides) result[k] = overrides[k];\n }\n return result;\n }\n\n function createButton() {\n var opts = state.opts;\n state.button = document.createElement(\"button\");\n state.button.setAttribute(\"data-embed-chat-btn\", \"\");\n state.button.setAttribute(\"aria-label\", \"Open chat\");\n state.button.setAttribute(\"aria-expanded\", \"false\");\n state.button.innerHTML = opts.buttonInnerHtml;\n Object.assign(state.button.style, mergeStyles(DEFAULTS.buttonStyle, opts.buttonStyle));\n state.button.addEventListener(\"mouseenter\", function () {\n state.button.style.transform = \"scale(1.05)\";\n });\n state.button.addEventListener(\"mouseleave\", function () {\n state.button.style.transform = \"\";\n });\n state.button.addEventListener(\"click\", toggle);\n state.button.addEventListener(\"keydown\", function (e) {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n toggle();\n }\n });\n document.body.appendChild(state.button);\n }\n\n function createOverlay() {\n var opts = state.opts;\n state.overlay = document.createElement(\"div\");\n state.overlay.setAttribute(\"data-embed-chat-overlay\", \"\");\n Object.assign(state.overlay.style, mergeStyles(DEFAULTS.overlayStyle, opts.overlayStyle));\n state.overlay.addEventListener(\"click\", toggle);\n document.body.appendChild(state.overlay);\n }\n\n function createIframe() {\n var opts = state.opts;\n state.iframe = document.createElement(\"iframe\");\n state.iframe.setAttribute(\"data-embed-chat-iframe\", \"\");\n state.iframe.setAttribute(\"title\", \"Chat Widget\");\n state.iframe.setAttribute(\"role\", \"dialog\");\n state.iframe.setAttribute(\"aria-modal\", \"true\");\n state.iframe.setAttribute(\"allow\", \"clipboard-write; microphone\");\n state.iframe.src = opts.iframeSrc;\n Object.assign(state.iframe.style, {\n position: \"fixed\",\n bottom: \"96px\",\n right: \"24px\",\n width: \"420px\",\n height: \"600px\",\n maxWidth: \"calc(100dvw - 48px)\",\n maxHeight: \"calc(100dvh - 120px)\",\n border: \"none\",\n borderRadius: \"16px\",\n boxShadow: \"0 8px 32px rgba(0,0,0,0.15)\",\n zIndex: \"2147483647\",\n opacity: \"0\",\n transform: \"translateY(16px) scale(0.96)\",\n transition: \"opacity 0.2s, transform 0.25s\",\n pointerEvents: \"none\",\n background: \"#fff\",\n });\n document.body.appendChild(state.iframe);\n\n state.iframe.addEventListener(\"load\", function () {\n var savedTheme = \"auto\";\n try {\n var stored = localStorage.getItem(\"chat-theme\");\n if (stored === \"light\" || stored === \"dark\" || stored === \"auto\") savedTheme = stored;\n } catch {\n /* unavailable */\n }\n state.iframe.contentWindow.postMessage(\n {\n type: \"chat-config\",\n title: opts.title,\n placeholder: opts.placeholder,\n theme: { mode: savedTheme },\n },\n \"*\",\n );\n });\n }\n\n function toggle() {\n state.isOpen = !state.isOpen;\n var open = state.isOpen;\n\n state.button.setAttribute(\"aria-expanded\", String(open));\n state.iframe.style.opacity = open ? \"1\" : \"0\";\n state.iframe.style.transform = open ? \"translateY(0) scale(1)\" : \"translateY(16px) scale(0.96)\";\n state.iframe.style.pointerEvents = open ? \"auto\" : \"none\";\n\n state.overlay.style.opacity = open ? \"1\" : \"0\";\n state.overlay.style.pointerEvents = open ? \"auto\" : \"none\";\n\n state.button.style.transform = open ? \"scale(0)\" : \"\";\n state.button.style.opacity = open ? \"0\" : \"1\";\n state.button.style.pointerEvents = open ? \"none\" : \"auto\";\n\n document.body.style.overflow = open ? \"hidden\" : \"\";\n\n if (open) state.iframe.focus();\n }\n\n function handleMessage(event) {\n if (!state.iframe || event.source !== state.iframe.contentWindow) return;\n var data = event.data || {};\n if (data.type === \"chat-message\") {\n console.log(\"[Embed Chat] Message:\", data.text);\n }\n if (data.type === \"chat-close\") {\n toggle();\n }\n if (data.type === \"chat-viewport-config\") {\n var meta = document.querySelector('meta[name=\"viewport\"]');\n if (!meta) return;\n var current = meta.getAttribute(\"content\") || \"\";\n if (data.content) {\n if (state.originalViewport === undefined) state.originalViewport = current;\n if (!current.includes(data.content)) {\n meta.setAttribute(\"content\", current + (current ? \", \" : \"\") + data.content);\n }\n } else {\n meta.setAttribute(\"content\", state.originalViewport ?? current);\n state.originalViewport = undefined;\n }\n }\n }\n\n function destroy() {\n if (!state.initialized) return;\n if (state.button && state.button.parentNode) state.button.parentNode.removeChild(state.button);\n if (state.iframe && state.iframe.parentNode) state.iframe.parentNode.removeChild(state.iframe);\n if (state.overlay && state.overlay.parentNode)\n state.overlay.parentNode.removeChild(state.overlay);\n if (state.styleEl && state.styleEl.parentNode)\n state.styleEl.parentNode.removeChild(state.styleEl);\n window.removeEventListener(\"message\", handleMessage);\n state.initialized = false;\n }\n\n function _initialize(opts) {\n if (document.querySelector(\"[data-embed-chat-btn]\")) return;\n\n state.opts = {};\n for (var key in DEFAULTS) {\n state.opts[key] = DEFAULTS[key];\n }\n if (opts) {\n for (var k in opts) {\n if (k === \"buttonStyle\" || k === \"overlayStyle\") {\n state.opts[k] = mergeStyles(state.opts[k] || {}, opts[k]);\n } else if (opts[k] !== undefined) {\n state.opts[k] = opts[k];\n }\n }\n }\n\n var style = document.createElement(\"style\");\n style.textContent =\n \"@media (max-width: 799px) { [data-embed-chat-iframe] { width: 100dvw !important; height: 100dvh !important; bottom: 0 !important; right: 0 !important; max-width: none !important; max-height: none !important; border-radius: 0 !important; } [data-embed-chat-overlay] { display: none !important; } }\";\n document.head.appendChild(style);\n state.styleEl = style;\n\n createOverlay();\n createIframe();\n createButton();\n window.addEventListener(\"message\", handleMessage);\n state.initialized = true;\n }\n\n function initialize(opts) {\n if (document.readyState === \"loading\") {\n document.addEventListener(\"DOMContentLoaded\", function () {\n _initialize(opts);\n });\n } else {\n _initialize(opts);\n }\n }\n\n window.ChatSDK = { initialize: initialize, destroy: destroy };\n})();\n"],"mappings":"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","names":[]}
package/dist/index.cjs CHANGED
@@ -20,6 +20,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
+ WEBVIEW_SHIM: () => WEBVIEW_SHIM,
24
+ buildShimUrl: () => buildShimUrl,
23
25
  useIframeBridge: () => useIframeBridge
24
26
  });
25
27
  module.exports = __toCommonJS(index_exports);
@@ -28,8 +30,15 @@ module.exports = __toCommonJS(index_exports);
28
30
  var import_react = require("react");
29
31
  function useIframeBridge() {
30
32
  const [config, setConfig] = (0, import_react.useState)(null);
33
+ const [pushState, setPushState] = (0, import_react.useState)(null);
31
34
  const notificationCbRef = (0, import_react.useRef)(null);
35
+ const readyRef = (0, import_react.useRef)(false);
32
36
  const isInIframe = typeof window !== "undefined" && window !== window.parent;
37
+ (0, import_react.useEffect)(() => {
38
+ if (typeof window !== "undefined" && window.__chatBridge?._pushState) {
39
+ setPushState(window.__chatBridge._pushState);
40
+ }
41
+ }, []);
33
42
  const notifyMessage = (0, import_react.useCallback)(
34
43
  (text) => {
35
44
  if (!isInIframe) return;
@@ -38,9 +47,36 @@ function useIframeBridge() {
38
47
  },
39
48
  [isInIframe]
40
49
  );
50
+ const notifyViewportConfig = (0, import_react.useCallback)(
51
+ (content) => {
52
+ if (!isInIframe) return;
53
+ const msg = { type: "chat-viewport-config", content };
54
+ window.parent.postMessage(msg, "*");
55
+ },
56
+ [isInIframe]
57
+ );
41
58
  const onNotificationClicked = (0, import_react.useCallback)((cb) => {
42
59
  notificationCbRef.current = cb;
43
60
  }, []);
61
+ const requestPushSubscribe = (0, import_react.useCallback)(() => {
62
+ if (!isInIframe) return;
63
+ const msg = { type: "chat-push-subscribe" };
64
+ window.parent.postMessage(msg, "*");
65
+ }, [isInIframe]);
66
+ const requestPushUnsubscribe = (0, import_react.useCallback)(() => {
67
+ if (!isInIframe) return;
68
+ const msg = { type: "chat-push-unsubscribe" };
69
+ window.parent.postMessage(msg, "*");
70
+ }, [isInIframe]);
71
+ (0, import_react.useEffect)(() => {
72
+ if (!isInIframe) return;
73
+ if (readyRef.current) return;
74
+ readyRef.current = true;
75
+ const msg = { type: "chat-ready" };
76
+ if (typeof window.parent.postMessage === "function") {
77
+ window.parent.postMessage(msg, "*");
78
+ }
79
+ }, [isInIframe]);
44
80
  (0, import_react.useEffect)(() => {
45
81
  if (!isInIframe) return;
46
82
  function handleMessage(event) {
@@ -56,15 +92,113 @@ function useIframeBridge() {
56
92
  case "chat-notification-clicked":
57
93
  notificationCbRef.current?.();
58
94
  break;
95
+ case "chat-push-state":
96
+ if (typeof data.status === "string") {
97
+ setPushState(data.status);
98
+ }
99
+ break;
100
+ }
101
+ }
102
+ function handleCustomEvent(event) {
103
+ const detail = event.detail;
104
+ if (!detail || typeof detail !== "object") return;
105
+ if (detail.type === "chat-push-state" && typeof detail.status === "string") {
106
+ setPushState(detail.status);
59
107
  }
60
108
  }
61
109
  window.addEventListener("message", handleMessage);
62
- return () => window.removeEventListener("message", handleMessage);
110
+ window.addEventListener("chat-bridge", handleCustomEvent);
111
+ return () => {
112
+ window.removeEventListener("message", handleMessage);
113
+ window.removeEventListener("chat-bridge", handleCustomEvent);
114
+ };
63
115
  }, [isInIframe]);
64
- return { config, isInIframe, notifyMessage, onNotificationClicked };
116
+ return {
117
+ config,
118
+ isInIframe,
119
+ notifyMessage,
120
+ notifyViewportConfig,
121
+ onNotificationClicked,
122
+ pushState,
123
+ requestPushSubscribe,
124
+ requestPushUnsubscribe
125
+ };
126
+ }
127
+
128
+ // src/shim.ts
129
+ var WEBVIEW_SHIM = `
130
+ (function () {
131
+ 'use strict';
132
+ var _cached = [];
133
+ var _originalPostMessage = window.parent && window.parent.postMessage;
134
+
135
+ function _send(msg) {
136
+ try {
137
+ var json = JSON.stringify(msg);
138
+ } catch (e) {
139
+ var errJson = JSON.stringify({ type: 'chat-error', code: 'SERIALIZE_ERROR', message: 'Failed to serialize message' + e.message });
140
+ try { if (window.parent) window.parent.postMessage(errJson, '*'); } catch (_) {}
141
+ console.error('[ChatBridge] JSON.stringify failed:', e);
142
+ return;
143
+ }
144
+ try {
145
+ if (window.ReactNativeWebView && window.ReactNativeWebView.postMessage) {
146
+ window.ReactNativeWebView.postMessage(json);
147
+ } else if (window.AndroidBridge && window.AndroidBridge.postMessage) {
148
+ window.AndroidBridge.postMessage(json);
149
+ } else if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.chatBridge) {
150
+ window.webkit.messageHandlers.chatBridge.postMessage(msg);
151
+ } else if (_originalPostMessage) {
152
+ _originalPostMessage.call(window.parent, msg, '*');
153
+ } else {
154
+ console.warn('[ChatBridge] No bridge API detected');
155
+ }
156
+ } catch (e) {
157
+ var fallback = JSON.stringify({ type: 'chat-error', code: 'BRIDGE_ERROR', message: 'Bridge postMessage failed: ' + e.message });
158
+ try { if (window.parent) window.parent.postMessage(fallback, '*'); } catch (_) {}
159
+ console.error('[ChatBridge] postMessage failed:', e);
160
+ }
161
+ }
162
+
163
+ window.__chatBridge = {
164
+ _pushState: null,
165
+ send: function (msg) { _send(msg); },
166
+ setPushState: function (status) { window.__chatBridge._pushState = status; },
167
+ };
168
+
169
+ var _batches = 0;
170
+ window.addEventListener('chat-bridge', function (e) {
171
+ if (_batches++ > 0) return;
172
+ requestAnimationFrame(function () {
173
+ _batches = 0;
174
+ });
175
+ var payload = e.detail;
176
+ if (!payload || typeof payload !== 'object') return;
177
+ var type = payload.type;
178
+ if (type === 'chat-config') {
179
+ window.__chatBridge._config = payload;
180
+ } else if (type === 'chat-push-state') {
181
+ window.__chatBridge._pushState = payload.status || null;
182
+ }
183
+ _cached.push(payload);
184
+ });
185
+
186
+ window.addEventListener('message', function (e) {
187
+ var data = e.data;
188
+ if (!data || typeof data !== 'object' || !data.type) return;
189
+ if (data.type === 'chat-push-state') {
190
+ window.__chatBridge._pushState = data.status || null;
191
+ }
192
+ });
193
+ })();
194
+ `;
195
+ function buildShimUrl() {
196
+ return "data:text/javascript;base64," + btoa(WEBVIEW_SHIM);
65
197
  }
66
198
  // Annotate the CommonJS export names for ESM import in node:
67
199
  0 && (module.exports = {
200
+ WEBVIEW_SHIM,
201
+ buildShimUrl,
68
202
  useIframeBridge
69
203
  });
70
204
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/useIframeBridge.ts"],"sourcesContent":["export { useIframeBridge } from \"./useIframeBridge\";\nexport type { BridgeConfig, IframeBridgeHook, BridgeMessage } from \"./types\";\n","import { useCallback, useEffect, useRef, useState } from \"react\";\nimport type { BridgeConfig, BridgeMessage, IframeBridgeHook } from \"./types\";\n\nexport function useIframeBridge(): IframeBridgeHook {\n const [config, setConfig] = useState<BridgeConfig | null>(null);\n const notificationCbRef = useRef<(() => void) | null>(null);\n\n const isInIframe = typeof window !== \"undefined\" && window !== window.parent;\n\n const notifyMessage = useCallback(\n (text: string) => {\n if (!isInIframe) return;\n const msg: BridgeMessage = { type: \"chat-message\", text };\n window.parent.postMessage(msg, \"*\");\n },\n [isInIframe],\n );\n\n const onNotificationClicked = useCallback((cb: () => void) => {\n notificationCbRef.current = cb;\n }, []);\n\n useEffect(() => {\n if (!isInIframe) return;\n\n function handleMessage(event: MessageEvent) {\n const data = event.data as Record<string, unknown>;\n if (!data || typeof data !== \"object\" || !data.type) return;\n\n switch (data.type) {\n case \"chat-config\": {\n const configData = { ...data };\n delete configData.type;\n setConfig(configData as BridgeConfig);\n break;\n }\n case \"chat-notification-clicked\":\n notificationCbRef.current?.();\n break;\n }\n }\n\n window.addEventListener(\"message\", handleMessage);\n return () => window.removeEventListener(\"message\", handleMessage);\n }, [isInIframe]);\n\n return { config, isInIframe, notifyMessage, onNotificationClicked };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,mBAAyD;AAGlD,SAAS,kBAAoC;AAClD,QAAM,CAAC,QAAQ,SAAS,QAAI,uBAA8B,IAAI;AAC9D,QAAM,wBAAoB,qBAA4B,IAAI;AAE1D,QAAM,aAAa,OAAO,WAAW,eAAe,WAAW,OAAO;AAEtE,QAAM,oBAAgB;AAAA,IACpB,CAAC,SAAiB;AAChB,UAAI,CAAC,WAAY;AACjB,YAAM,MAAqB,EAAE,MAAM,gBAAgB,KAAK;AACxD,aAAO,OAAO,YAAY,KAAK,GAAG;AAAA,IACpC;AAAA,IACA,CAAC,UAAU;AAAA,EACb;AAEA,QAAM,4BAAwB,0BAAY,CAAC,OAAmB;AAC5D,sBAAkB,UAAU;AAAA,EAC9B,GAAG,CAAC,CAAC;AAEL,8BAAU,MAAM;AACd,QAAI,CAAC,WAAY;AAEjB,aAAS,cAAc,OAAqB;AAC1C,YAAM,OAAO,MAAM;AACnB,UAAI,CAAC,QAAQ,OAAO,SAAS,YAAY,CAAC,KAAK,KAAM;AAErD,cAAQ,KAAK,MAAM;AAAA,QACjB,KAAK,eAAe;AAClB,gBAAM,aAAa,EAAE,GAAG,KAAK;AAC7B,iBAAO,WAAW;AAClB,oBAAU,UAA0B;AACpC;AAAA,QACF;AAAA,QACA,KAAK;AACH,4BAAkB,UAAU;AAC5B;AAAA,MACJ;AAAA,IACF;AAEA,WAAO,iBAAiB,WAAW,aAAa;AAChD,WAAO,MAAM,OAAO,oBAAoB,WAAW,aAAa;AAAA,EAClE,GAAG,CAAC,UAAU,CAAC;AAEf,SAAO,EAAE,QAAQ,YAAY,eAAe,sBAAsB;AACpE;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/useIframeBridge.ts","../src/shim.ts"],"sourcesContent":["export { useIframeBridge } from \"./useIframeBridge\";\nexport { WEBVIEW_SHIM, buildShimUrl } from \"./shim\";\nexport type {\n BridgeConfig,\n IframeBridgeHook,\n BridgeMessage,\n BridgePushStatus,\n BridgeMessageType,\n ThemeMode,\n} from \"./types\";\n","import { useCallback, useEffect, useRef, useState } from \"react\";\nimport type { BridgeConfig, BridgeMessage, BridgePushStatus, IframeBridgeHook } from \"./types\";\n\nexport function useIframeBridge(): IframeBridgeHook {\n const [config, setConfig] = useState<BridgeConfig | null>(null);\n const [pushState, setPushState] = useState<BridgePushStatus | null>(null);\n const notificationCbRef = useRef<(() => void) | null>(null);\n const readyRef = useRef(false);\n\n const isInIframe = typeof window !== \"undefined\" && window !== window.parent;\n\n useEffect(() => {\n if (typeof window !== \"undefined\" && (window as any).__chatBridge?._pushState) {\n setPushState((window as any).__chatBridge._pushState);\n }\n }, []);\n\n const notifyMessage = useCallback(\n (text: string) => {\n if (!isInIframe) return;\n const msg: BridgeMessage = { type: \"chat-message\", text };\n window.parent.postMessage(msg, \"*\");\n },\n [isInIframe],\n );\n\n const notifyViewportConfig = useCallback(\n (content: string) => {\n if (!isInIframe) return;\n const msg: BridgeMessage = { type: \"chat-viewport-config\", content };\n window.parent.postMessage(msg, \"*\");\n },\n [isInIframe],\n );\n\n const onNotificationClicked = useCallback((cb: () => void) => {\n notificationCbRef.current = cb;\n }, []);\n\n const requestPushSubscribe = useCallback(() => {\n if (!isInIframe) return;\n const msg: BridgeMessage = { type: \"chat-push-subscribe\" };\n window.parent.postMessage(msg, \"*\");\n }, [isInIframe]);\n\n const requestPushUnsubscribe = useCallback(() => {\n if (!isInIframe) return;\n const msg: BridgeMessage = { type: \"chat-push-unsubscribe\" };\n window.parent.postMessage(msg, \"*\");\n }, [isInIframe]);\n\n useEffect(() => {\n if (!isInIframe) return;\n if (readyRef.current) return;\n readyRef.current = true;\n\n const msg: BridgeMessage = { type: \"chat-ready\" };\n if (typeof window.parent.postMessage === \"function\") {\n window.parent.postMessage(msg, \"*\");\n }\n }, [isInIframe]);\n\n useEffect(() => {\n if (!isInIframe) return;\n\n function handleMessage(event: MessageEvent) {\n const data = event.data as Record<string, unknown>;\n if (!data || typeof data !== \"object\" || !data.type) return;\n\n switch (data.type) {\n case \"chat-config\": {\n const configData = { ...data };\n delete configData.type;\n setConfig(configData as BridgeConfig);\n break;\n }\n case \"chat-notification-clicked\":\n notificationCbRef.current?.();\n break;\n case \"chat-push-state\":\n if (typeof data.status === \"string\") {\n setPushState(data.status as BridgePushStatus);\n }\n break;\n }\n }\n\n function handleCustomEvent(event: Event) {\n const detail = (event as CustomEvent).detail;\n if (!detail || typeof detail !== \"object\") return;\n if (detail.type === \"chat-push-state\" && typeof detail.status === \"string\") {\n setPushState(detail.status as BridgePushStatus);\n }\n }\n\n window.addEventListener(\"message\", handleMessage);\n window.addEventListener(\"chat-bridge\", handleCustomEvent);\n return () => {\n window.removeEventListener(\"message\", handleMessage);\n window.removeEventListener(\"chat-bridge\", handleCustomEvent);\n };\n }, [isInIframe]);\n\n return {\n config,\n isInIframe,\n notifyMessage,\n notifyViewportConfig,\n onNotificationClicked,\n pushState,\n requestPushSubscribe,\n requestPushUnsubscribe,\n };\n}\n","export const WEBVIEW_SHIM: string = `\n(function () {\n 'use strict';\n var _cached = [];\n var _originalPostMessage = window.parent && window.parent.postMessage;\n\n function _send(msg) {\n try {\n var json = JSON.stringify(msg);\n } catch (e) {\n var errJson = JSON.stringify({ type: 'chat-error', code: 'SERIALIZE_ERROR', message: 'Failed to serialize message' + e.message });\n try { if (window.parent) window.parent.postMessage(errJson, '*'); } catch (_) {}\n console.error('[ChatBridge] JSON.stringify failed:', e);\n return;\n }\n try {\n if (window.ReactNativeWebView && window.ReactNativeWebView.postMessage) {\n window.ReactNativeWebView.postMessage(json);\n } else if (window.AndroidBridge && window.AndroidBridge.postMessage) {\n window.AndroidBridge.postMessage(json);\n } else if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.chatBridge) {\n window.webkit.messageHandlers.chatBridge.postMessage(msg);\n } else if (_originalPostMessage) {\n _originalPostMessage.call(window.parent, msg, '*');\n } else {\n console.warn('[ChatBridge] No bridge API detected');\n }\n } catch (e) {\n var fallback = JSON.stringify({ type: 'chat-error', code: 'BRIDGE_ERROR', message: 'Bridge postMessage failed: ' + e.message });\n try { if (window.parent) window.parent.postMessage(fallback, '*'); } catch (_) {}\n console.error('[ChatBridge] postMessage failed:', e);\n }\n }\n\n window.__chatBridge = {\n _pushState: null,\n send: function (msg) { _send(msg); },\n setPushState: function (status) { window.__chatBridge._pushState = status; },\n };\n\n var _batches = 0;\n window.addEventListener('chat-bridge', function (e) {\n if (_batches++ > 0) return;\n requestAnimationFrame(function () {\n _batches = 0;\n });\n var payload = e.detail;\n if (!payload || typeof payload !== 'object') return;\n var type = payload.type;\n if (type === 'chat-config') {\n window.__chatBridge._config = payload;\n } else if (type === 'chat-push-state') {\n window.__chatBridge._pushState = payload.status || null;\n }\n _cached.push(payload);\n });\n\n window.addEventListener('message', function (e) {\n var data = e.data;\n if (!data || typeof data !== 'object' || !data.type) return;\n if (data.type === 'chat-push-state') {\n window.__chatBridge._pushState = data.status || null;\n }\n });\n})();\n`;\n\nexport function buildShimUrl(): string {\n return \"data:text/javascript;base64,\" + btoa(WEBVIEW_SHIM);\n}\n"],"mappings":"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","names":[]}
package/dist/index.d.cts CHANGED
@@ -1,22 +1,34 @@
1
+ type BridgePushStatus = "unsupported" | "default" | "subscribed" | "denied" | "subscribing" | "error";
2
+ type BridgeMessageType = "chat-ready" | "chat-config" | "chat-message" | "chat-notification-clicked" | "chat-close" | "chat-viewport-config" | "chat-viewport-insets" | "chat-push-state" | "chat-push-subscribe" | "chat-push-unsubscribe" | "chat-error";
3
+ type ThemeMode = "auto" | "light" | "dark";
1
4
  interface BridgeConfig {
2
5
  locale?: string;
3
6
  title?: string;
4
7
  placeholder?: string;
5
8
  theme?: {
6
- mode?: "auto" | "light" | "dark";
9
+ mode?: ThemeMode;
10
+ cssVariables?: Record<string, string>;
7
11
  };
8
12
  }
9
13
  interface IframeBridgeHook {
10
14
  config: BridgeConfig | null;
11
15
  isInIframe: boolean;
12
16
  notifyMessage: (text: string) => void;
17
+ notifyViewportConfig: (content: string) => void;
13
18
  onNotificationClicked: (cb: () => void) => void;
19
+ pushState: BridgePushStatus | null;
20
+ requestPushSubscribe: () => void;
21
+ requestPushUnsubscribe: () => void;
14
22
  }
15
23
  interface BridgeMessage {
16
- type: "chat-config" | "chat-message" | "chat-notification-clicked" | "chat-close";
24
+ type: BridgeMessageType;
25
+ id?: string;
17
26
  [key: string]: unknown;
18
27
  }
19
28
 
20
29
  declare function useIframeBridge(): IframeBridgeHook;
21
30
 
22
- export { type BridgeConfig, type BridgeMessage, type IframeBridgeHook, useIframeBridge };
31
+ declare const WEBVIEW_SHIM: string;
32
+ declare function buildShimUrl(): string;
33
+
34
+ export { type BridgeConfig, type BridgeMessage, type BridgeMessageType, type BridgePushStatus, type IframeBridgeHook, type ThemeMode, WEBVIEW_SHIM, buildShimUrl, useIframeBridge };
package/dist/index.d.ts CHANGED
@@ -1,22 +1,34 @@
1
+ type BridgePushStatus = "unsupported" | "default" | "subscribed" | "denied" | "subscribing" | "error";
2
+ type BridgeMessageType = "chat-ready" | "chat-config" | "chat-message" | "chat-notification-clicked" | "chat-close" | "chat-viewport-config" | "chat-viewport-insets" | "chat-push-state" | "chat-push-subscribe" | "chat-push-unsubscribe" | "chat-error";
3
+ type ThemeMode = "auto" | "light" | "dark";
1
4
  interface BridgeConfig {
2
5
  locale?: string;
3
6
  title?: string;
4
7
  placeholder?: string;
5
8
  theme?: {
6
- mode?: "auto" | "light" | "dark";
9
+ mode?: ThemeMode;
10
+ cssVariables?: Record<string, string>;
7
11
  };
8
12
  }
9
13
  interface IframeBridgeHook {
10
14
  config: BridgeConfig | null;
11
15
  isInIframe: boolean;
12
16
  notifyMessage: (text: string) => void;
17
+ notifyViewportConfig: (content: string) => void;
13
18
  onNotificationClicked: (cb: () => void) => void;
19
+ pushState: BridgePushStatus | null;
20
+ requestPushSubscribe: () => void;
21
+ requestPushUnsubscribe: () => void;
14
22
  }
15
23
  interface BridgeMessage {
16
- type: "chat-config" | "chat-message" | "chat-notification-clicked" | "chat-close";
24
+ type: BridgeMessageType;
25
+ id?: string;
17
26
  [key: string]: unknown;
18
27
  }
19
28
 
20
29
  declare function useIframeBridge(): IframeBridgeHook;
21
30
 
22
- export { type BridgeConfig, type BridgeMessage, type IframeBridgeHook, useIframeBridge };
31
+ declare const WEBVIEW_SHIM: string;
32
+ declare function buildShimUrl(): string;
33
+
34
+ export { type BridgeConfig, type BridgeMessage, type BridgeMessageType, type BridgePushStatus, type IframeBridgeHook, type ThemeMode, WEBVIEW_SHIM, buildShimUrl, useIframeBridge };
package/dist/index.js CHANGED
@@ -2,8 +2,15 @@
2
2
  import { useCallback, useEffect, useRef, useState } from "react";
3
3
  function useIframeBridge() {
4
4
  const [config, setConfig] = useState(null);
5
+ const [pushState, setPushState] = useState(null);
5
6
  const notificationCbRef = useRef(null);
7
+ const readyRef = useRef(false);
6
8
  const isInIframe = typeof window !== "undefined" && window !== window.parent;
9
+ useEffect(() => {
10
+ if (typeof window !== "undefined" && window.__chatBridge?._pushState) {
11
+ setPushState(window.__chatBridge._pushState);
12
+ }
13
+ }, []);
7
14
  const notifyMessage = useCallback(
8
15
  (text) => {
9
16
  if (!isInIframe) return;
@@ -12,9 +19,36 @@ function useIframeBridge() {
12
19
  },
13
20
  [isInIframe]
14
21
  );
22
+ const notifyViewportConfig = useCallback(
23
+ (content) => {
24
+ if (!isInIframe) return;
25
+ const msg = { type: "chat-viewport-config", content };
26
+ window.parent.postMessage(msg, "*");
27
+ },
28
+ [isInIframe]
29
+ );
15
30
  const onNotificationClicked = useCallback((cb) => {
16
31
  notificationCbRef.current = cb;
17
32
  }, []);
33
+ const requestPushSubscribe = useCallback(() => {
34
+ if (!isInIframe) return;
35
+ const msg = { type: "chat-push-subscribe" };
36
+ window.parent.postMessage(msg, "*");
37
+ }, [isInIframe]);
38
+ const requestPushUnsubscribe = useCallback(() => {
39
+ if (!isInIframe) return;
40
+ const msg = { type: "chat-push-unsubscribe" };
41
+ window.parent.postMessage(msg, "*");
42
+ }, [isInIframe]);
43
+ useEffect(() => {
44
+ if (!isInIframe) return;
45
+ if (readyRef.current) return;
46
+ readyRef.current = true;
47
+ const msg = { type: "chat-ready" };
48
+ if (typeof window.parent.postMessage === "function") {
49
+ window.parent.postMessage(msg, "*");
50
+ }
51
+ }, [isInIframe]);
18
52
  useEffect(() => {
19
53
  if (!isInIframe) return;
20
54
  function handleMessage(event) {
@@ -30,14 +64,112 @@ function useIframeBridge() {
30
64
  case "chat-notification-clicked":
31
65
  notificationCbRef.current?.();
32
66
  break;
67
+ case "chat-push-state":
68
+ if (typeof data.status === "string") {
69
+ setPushState(data.status);
70
+ }
71
+ break;
72
+ }
73
+ }
74
+ function handleCustomEvent(event) {
75
+ const detail = event.detail;
76
+ if (!detail || typeof detail !== "object") return;
77
+ if (detail.type === "chat-push-state" && typeof detail.status === "string") {
78
+ setPushState(detail.status);
33
79
  }
34
80
  }
35
81
  window.addEventListener("message", handleMessage);
36
- return () => window.removeEventListener("message", handleMessage);
82
+ window.addEventListener("chat-bridge", handleCustomEvent);
83
+ return () => {
84
+ window.removeEventListener("message", handleMessage);
85
+ window.removeEventListener("chat-bridge", handleCustomEvent);
86
+ };
37
87
  }, [isInIframe]);
38
- return { config, isInIframe, notifyMessage, onNotificationClicked };
88
+ return {
89
+ config,
90
+ isInIframe,
91
+ notifyMessage,
92
+ notifyViewportConfig,
93
+ onNotificationClicked,
94
+ pushState,
95
+ requestPushSubscribe,
96
+ requestPushUnsubscribe
97
+ };
98
+ }
99
+
100
+ // src/shim.ts
101
+ var WEBVIEW_SHIM = `
102
+ (function () {
103
+ 'use strict';
104
+ var _cached = [];
105
+ var _originalPostMessage = window.parent && window.parent.postMessage;
106
+
107
+ function _send(msg) {
108
+ try {
109
+ var json = JSON.stringify(msg);
110
+ } catch (e) {
111
+ var errJson = JSON.stringify({ type: 'chat-error', code: 'SERIALIZE_ERROR', message: 'Failed to serialize message' + e.message });
112
+ try { if (window.parent) window.parent.postMessage(errJson, '*'); } catch (_) {}
113
+ console.error('[ChatBridge] JSON.stringify failed:', e);
114
+ return;
115
+ }
116
+ try {
117
+ if (window.ReactNativeWebView && window.ReactNativeWebView.postMessage) {
118
+ window.ReactNativeWebView.postMessage(json);
119
+ } else if (window.AndroidBridge && window.AndroidBridge.postMessage) {
120
+ window.AndroidBridge.postMessage(json);
121
+ } else if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.chatBridge) {
122
+ window.webkit.messageHandlers.chatBridge.postMessage(msg);
123
+ } else if (_originalPostMessage) {
124
+ _originalPostMessage.call(window.parent, msg, '*');
125
+ } else {
126
+ console.warn('[ChatBridge] No bridge API detected');
127
+ }
128
+ } catch (e) {
129
+ var fallback = JSON.stringify({ type: 'chat-error', code: 'BRIDGE_ERROR', message: 'Bridge postMessage failed: ' + e.message });
130
+ try { if (window.parent) window.parent.postMessage(fallback, '*'); } catch (_) {}
131
+ console.error('[ChatBridge] postMessage failed:', e);
132
+ }
133
+ }
134
+
135
+ window.__chatBridge = {
136
+ _pushState: null,
137
+ send: function (msg) { _send(msg); },
138
+ setPushState: function (status) { window.__chatBridge._pushState = status; },
139
+ };
140
+
141
+ var _batches = 0;
142
+ window.addEventListener('chat-bridge', function (e) {
143
+ if (_batches++ > 0) return;
144
+ requestAnimationFrame(function () {
145
+ _batches = 0;
146
+ });
147
+ var payload = e.detail;
148
+ if (!payload || typeof payload !== 'object') return;
149
+ var type = payload.type;
150
+ if (type === 'chat-config') {
151
+ window.__chatBridge._config = payload;
152
+ } else if (type === 'chat-push-state') {
153
+ window.__chatBridge._pushState = payload.status || null;
154
+ }
155
+ _cached.push(payload);
156
+ });
157
+
158
+ window.addEventListener('message', function (e) {
159
+ var data = e.data;
160
+ if (!data || typeof data !== 'object' || !data.type) return;
161
+ if (data.type === 'chat-push-state') {
162
+ window.__chatBridge._pushState = data.status || null;
163
+ }
164
+ });
165
+ })();
166
+ `;
167
+ function buildShimUrl() {
168
+ return "data:text/javascript;base64," + btoa(WEBVIEW_SHIM);
39
169
  }
40
170
  export {
171
+ WEBVIEW_SHIM,
172
+ buildShimUrl,
41
173
  useIframeBridge
42
174
  };
43
175
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/useIframeBridge.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from \"react\";\nimport type { BridgeConfig, BridgeMessage, IframeBridgeHook } from \"./types\";\n\nexport function useIframeBridge(): IframeBridgeHook {\n const [config, setConfig] = useState<BridgeConfig | null>(null);\n const notificationCbRef = useRef<(() => void) | null>(null);\n\n const isInIframe = typeof window !== \"undefined\" && window !== window.parent;\n\n const notifyMessage = useCallback(\n (text: string) => {\n if (!isInIframe) return;\n const msg: BridgeMessage = { type: \"chat-message\", text };\n window.parent.postMessage(msg, \"*\");\n },\n [isInIframe],\n );\n\n const onNotificationClicked = useCallback((cb: () => void) => {\n notificationCbRef.current = cb;\n }, []);\n\n useEffect(() => {\n if (!isInIframe) return;\n\n function handleMessage(event: MessageEvent) {\n const data = event.data as Record<string, unknown>;\n if (!data || typeof data !== \"object\" || !data.type) return;\n\n switch (data.type) {\n case \"chat-config\": {\n const configData = { ...data };\n delete configData.type;\n setConfig(configData as BridgeConfig);\n break;\n }\n case \"chat-notification-clicked\":\n notificationCbRef.current?.();\n break;\n }\n }\n\n window.addEventListener(\"message\", handleMessage);\n return () => window.removeEventListener(\"message\", handleMessage);\n }, [isInIframe]);\n\n return { config, isInIframe, notifyMessage, onNotificationClicked };\n}\n"],"mappings":";AAAA,SAAS,aAAa,WAAW,QAAQ,gBAAgB;AAGlD,SAAS,kBAAoC;AAClD,QAAM,CAAC,QAAQ,SAAS,IAAI,SAA8B,IAAI;AAC9D,QAAM,oBAAoB,OAA4B,IAAI;AAE1D,QAAM,aAAa,OAAO,WAAW,eAAe,WAAW,OAAO;AAEtE,QAAM,gBAAgB;AAAA,IACpB,CAAC,SAAiB;AAChB,UAAI,CAAC,WAAY;AACjB,YAAM,MAAqB,EAAE,MAAM,gBAAgB,KAAK;AACxD,aAAO,OAAO,YAAY,KAAK,GAAG;AAAA,IACpC;AAAA,IACA,CAAC,UAAU;AAAA,EACb;AAEA,QAAM,wBAAwB,YAAY,CAAC,OAAmB;AAC5D,sBAAkB,UAAU;AAAA,EAC9B,GAAG,CAAC,CAAC;AAEL,YAAU,MAAM;AACd,QAAI,CAAC,WAAY;AAEjB,aAAS,cAAc,OAAqB;AAC1C,YAAM,OAAO,MAAM;AACnB,UAAI,CAAC,QAAQ,OAAO,SAAS,YAAY,CAAC,KAAK,KAAM;AAErD,cAAQ,KAAK,MAAM;AAAA,QACjB,KAAK,eAAe;AAClB,gBAAM,aAAa,EAAE,GAAG,KAAK;AAC7B,iBAAO,WAAW;AAClB,oBAAU,UAA0B;AACpC;AAAA,QACF;AAAA,QACA,KAAK;AACH,4BAAkB,UAAU;AAC5B;AAAA,MACJ;AAAA,IACF;AAEA,WAAO,iBAAiB,WAAW,aAAa;AAChD,WAAO,MAAM,OAAO,oBAAoB,WAAW,aAAa;AAAA,EAClE,GAAG,CAAC,UAAU,CAAC;AAEf,SAAO,EAAE,QAAQ,YAAY,eAAe,sBAAsB;AACpE;","names":[]}
1
+ {"version":3,"sources":["../src/useIframeBridge.ts","../src/shim.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from \"react\";\nimport type { BridgeConfig, BridgeMessage, BridgePushStatus, IframeBridgeHook } from \"./types\";\n\nexport function useIframeBridge(): IframeBridgeHook {\n const [config, setConfig] = useState<BridgeConfig | null>(null);\n const [pushState, setPushState] = useState<BridgePushStatus | null>(null);\n const notificationCbRef = useRef<(() => void) | null>(null);\n const readyRef = useRef(false);\n\n const isInIframe = typeof window !== \"undefined\" && window !== window.parent;\n\n useEffect(() => {\n if (typeof window !== \"undefined\" && (window as any).__chatBridge?._pushState) {\n setPushState((window as any).__chatBridge._pushState);\n }\n }, []);\n\n const notifyMessage = useCallback(\n (text: string) => {\n if (!isInIframe) return;\n const msg: BridgeMessage = { type: \"chat-message\", text };\n window.parent.postMessage(msg, \"*\");\n },\n [isInIframe],\n );\n\n const notifyViewportConfig = useCallback(\n (content: string) => {\n if (!isInIframe) return;\n const msg: BridgeMessage = { type: \"chat-viewport-config\", content };\n window.parent.postMessage(msg, \"*\");\n },\n [isInIframe],\n );\n\n const onNotificationClicked = useCallback((cb: () => void) => {\n notificationCbRef.current = cb;\n }, []);\n\n const requestPushSubscribe = useCallback(() => {\n if (!isInIframe) return;\n const msg: BridgeMessage = { type: \"chat-push-subscribe\" };\n window.parent.postMessage(msg, \"*\");\n }, [isInIframe]);\n\n const requestPushUnsubscribe = useCallback(() => {\n if (!isInIframe) return;\n const msg: BridgeMessage = { type: \"chat-push-unsubscribe\" };\n window.parent.postMessage(msg, \"*\");\n }, [isInIframe]);\n\n useEffect(() => {\n if (!isInIframe) return;\n if (readyRef.current) return;\n readyRef.current = true;\n\n const msg: BridgeMessage = { type: \"chat-ready\" };\n if (typeof window.parent.postMessage === \"function\") {\n window.parent.postMessage(msg, \"*\");\n }\n }, [isInIframe]);\n\n useEffect(() => {\n if (!isInIframe) return;\n\n function handleMessage(event: MessageEvent) {\n const data = event.data as Record<string, unknown>;\n if (!data || typeof data !== \"object\" || !data.type) return;\n\n switch (data.type) {\n case \"chat-config\": {\n const configData = { ...data };\n delete configData.type;\n setConfig(configData as BridgeConfig);\n break;\n }\n case \"chat-notification-clicked\":\n notificationCbRef.current?.();\n break;\n case \"chat-push-state\":\n if (typeof data.status === \"string\") {\n setPushState(data.status as BridgePushStatus);\n }\n break;\n }\n }\n\n function handleCustomEvent(event: Event) {\n const detail = (event as CustomEvent).detail;\n if (!detail || typeof detail !== \"object\") return;\n if (detail.type === \"chat-push-state\" && typeof detail.status === \"string\") {\n setPushState(detail.status as BridgePushStatus);\n }\n }\n\n window.addEventListener(\"message\", handleMessage);\n window.addEventListener(\"chat-bridge\", handleCustomEvent);\n return () => {\n window.removeEventListener(\"message\", handleMessage);\n window.removeEventListener(\"chat-bridge\", handleCustomEvent);\n };\n }, [isInIframe]);\n\n return {\n config,\n isInIframe,\n notifyMessage,\n notifyViewportConfig,\n onNotificationClicked,\n pushState,\n requestPushSubscribe,\n requestPushUnsubscribe,\n };\n}\n","export const WEBVIEW_SHIM: string = `\n(function () {\n 'use strict';\n var _cached = [];\n var _originalPostMessage = window.parent && window.parent.postMessage;\n\n function _send(msg) {\n try {\n var json = JSON.stringify(msg);\n } catch (e) {\n var errJson = JSON.stringify({ type: 'chat-error', code: 'SERIALIZE_ERROR', message: 'Failed to serialize message' + e.message });\n try { if (window.parent) window.parent.postMessage(errJson, '*'); } catch (_) {}\n console.error('[ChatBridge] JSON.stringify failed:', e);\n return;\n }\n try {\n if (window.ReactNativeWebView && window.ReactNativeWebView.postMessage) {\n window.ReactNativeWebView.postMessage(json);\n } else if (window.AndroidBridge && window.AndroidBridge.postMessage) {\n window.AndroidBridge.postMessage(json);\n } else if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.chatBridge) {\n window.webkit.messageHandlers.chatBridge.postMessage(msg);\n } else if (_originalPostMessage) {\n _originalPostMessage.call(window.parent, msg, '*');\n } else {\n console.warn('[ChatBridge] No bridge API detected');\n }\n } catch (e) {\n var fallback = JSON.stringify({ type: 'chat-error', code: 'BRIDGE_ERROR', message: 'Bridge postMessage failed: ' + e.message });\n try { if (window.parent) window.parent.postMessage(fallback, '*'); } catch (_) {}\n console.error('[ChatBridge] postMessage failed:', e);\n }\n }\n\n window.__chatBridge = {\n _pushState: null,\n send: function (msg) { _send(msg); },\n setPushState: function (status) { window.__chatBridge._pushState = status; },\n };\n\n var _batches = 0;\n window.addEventListener('chat-bridge', function (e) {\n if (_batches++ > 0) return;\n requestAnimationFrame(function () {\n _batches = 0;\n });\n var payload = e.detail;\n if (!payload || typeof payload !== 'object') return;\n var type = payload.type;\n if (type === 'chat-config') {\n window.__chatBridge._config = payload;\n } else if (type === 'chat-push-state') {\n window.__chatBridge._pushState = payload.status || null;\n }\n _cached.push(payload);\n });\n\n window.addEventListener('message', function (e) {\n var data = e.data;\n if (!data || typeof data !== 'object' || !data.type) return;\n if (data.type === 'chat-push-state') {\n window.__chatBridge._pushState = data.status || null;\n }\n });\n})();\n`;\n\nexport function buildShimUrl(): string {\n return \"data:text/javascript;base64,\" + btoa(WEBVIEW_SHIM);\n}\n"],"mappings":"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","names":[]}
package/dist/shim.cjs ADDED
@@ -0,0 +1,101 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/shim.ts
21
+ var shim_exports = {};
22
+ __export(shim_exports, {
23
+ WEBVIEW_SHIM: () => WEBVIEW_SHIM,
24
+ buildShimUrl: () => buildShimUrl
25
+ });
26
+ module.exports = __toCommonJS(shim_exports);
27
+ var WEBVIEW_SHIM = `
28
+ (function () {
29
+ 'use strict';
30
+ var _cached = [];
31
+ var _originalPostMessage = window.parent && window.parent.postMessage;
32
+
33
+ function _send(msg) {
34
+ try {
35
+ var json = JSON.stringify(msg);
36
+ } catch (e) {
37
+ var errJson = JSON.stringify({ type: 'chat-error', code: 'SERIALIZE_ERROR', message: 'Failed to serialize message' + e.message });
38
+ try { if (window.parent) window.parent.postMessage(errJson, '*'); } catch (_) {}
39
+ console.error('[ChatBridge] JSON.stringify failed:', e);
40
+ return;
41
+ }
42
+ try {
43
+ if (window.ReactNativeWebView && window.ReactNativeWebView.postMessage) {
44
+ window.ReactNativeWebView.postMessage(json);
45
+ } else if (window.AndroidBridge && window.AndroidBridge.postMessage) {
46
+ window.AndroidBridge.postMessage(json);
47
+ } else if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.chatBridge) {
48
+ window.webkit.messageHandlers.chatBridge.postMessage(msg);
49
+ } else if (_originalPostMessage) {
50
+ _originalPostMessage.call(window.parent, msg, '*');
51
+ } else {
52
+ console.warn('[ChatBridge] No bridge API detected');
53
+ }
54
+ } catch (e) {
55
+ var fallback = JSON.stringify({ type: 'chat-error', code: 'BRIDGE_ERROR', message: 'Bridge postMessage failed: ' + e.message });
56
+ try { if (window.parent) window.parent.postMessage(fallback, '*'); } catch (_) {}
57
+ console.error('[ChatBridge] postMessage failed:', e);
58
+ }
59
+ }
60
+
61
+ window.__chatBridge = {
62
+ _pushState: null,
63
+ send: function (msg) { _send(msg); },
64
+ setPushState: function (status) { window.__chatBridge._pushState = status; },
65
+ };
66
+
67
+ var _batches = 0;
68
+ window.addEventListener('chat-bridge', function (e) {
69
+ if (_batches++ > 0) return;
70
+ requestAnimationFrame(function () {
71
+ _batches = 0;
72
+ });
73
+ var payload = e.detail;
74
+ if (!payload || typeof payload !== 'object') return;
75
+ var type = payload.type;
76
+ if (type === 'chat-config') {
77
+ window.__chatBridge._config = payload;
78
+ } else if (type === 'chat-push-state') {
79
+ window.__chatBridge._pushState = payload.status || null;
80
+ }
81
+ _cached.push(payload);
82
+ });
83
+
84
+ window.addEventListener('message', function (e) {
85
+ var data = e.data;
86
+ if (!data || typeof data !== 'object' || !data.type) return;
87
+ if (data.type === 'chat-push-state') {
88
+ window.__chatBridge._pushState = data.status || null;
89
+ }
90
+ });
91
+ })();
92
+ `;
93
+ function buildShimUrl() {
94
+ return "data:text/javascript;base64," + btoa(WEBVIEW_SHIM);
95
+ }
96
+ // Annotate the CommonJS export names for ESM import in node:
97
+ 0 && (module.exports = {
98
+ WEBVIEW_SHIM,
99
+ buildShimUrl
100
+ });
101
+ //# sourceMappingURL=shim.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/shim.ts"],"sourcesContent":["export const WEBVIEW_SHIM: string = `\n(function () {\n 'use strict';\n var _cached = [];\n var _originalPostMessage = window.parent && window.parent.postMessage;\n\n function _send(msg) {\n try {\n var json = JSON.stringify(msg);\n } catch (e) {\n var errJson = JSON.stringify({ type: 'chat-error', code: 'SERIALIZE_ERROR', message: 'Failed to serialize message' + e.message });\n try { if (window.parent) window.parent.postMessage(errJson, '*'); } catch (_) {}\n console.error('[ChatBridge] JSON.stringify failed:', e);\n return;\n }\n try {\n if (window.ReactNativeWebView && window.ReactNativeWebView.postMessage) {\n window.ReactNativeWebView.postMessage(json);\n } else if (window.AndroidBridge && window.AndroidBridge.postMessage) {\n window.AndroidBridge.postMessage(json);\n } else if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.chatBridge) {\n window.webkit.messageHandlers.chatBridge.postMessage(msg);\n } else if (_originalPostMessage) {\n _originalPostMessage.call(window.parent, msg, '*');\n } else {\n console.warn('[ChatBridge] No bridge API detected');\n }\n } catch (e) {\n var fallback = JSON.stringify({ type: 'chat-error', code: 'BRIDGE_ERROR', message: 'Bridge postMessage failed: ' + e.message });\n try { if (window.parent) window.parent.postMessage(fallback, '*'); } catch (_) {}\n console.error('[ChatBridge] postMessage failed:', e);\n }\n }\n\n window.__chatBridge = {\n _pushState: null,\n send: function (msg) { _send(msg); },\n setPushState: function (status) { window.__chatBridge._pushState = status; },\n };\n\n var _batches = 0;\n window.addEventListener('chat-bridge', function (e) {\n if (_batches++ > 0) return;\n requestAnimationFrame(function () {\n _batches = 0;\n });\n var payload = e.detail;\n if (!payload || typeof payload !== 'object') return;\n var type = payload.type;\n if (type === 'chat-config') {\n window.__chatBridge._config = payload;\n } else if (type === 'chat-push-state') {\n window.__chatBridge._pushState = payload.status || null;\n }\n _cached.push(payload);\n });\n\n window.addEventListener('message', function (e) {\n var data = e.data;\n if (!data || typeof data !== 'object' || !data.type) return;\n if (data.type === 'chat-push-state') {\n window.__chatBridge._pushState = data.status || null;\n }\n });\n})();\n`;\n\nexport function buildShimUrl(): string {\n return \"data:text/javascript;base64,\" + btoa(WEBVIEW_SHIM);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAO,IAAM,eAAuB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmE7B,SAAS,eAAuB;AACrC,SAAO,iCAAiC,KAAK,YAAY;AAC3D;","names":[]}
package/dist/shim.js ADDED
@@ -0,0 +1,75 @@
1
+ // src/shim.ts
2
+ var WEBVIEW_SHIM = `
3
+ (function () {
4
+ 'use strict';
5
+ var _cached = [];
6
+ var _originalPostMessage = window.parent && window.parent.postMessage;
7
+
8
+ function _send(msg) {
9
+ try {
10
+ var json = JSON.stringify(msg);
11
+ } catch (e) {
12
+ var errJson = JSON.stringify({ type: 'chat-error', code: 'SERIALIZE_ERROR', message: 'Failed to serialize message' + e.message });
13
+ try { if (window.parent) window.parent.postMessage(errJson, '*'); } catch (_) {}
14
+ console.error('[ChatBridge] JSON.stringify failed:', e);
15
+ return;
16
+ }
17
+ try {
18
+ if (window.ReactNativeWebView && window.ReactNativeWebView.postMessage) {
19
+ window.ReactNativeWebView.postMessage(json);
20
+ } else if (window.AndroidBridge && window.AndroidBridge.postMessage) {
21
+ window.AndroidBridge.postMessage(json);
22
+ } else if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.chatBridge) {
23
+ window.webkit.messageHandlers.chatBridge.postMessage(msg);
24
+ } else if (_originalPostMessage) {
25
+ _originalPostMessage.call(window.parent, msg, '*');
26
+ } else {
27
+ console.warn('[ChatBridge] No bridge API detected');
28
+ }
29
+ } catch (e) {
30
+ var fallback = JSON.stringify({ type: 'chat-error', code: 'BRIDGE_ERROR', message: 'Bridge postMessage failed: ' + e.message });
31
+ try { if (window.parent) window.parent.postMessage(fallback, '*'); } catch (_) {}
32
+ console.error('[ChatBridge] postMessage failed:', e);
33
+ }
34
+ }
35
+
36
+ window.__chatBridge = {
37
+ _pushState: null,
38
+ send: function (msg) { _send(msg); },
39
+ setPushState: function (status) { window.__chatBridge._pushState = status; },
40
+ };
41
+
42
+ var _batches = 0;
43
+ window.addEventListener('chat-bridge', function (e) {
44
+ if (_batches++ > 0) return;
45
+ requestAnimationFrame(function () {
46
+ _batches = 0;
47
+ });
48
+ var payload = e.detail;
49
+ if (!payload || typeof payload !== 'object') return;
50
+ var type = payload.type;
51
+ if (type === 'chat-config') {
52
+ window.__chatBridge._config = payload;
53
+ } else if (type === 'chat-push-state') {
54
+ window.__chatBridge._pushState = payload.status || null;
55
+ }
56
+ _cached.push(payload);
57
+ });
58
+
59
+ window.addEventListener('message', function (e) {
60
+ var data = e.data;
61
+ if (!data || typeof data !== 'object' || !data.type) return;
62
+ if (data.type === 'chat-push-state') {
63
+ window.__chatBridge._pushState = data.status || null;
64
+ }
65
+ });
66
+ })();
67
+ `;
68
+ function buildShimUrl() {
69
+ return "data:text/javascript;base64," + btoa(WEBVIEW_SHIM);
70
+ }
71
+ export {
72
+ WEBVIEW_SHIM,
73
+ buildShimUrl
74
+ };
75
+ //# sourceMappingURL=shim.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/shim.ts"],"sourcesContent":["export const WEBVIEW_SHIM: string = `\n(function () {\n 'use strict';\n var _cached = [];\n var _originalPostMessage = window.parent && window.parent.postMessage;\n\n function _send(msg) {\n try {\n var json = JSON.stringify(msg);\n } catch (e) {\n var errJson = JSON.stringify({ type: 'chat-error', code: 'SERIALIZE_ERROR', message: 'Failed to serialize message' + e.message });\n try { if (window.parent) window.parent.postMessage(errJson, '*'); } catch (_) {}\n console.error('[ChatBridge] JSON.stringify failed:', e);\n return;\n }\n try {\n if (window.ReactNativeWebView && window.ReactNativeWebView.postMessage) {\n window.ReactNativeWebView.postMessage(json);\n } else if (window.AndroidBridge && window.AndroidBridge.postMessage) {\n window.AndroidBridge.postMessage(json);\n } else if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.chatBridge) {\n window.webkit.messageHandlers.chatBridge.postMessage(msg);\n } else if (_originalPostMessage) {\n _originalPostMessage.call(window.parent, msg, '*');\n } else {\n console.warn('[ChatBridge] No bridge API detected');\n }\n } catch (e) {\n var fallback = JSON.stringify({ type: 'chat-error', code: 'BRIDGE_ERROR', message: 'Bridge postMessage failed: ' + e.message });\n try { if (window.parent) window.parent.postMessage(fallback, '*'); } catch (_) {}\n console.error('[ChatBridge] postMessage failed:', e);\n }\n }\n\n window.__chatBridge = {\n _pushState: null,\n send: function (msg) { _send(msg); },\n setPushState: function (status) { window.__chatBridge._pushState = status; },\n };\n\n var _batches = 0;\n window.addEventListener('chat-bridge', function (e) {\n if (_batches++ > 0) return;\n requestAnimationFrame(function () {\n _batches = 0;\n });\n var payload = e.detail;\n if (!payload || typeof payload !== 'object') return;\n var type = payload.type;\n if (type === 'chat-config') {\n window.__chatBridge._config = payload;\n } else if (type === 'chat-push-state') {\n window.__chatBridge._pushState = payload.status || null;\n }\n _cached.push(payload);\n });\n\n window.addEventListener('message', function (e) {\n var data = e.data;\n if (!data || typeof data !== 'object' || !data.type) return;\n if (data.type === 'chat-push-state') {\n window.__chatBridge._pushState = data.status || null;\n }\n });\n})();\n`;\n\nexport function buildShimUrl(): string {\n return \"data:text/javascript;base64,\" + btoa(WEBVIEW_SHIM);\n}\n"],"mappings":";AAAO,IAAM,eAAuB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmE7B,SAAS,eAAuB;AACrC,SAAO,iCAAiC,KAAK,YAAY;AAC3D;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bootdesk/chat-widget-bridge",
3
- "version": "0.3.3",
3
+ "version": "0.3.5",
4
4
  "description": "Iframe bridge for BootDesk Chat SDK - enables embedding the chat widget in an iframe with cross-frame communication via postMessage",
5
5
  "repository": "https://github.com/bootdesk/chat-sdk",
6
6
  "type": "module",
@@ -16,6 +16,10 @@
16
16
  "./embed-chat": {
17
17
  "import": "./dist/embed-chat.js",
18
18
  "require": "./dist/embed-chat.cjs"
19
+ },
20
+ "./shim": {
21
+ "import": "./dist/shim.js",
22
+ "require": "./dist/shim.cjs"
19
23
  }
20
24
  },
21
25
  "files": [