@bootdesk/chat-widget-bridge 0.1.0

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 ADDED
@@ -0,0 +1,152 @@
1
+ # @bootdesk/chat-widget-bridge
2
+
3
+ Iframe bridge for BootDesk Chat SDK — enables embedding the chat widget in an iframe with cross-frame communication via `postMessage`.
4
+
5
+ Includes:
6
+ - **`useIframeBridge`** — React hook for iframe communication
7
+ - **`embed-chat`** — Vanilla JS embed script that creates a floating chat button and iframe dynamically
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ npm install @bootdesk/chat-widget-bridge
13
+ ```
14
+
15
+ Peer dependency: `react` (only needed for `useIframeBridge`).
16
+
17
+ ## Usage
18
+
19
+ ### In the iframe (child)
20
+
21
+ ```tsx
22
+ import { useIframeBridge } from "@bootdesk/chat-widget-bridge";
23
+
24
+ function Chat() {
25
+ const { config, isInIframe, notifyMessage, notifyViewportConfig, onNotificationClicked } =
26
+ useIframeBridge();
27
+
28
+ // config.title, config.locale, config.placeholder, config.theme.mode
29
+ // are set by the parent page via postMessage.
30
+ // notifyViewportConfig tells the parent to add/remove
31
+ // interactive-widget=resizes-content on the viewport meta (Android only).
32
+ // iOS doesn't support this — it uses dvh units instead.
33
+ }
34
+ ```
35
+
36
+ ### In the parent page
37
+
38
+ ```js
39
+ const iframe = document.getElementById("chat-iframe");
40
+
41
+ // Send config to iframe
42
+ iframe.contentWindow.postMessage(
43
+ {
44
+ type: "chat-config",
45
+ title: "Support Chat",
46
+ locale: "pt-BR",
47
+ theme: { mode: "auto" },
48
+ },
49
+ "*",
50
+ );
51
+
52
+ // Listen for messages from iframe
53
+ window.addEventListener("message", (event) => {
54
+ if (event.data?.type === "chat-message") {
55
+ console.log("User sent:", event.data.text);
56
+ }
57
+ if (event.data?.type === "chat-viewport-config") {
58
+ const meta = document.querySelector('meta[name="viewport"]');
59
+ if (!meta) return;
60
+ const current = meta.getAttribute("content") || "";
61
+ if (event.data.content) {
62
+ if (!current.includes(event.data.content)) {
63
+ meta.setAttribute("content", current + (current ? ", " : "") + event.data.content);
64
+ }
65
+ } else {
66
+ meta.setAttribute(
67
+ "content",
68
+ current.replace(/,?\s*interactive-widget=[^,]*/g, "").replace(/^,\s*/, ""),
69
+ );
70
+ }
71
+ }
72
+ });
73
+
74
+ // Trigger notification click in iframe
75
+ iframe.contentWindow.postMessage(
76
+ { type: "chat-notification-clicked" },
77
+ "*",
78
+ );
79
+ ```
80
+
81
+ ## API
82
+
83
+ | Return value | Description |
84
+ |---|---|
85
+ | `config` | `BridgeConfig \| null` — config from parent (title, locale, placeholder, theme) |
86
+ | `isInIframe` | `boolean` — `true` when window !== window.parent |
87
+ | `notifyMessage(text)` | Sends `{ type: "chat-message", text }` to parent |
88
+ | `notifyViewportConfig(content)` | Sends `{ type: "chat-viewport-config", content }` to parent (Android keyboard support via `interactive-widget=resizes-content`; iOS handles this via `dvh` units) |
89
+ | `onNotificationClicked(cb)` | Registers callback for `chat-notification-clicked` from parent |
90
+
91
+ ## Message Protocol
92
+
93
+ | Direction | type | Payload |
94
+ |---|---|---|
95
+ | Parent → Child | `chat-config` | `{ title?, locale?, placeholder?, theme?: { mode? } }` |
96
+ | Parent → Child | `chat-notification-clicked` | `{}` |
97
+ | Child → Parent | `chat-message` | `{ text: string }` |
98
+ | Child → Parent | `chat-close` | `{}` — requests parent to close/hide the iframe |
99
+ | Child → Parent | `chat-viewport-config` | `{ content: string }` — asks parent to add `interactive-widget=resizes-content` on viewport meta (Android only; iOS uses `dvh` units) |
100
+
101
+ ## Embed Script (`embed-chat`)
102
+
103
+ Self-contained vanilla JS script that creates a floating chat button, overlay, and an iframe dynamically on any page.
104
+
105
+ ### Usage
106
+
107
+ As a module import (Vite/webpack):
108
+ ```js
109
+ import "@bootdesk/chat-widget-bridge/embed-chat";
110
+
111
+ ChatSDK.initialize();
112
+ ```
113
+
114
+ Via a `<script>` tag:
115
+ ```html
116
+ <script src="https://cdn.example.com/embed-chat.js"></script>
117
+ <script>
118
+ ChatSDK.initialize({
119
+ iframeSrc: "/my-chat-page",
120
+ title: "Support Chat",
121
+ placeholder: "How can we help?",
122
+ buttonInnerHtml: '<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><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>',
123
+ buttonStyle: { background: "#ff4433" },
124
+ overlayStyle: { background: "rgba(0,0,0,0.5)" },
125
+ });
126
+ </script>
127
+ ```
128
+
129
+ ### Behavior
130
+
131
+ - Exposes `window.ChatSDK.initialize()` to create a floating chat button, overlay, and iframe
132
+ - On click, opens a panel with the iframe (slide + fade animation)
133
+ - On small screens (<800px) the iframe goes fullscreen and the overlay is hidden
134
+ - Reads `localStorage` key `chat-theme` and passes it to the iframe via `chat-config`
135
+ - Listens for `chat-close` message from the iframe and closes the panel
136
+ - Logs `chat-message` events from the iframe to the console
137
+ - Handles `chat-viewport-config` to update the parent page's viewport meta for Android keyboard (`interactive-widget=resizes-content`; iOS uses `dvh` units)
138
+
139
+ ### Configuration
140
+
141
+ | Option | Type | Default | Description |
142
+ |---|---|---|---|
143
+ | `iframeSrc` | `string` | `"/chat-iframe"` | URL for the iframe src |
144
+ | `title` | `string` | `"Chat"` | Title sent to the iframe via `chat-config` |
145
+ | `placeholder` | `string` | `"Type a message..."` | Placeholder sent to the iframe via `chat-config` |
146
+ | `buttonInnerHtml` | `string` | Chat bubble SVG | Inner HTML of the floating button |
147
+ | `buttonStyle` | `object` | Default button styles | CSS overrides for the button |
148
+ | `overlayStyle` | `object` | Default overlay styles | CSS overrides for the overlay |
149
+
150
+ ## License
151
+
152
+ MIT
@@ -0,0 +1,195 @@
1
+ "use strict";
2
+
3
+ // src/embed-chat.js
4
+ (function() {
5
+ "use strict";
6
+ var DEFAULTS = {
7
+ iframeSrc: "/chat-iframe",
8
+ title: "Chat",
9
+ placeholder: "Type a message...",
10
+ buttonInnerHtml: '<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>',
11
+ buttonStyle: {
12
+ position: "fixed",
13
+ bottom: "24px",
14
+ right: "24px",
15
+ width: "56px",
16
+ height: "56px",
17
+ borderRadius: "50%",
18
+ border: "none",
19
+ background: "var(--chat-primary, #6366f1)",
20
+ color: "#fff",
21
+ cursor: "pointer",
22
+ display: "flex",
23
+ alignItems: "center",
24
+ justifyContent: "center",
25
+ boxShadow: "0 4px 16px rgba(0,0,0,0.2)",
26
+ zIndex: "2147483646",
27
+ transition: "transform 0.2s, opacity 0.2s"
28
+ },
29
+ overlayStyle: {
30
+ position: "fixed",
31
+ inset: "0",
32
+ background: "rgba(0,0,0,0.3)",
33
+ zIndex: "2147483646",
34
+ opacity: "0",
35
+ transition: "opacity 0.2s",
36
+ pointerEvents: "none"
37
+ }
38
+ };
39
+ var state = {
40
+ opts: null,
41
+ button: null,
42
+ iframe: null,
43
+ overlay: null,
44
+ isOpen: false,
45
+ originalViewport: void 0
46
+ };
47
+ function mergeStyles(base, overrides) {
48
+ var result = {};
49
+ for (var key in base) result[key] = base[key];
50
+ if (overrides) {
51
+ for (var key in overrides) result[key] = overrides[key];
52
+ }
53
+ return result;
54
+ }
55
+ function createButton() {
56
+ var opts = state.opts;
57
+ state.button = document.createElement("button");
58
+ state.button.setAttribute("data-embed-chat-btn", "");
59
+ state.button.setAttribute("aria-label", "Open chat");
60
+ state.button.setAttribute("aria-expanded", "false");
61
+ state.button.innerHTML = opts.buttonInnerHtml;
62
+ Object.assign(state.button.style, mergeStyles(DEFAULTS.buttonStyle, opts.buttonStyle));
63
+ state.button.addEventListener("mouseenter", function() {
64
+ state.button.style.transform = "scale(1.05)";
65
+ });
66
+ state.button.addEventListener("mouseleave", function() {
67
+ state.button.style.transform = "";
68
+ });
69
+ state.button.addEventListener("click", toggle);
70
+ state.button.addEventListener("keydown", function(e) {
71
+ if (e.key === "Enter" || e.key === " ") {
72
+ e.preventDefault();
73
+ toggle();
74
+ }
75
+ });
76
+ document.body.appendChild(state.button);
77
+ }
78
+ function createOverlay() {
79
+ var opts = state.opts;
80
+ state.overlay = document.createElement("div");
81
+ state.overlay.setAttribute("data-embed-chat-overlay", "");
82
+ Object.assign(state.overlay.style, mergeStyles(DEFAULTS.overlayStyle, opts.overlayStyle));
83
+ state.overlay.addEventListener("click", toggle);
84
+ document.body.appendChild(state.overlay);
85
+ }
86
+ function createIframe() {
87
+ var opts = state.opts;
88
+ state.iframe = document.createElement("iframe");
89
+ state.iframe.setAttribute("data-embed-chat-iframe", "");
90
+ state.iframe.setAttribute("title", "Chat Widget");
91
+ state.iframe.setAttribute("role", "dialog");
92
+ state.iframe.setAttribute("aria-modal", "true");
93
+ state.iframe.setAttribute("allow", "clipboard-write; microphone");
94
+ state.iframe.src = opts.iframeSrc;
95
+ Object.assign(state.iframe.style, {
96
+ position: "fixed",
97
+ bottom: "96px",
98
+ right: "24px",
99
+ width: "420px",
100
+ height: "600px",
101
+ maxWidth: "calc(100dvw - 48px)",
102
+ maxHeight: "calc(100dvh - 120px)",
103
+ border: "none",
104
+ borderRadius: "16px",
105
+ boxShadow: "0 8px 32px rgba(0,0,0,0.15)",
106
+ zIndex: "2147483647",
107
+ opacity: "0",
108
+ transform: "translateY(16px) scale(0.96)",
109
+ transition: "opacity 0.2s, transform 0.25s",
110
+ pointerEvents: "none",
111
+ background: "#fff"
112
+ });
113
+ document.body.appendChild(state.iframe);
114
+ state.iframe.addEventListener("load", function() {
115
+ var savedTheme = "auto";
116
+ try {
117
+ var stored = localStorage.getItem("chat-theme");
118
+ if (stored === "light" || stored === "dark" || stored === "auto") savedTheme = stored;
119
+ } catch {
120
+ }
121
+ state.iframe.contentWindow.postMessage(
122
+ { type: "chat-config", title: opts.title, placeholder: opts.placeholder, theme: { mode: savedTheme } },
123
+ "*"
124
+ );
125
+ });
126
+ }
127
+ function close() {
128
+ if (!state.isOpen) return;
129
+ toggle();
130
+ }
131
+ function toggle() {
132
+ state.isOpen = !state.isOpen;
133
+ var open = state.isOpen;
134
+ state.button.setAttribute("aria-expanded", String(open));
135
+ state.iframe.style.opacity = open ? "1" : "0";
136
+ state.iframe.style.transform = open ? "translateY(0) scale(1)" : "translateY(16px) scale(0.96)";
137
+ state.iframe.style.pointerEvents = open ? "auto" : "none";
138
+ state.overlay.style.opacity = open ? "1" : "0";
139
+ state.overlay.style.pointerEvents = open ? "auto" : "none";
140
+ state.button.style.transform = open ? "scale(0)" : "";
141
+ state.button.style.opacity = open ? "0" : "1";
142
+ state.button.style.pointerEvents = open ? "none" : "auto";
143
+ document.body.style.overflow = open ? "hidden" : "";
144
+ if (open) state.iframe.focus();
145
+ }
146
+ function handleMessage(event) {
147
+ if (!state.iframe || event.source !== state.iframe.contentWindow) return;
148
+ var data = event.data || {};
149
+ if (data.type === "chat-message") {
150
+ console.log("[Embed Chat] Message:", data.text);
151
+ }
152
+ if (data.type === "chat-close") {
153
+ close();
154
+ }
155
+ if (data.type === "chat-viewport-config") {
156
+ var meta = document.querySelector('meta[name="viewport"]');
157
+ if (!meta) return;
158
+ var current = meta.getAttribute("content") || "";
159
+ if (data.content) {
160
+ if (state.originalViewport === void 0) state.originalViewport = current;
161
+ if (!current.includes(data.content)) {
162
+ meta.setAttribute("content", current + (current ? ", " : "") + data.content);
163
+ }
164
+ } else {
165
+ meta.setAttribute("content", state.originalViewport ?? current);
166
+ state.originalViewport = void 0;
167
+ }
168
+ }
169
+ }
170
+ function initialize(opts) {
171
+ if (document.querySelector("[data-embed-chat-btn]")) return;
172
+ state.opts = {};
173
+ for (var key in DEFAULTS) {
174
+ state.opts[key] = DEFAULTS[key];
175
+ }
176
+ if (opts) {
177
+ for (var key in opts) {
178
+ if (key === "buttonStyle" || key === "overlayStyle") {
179
+ state.opts[key] = mergeStyles(state.opts[key] || {}, opts[key]);
180
+ } else if (opts[key] !== void 0) {
181
+ state.opts[key] = opts[key];
182
+ }
183
+ }
184
+ }
185
+ var style = document.createElement("style");
186
+ 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
+ document.head.appendChild(style);
188
+ createOverlay();
189
+ createIframe();
190
+ createButton();
191
+ window.addEventListener("message", handleMessage);
192
+ }
193
+ window.ChatSDK = { initialize };
194
+ })();
195
+ //# sourceMappingURL=embed-chat.cjs.map
@@ -0,0 +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 key in overrides) result[key] = overrides[key];\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 key in opts) {\n if (key === \"buttonStyle\" || key === \"overlayStyle\") {\n state.opts[key] = mergeStyles(state.opts[key] || {}, opts[key]);\n } else if (opts[key] !== undefined) {\n state.opts[key] = opts[key];\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":[]}
@@ -0,0 +1,193 @@
1
+ // src/embed-chat.js
2
+ (function() {
3
+ "use strict";
4
+ var DEFAULTS = {
5
+ iframeSrc: "/chat-iframe",
6
+ title: "Chat",
7
+ placeholder: "Type a message...",
8
+ buttonInnerHtml: '<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>',
9
+ buttonStyle: {
10
+ position: "fixed",
11
+ bottom: "24px",
12
+ right: "24px",
13
+ width: "56px",
14
+ height: "56px",
15
+ borderRadius: "50%",
16
+ border: "none",
17
+ background: "var(--chat-primary, #6366f1)",
18
+ color: "#fff",
19
+ cursor: "pointer",
20
+ display: "flex",
21
+ alignItems: "center",
22
+ justifyContent: "center",
23
+ boxShadow: "0 4px 16px rgba(0,0,0,0.2)",
24
+ zIndex: "2147483646",
25
+ transition: "transform 0.2s, opacity 0.2s"
26
+ },
27
+ overlayStyle: {
28
+ position: "fixed",
29
+ inset: "0",
30
+ background: "rgba(0,0,0,0.3)",
31
+ zIndex: "2147483646",
32
+ opacity: "0",
33
+ transition: "opacity 0.2s",
34
+ pointerEvents: "none"
35
+ }
36
+ };
37
+ var state = {
38
+ opts: null,
39
+ button: null,
40
+ iframe: null,
41
+ overlay: null,
42
+ isOpen: false,
43
+ originalViewport: void 0
44
+ };
45
+ function mergeStyles(base, overrides) {
46
+ var result = {};
47
+ for (var key in base) result[key] = base[key];
48
+ if (overrides) {
49
+ for (var key in overrides) result[key] = overrides[key];
50
+ }
51
+ return result;
52
+ }
53
+ function createButton() {
54
+ var opts = state.opts;
55
+ state.button = document.createElement("button");
56
+ state.button.setAttribute("data-embed-chat-btn", "");
57
+ state.button.setAttribute("aria-label", "Open chat");
58
+ state.button.setAttribute("aria-expanded", "false");
59
+ state.button.innerHTML = opts.buttonInnerHtml;
60
+ Object.assign(state.button.style, mergeStyles(DEFAULTS.buttonStyle, opts.buttonStyle));
61
+ state.button.addEventListener("mouseenter", function() {
62
+ state.button.style.transform = "scale(1.05)";
63
+ });
64
+ state.button.addEventListener("mouseleave", function() {
65
+ state.button.style.transform = "";
66
+ });
67
+ state.button.addEventListener("click", toggle);
68
+ state.button.addEventListener("keydown", function(e) {
69
+ if (e.key === "Enter" || e.key === " ") {
70
+ e.preventDefault();
71
+ toggle();
72
+ }
73
+ });
74
+ document.body.appendChild(state.button);
75
+ }
76
+ function createOverlay() {
77
+ var opts = state.opts;
78
+ state.overlay = document.createElement("div");
79
+ state.overlay.setAttribute("data-embed-chat-overlay", "");
80
+ Object.assign(state.overlay.style, mergeStyles(DEFAULTS.overlayStyle, opts.overlayStyle));
81
+ state.overlay.addEventListener("click", toggle);
82
+ document.body.appendChild(state.overlay);
83
+ }
84
+ function createIframe() {
85
+ var opts = state.opts;
86
+ state.iframe = document.createElement("iframe");
87
+ state.iframe.setAttribute("data-embed-chat-iframe", "");
88
+ state.iframe.setAttribute("title", "Chat Widget");
89
+ state.iframe.setAttribute("role", "dialog");
90
+ state.iframe.setAttribute("aria-modal", "true");
91
+ state.iframe.setAttribute("allow", "clipboard-write; microphone");
92
+ state.iframe.src = opts.iframeSrc;
93
+ Object.assign(state.iframe.style, {
94
+ position: "fixed",
95
+ bottom: "96px",
96
+ right: "24px",
97
+ width: "420px",
98
+ height: "600px",
99
+ maxWidth: "calc(100dvw - 48px)",
100
+ maxHeight: "calc(100dvh - 120px)",
101
+ border: "none",
102
+ borderRadius: "16px",
103
+ boxShadow: "0 8px 32px rgba(0,0,0,0.15)",
104
+ zIndex: "2147483647",
105
+ opacity: "0",
106
+ transform: "translateY(16px) scale(0.96)",
107
+ transition: "opacity 0.2s, transform 0.25s",
108
+ pointerEvents: "none",
109
+ background: "#fff"
110
+ });
111
+ document.body.appendChild(state.iframe);
112
+ state.iframe.addEventListener("load", function() {
113
+ var savedTheme = "auto";
114
+ try {
115
+ var stored = localStorage.getItem("chat-theme");
116
+ if (stored === "light" || stored === "dark" || stored === "auto") savedTheme = stored;
117
+ } catch {
118
+ }
119
+ state.iframe.contentWindow.postMessage(
120
+ { type: "chat-config", title: opts.title, placeholder: opts.placeholder, theme: { mode: savedTheme } },
121
+ "*"
122
+ );
123
+ });
124
+ }
125
+ function close() {
126
+ if (!state.isOpen) return;
127
+ toggle();
128
+ }
129
+ function toggle() {
130
+ state.isOpen = !state.isOpen;
131
+ var open = state.isOpen;
132
+ state.button.setAttribute("aria-expanded", String(open));
133
+ state.iframe.style.opacity = open ? "1" : "0";
134
+ state.iframe.style.transform = open ? "translateY(0) scale(1)" : "translateY(16px) scale(0.96)";
135
+ state.iframe.style.pointerEvents = open ? "auto" : "none";
136
+ state.overlay.style.opacity = open ? "1" : "0";
137
+ state.overlay.style.pointerEvents = open ? "auto" : "none";
138
+ state.button.style.transform = open ? "scale(0)" : "";
139
+ state.button.style.opacity = open ? "0" : "1";
140
+ state.button.style.pointerEvents = open ? "none" : "auto";
141
+ document.body.style.overflow = open ? "hidden" : "";
142
+ if (open) state.iframe.focus();
143
+ }
144
+ function handleMessage(event) {
145
+ if (!state.iframe || event.source !== state.iframe.contentWindow) return;
146
+ var data = event.data || {};
147
+ if (data.type === "chat-message") {
148
+ console.log("[Embed Chat] Message:", data.text);
149
+ }
150
+ if (data.type === "chat-close") {
151
+ close();
152
+ }
153
+ if (data.type === "chat-viewport-config") {
154
+ var meta = document.querySelector('meta[name="viewport"]');
155
+ if (!meta) return;
156
+ var current = meta.getAttribute("content") || "";
157
+ if (data.content) {
158
+ if (state.originalViewport === void 0) state.originalViewport = current;
159
+ if (!current.includes(data.content)) {
160
+ meta.setAttribute("content", current + (current ? ", " : "") + data.content);
161
+ }
162
+ } else {
163
+ meta.setAttribute("content", state.originalViewport ?? current);
164
+ state.originalViewport = void 0;
165
+ }
166
+ }
167
+ }
168
+ function initialize(opts) {
169
+ if (document.querySelector("[data-embed-chat-btn]")) return;
170
+ state.opts = {};
171
+ for (var key in DEFAULTS) {
172
+ state.opts[key] = DEFAULTS[key];
173
+ }
174
+ if (opts) {
175
+ for (var key in opts) {
176
+ if (key === "buttonStyle" || key === "overlayStyle") {
177
+ state.opts[key] = mergeStyles(state.opts[key] || {}, opts[key]);
178
+ } else if (opts[key] !== void 0) {
179
+ state.opts[key] = opts[key];
180
+ }
181
+ }
182
+ }
183
+ var style = document.createElement("style");
184
+ 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
+ document.head.appendChild(style);
186
+ createOverlay();
187
+ createIframe();
188
+ createButton();
189
+ window.addEventListener("message", handleMessage);
190
+ }
191
+ window.ChatSDK = { initialize };
192
+ })();
193
+ //# sourceMappingURL=embed-chat.js.map
@@ -0,0 +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 key in overrides) result[key] = overrides[key];\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 key in opts) {\n if (key === \"buttonStyle\" || key === \"overlayStyle\") {\n state.opts[key] = mergeStyles(state.opts[key] || {}, opts[key]);\n } else if (opts[key] !== undefined) {\n state.opts[key] = opts[key];\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":[]}
package/dist/index.cjs ADDED
@@ -0,0 +1,70 @@
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/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ useIframeBridge: () => useIframeBridge
24
+ });
25
+ module.exports = __toCommonJS(index_exports);
26
+
27
+ // src/useIframeBridge.ts
28
+ var import_react = require("react");
29
+ function useIframeBridge() {
30
+ const [config, setConfig] = (0, import_react.useState)(null);
31
+ const notificationCbRef = (0, import_react.useRef)(null);
32
+ const isInIframe = typeof window !== "undefined" && window !== window.parent;
33
+ const notifyMessage = (0, import_react.useCallback)(
34
+ (text) => {
35
+ if (!isInIframe) return;
36
+ const msg = { type: "chat-message", text };
37
+ window.parent.postMessage(msg, "*");
38
+ },
39
+ [isInIframe]
40
+ );
41
+ const onNotificationClicked = (0, import_react.useCallback)((cb) => {
42
+ notificationCbRef.current = cb;
43
+ }, []);
44
+ (0, import_react.useEffect)(() => {
45
+ if (!isInIframe) return;
46
+ function handleMessage(event) {
47
+ const data = event.data;
48
+ if (!data || typeof data !== "object" || !data.type) return;
49
+ switch (data.type) {
50
+ case "chat-config": {
51
+ const configData = { ...data };
52
+ delete configData.type;
53
+ setConfig(configData);
54
+ break;
55
+ }
56
+ case "chat-notification-clicked":
57
+ notificationCbRef.current?.();
58
+ break;
59
+ }
60
+ }
61
+ window.addEventListener("message", handleMessage);
62
+ return () => window.removeEventListener("message", handleMessage);
63
+ }, [isInIframe]);
64
+ return { config, isInIframe, notifyMessage, onNotificationClicked };
65
+ }
66
+ // Annotate the CommonJS export names for ESM import in node:
67
+ 0 && (module.exports = {
68
+ useIframeBridge
69
+ });
70
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +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":[]}
@@ -0,0 +1,22 @@
1
+ interface BridgeConfig {
2
+ locale?: string;
3
+ title?: string;
4
+ placeholder?: string;
5
+ theme?: {
6
+ mode?: "auto" | "light" | "dark";
7
+ };
8
+ }
9
+ interface IframeBridgeHook {
10
+ config: BridgeConfig | null;
11
+ isInIframe: boolean;
12
+ notifyMessage: (text: string) => void;
13
+ onNotificationClicked: (cb: () => void) => void;
14
+ }
15
+ interface BridgeMessage {
16
+ type: "chat-config" | "chat-message" | "chat-notification-clicked" | "chat-close";
17
+ [key: string]: unknown;
18
+ }
19
+
20
+ declare function useIframeBridge(): IframeBridgeHook;
21
+
22
+ export { type BridgeConfig, type BridgeMessage, type IframeBridgeHook, useIframeBridge };
@@ -0,0 +1,22 @@
1
+ interface BridgeConfig {
2
+ locale?: string;
3
+ title?: string;
4
+ placeholder?: string;
5
+ theme?: {
6
+ mode?: "auto" | "light" | "dark";
7
+ };
8
+ }
9
+ interface IframeBridgeHook {
10
+ config: BridgeConfig | null;
11
+ isInIframe: boolean;
12
+ notifyMessage: (text: string) => void;
13
+ onNotificationClicked: (cb: () => void) => void;
14
+ }
15
+ interface BridgeMessage {
16
+ type: "chat-config" | "chat-message" | "chat-notification-clicked" | "chat-close";
17
+ [key: string]: unknown;
18
+ }
19
+
20
+ declare function useIframeBridge(): IframeBridgeHook;
21
+
22
+ export { type BridgeConfig, type BridgeMessage, type IframeBridgeHook, useIframeBridge };
package/dist/index.js ADDED
@@ -0,0 +1,43 @@
1
+ // src/useIframeBridge.ts
2
+ import { useCallback, useEffect, useRef, useState } from "react";
3
+ function useIframeBridge() {
4
+ const [config, setConfig] = useState(null);
5
+ const notificationCbRef = useRef(null);
6
+ const isInIframe = typeof window !== "undefined" && window !== window.parent;
7
+ const notifyMessage = useCallback(
8
+ (text) => {
9
+ if (!isInIframe) return;
10
+ const msg = { type: "chat-message", text };
11
+ window.parent.postMessage(msg, "*");
12
+ },
13
+ [isInIframe]
14
+ );
15
+ const onNotificationClicked = useCallback((cb) => {
16
+ notificationCbRef.current = cb;
17
+ }, []);
18
+ useEffect(() => {
19
+ if (!isInIframe) return;
20
+ function handleMessage(event) {
21
+ const data = event.data;
22
+ if (!data || typeof data !== "object" || !data.type) return;
23
+ switch (data.type) {
24
+ case "chat-config": {
25
+ const configData = { ...data };
26
+ delete configData.type;
27
+ setConfig(configData);
28
+ break;
29
+ }
30
+ case "chat-notification-clicked":
31
+ notificationCbRef.current?.();
32
+ break;
33
+ }
34
+ }
35
+ window.addEventListener("message", handleMessage);
36
+ return () => window.removeEventListener("message", handleMessage);
37
+ }, [isInIframe]);
38
+ return { config, isInIframe, notifyMessage, onNotificationClicked };
39
+ }
40
+ export {
41
+ useIframeBridge
42
+ };
43
+ //# sourceMappingURL=index.js.map
@@ -0,0 +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":[]}
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@bootdesk/chat-widget-bridge",
3
+ "version": "0.1.0",
4
+ "description": "Iframe bridge for BootDesk Chat SDK - enables embedding the chat widget in an iframe with cross-frame communication via postMessage",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js",
13
+ "require": "./dist/index.cjs"
14
+ },
15
+ "./embed-chat": {
16
+ "import": "./dist/embed-chat.js",
17
+ "require": "./dist/embed-chat.cjs"
18
+ }
19
+ },
20
+ "files": ["dist"],
21
+ "scripts": {
22
+ "build": "tsup",
23
+ "test": "vitest run",
24
+ "lint": "eslint src",
25
+ "format": "prettier --write \"src/**/*.ts\"",
26
+ "format:check": "prettier --check \"src/**/*.ts\"",
27
+ "typecheck": "tsc --noEmit",
28
+ "docs": "typedoc --out ../../docs/_build/js/bridge src"
29
+ },
30
+ "peerDependencies": {
31
+ "react": "^18.0.0 || ^19.0.0"
32
+ },
33
+ "devDependencies": {
34
+ "@eslint/js": "^10.0.1",
35
+ "@testing-library/react": "^16.0.0",
36
+ "@testing-library/jest-dom": "^6.0.0",
37
+ "@types/react": "^18.0.0",
38
+ "eslint": "^10.4.0",
39
+ "eslint-config-prettier": "^10.1.8",
40
+ "jsdom": "^25.0.0",
41
+ "prettier": "^3.8.3",
42
+ "react": "^18.0.0",
43
+ "react-dom": "^18.0.0",
44
+ "tsup": "^8.0.0",
45
+ "typescript": "^5.0.0",
46
+ "typescript-eslint": "^8.59.4",
47
+ "vitest": "^1.0.0"
48
+ }
49
+ }