@salesforce/experimental-mfe-bridge 2.2.0 → 2.2.1-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.esm.js +1 -1
- package/package.json +3 -3
- package/dist/index.iife.js +0 -282
- package/dist/index.iife.prod.js +0 -3
package/dist/index.esm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! @salesforce/experimental-mfe-bridge v2.2.
|
|
1
|
+
/*! @salesforce/experimental-mfe-bridge v2.2.1-rc.1 (2026-04-09) */
|
|
2
2
|
/**
|
|
3
3
|
* EmbeddingResizer - Handles dynamic iframe/container resizing
|
|
4
4
|
* Uses ResizeObserver to monitor element size changes and notify the host
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforce/experimental-mfe-bridge",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.1-rc.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "EventTarget-Based Embed ↔ Host Communication for UI Embedding",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
"test": "jest",
|
|
25
25
|
"clean": "rimraf dist"
|
|
26
26
|
},
|
|
27
|
-
"
|
|
28
|
-
"utils": "2.2.
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"utils": "2.2.1-rc.1"
|
|
29
29
|
},
|
|
30
30
|
"files": [
|
|
31
31
|
"dist/",
|
package/dist/index.iife.js
DELETED
|
@@ -1,282 +0,0 @@
|
|
|
1
|
-
var LightningBridge = (function (exports) {
|
|
2
|
-
'use strict';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* EmbeddingResizer - Handles dynamic iframe/container resizing
|
|
6
|
-
* Uses ResizeObserver to monitor element size changes and notify the host
|
|
7
|
-
*/
|
|
8
|
-
class EmbeddingResizer {
|
|
9
|
-
#observer = null;
|
|
10
|
-
#targetElement;
|
|
11
|
-
#onResize;
|
|
12
|
-
#onReady;
|
|
13
|
-
#waitForDOMReady;
|
|
14
|
-
#lastHeight = -1;
|
|
15
|
-
#scheduled = false;
|
|
16
|
-
#isObserving = false;
|
|
17
|
-
constructor(options) {
|
|
18
|
-
this.#targetElement = options.targetElement || document.body;
|
|
19
|
-
this.#onResize = options.onResize;
|
|
20
|
-
this.#onReady = options.onReady;
|
|
21
|
-
this.#waitForDOMReady = options.waitForDOMReady ?? true;
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Start observing the target element for size changes
|
|
25
|
-
*/
|
|
26
|
-
start() {
|
|
27
|
-
if (this.#isObserving) {
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
if (this.#waitForDOMReady && document.readyState === "loading") {
|
|
31
|
-
document.addEventListener("DOMContentLoaded", () => this.#startObserver(), { once: true });
|
|
32
|
-
}
|
|
33
|
-
else {
|
|
34
|
-
this.#startObserver();
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Stop observing and clean up resources
|
|
39
|
-
*/
|
|
40
|
-
stop() {
|
|
41
|
-
if (this.#observer) {
|
|
42
|
-
this.#observer.disconnect();
|
|
43
|
-
this.#observer = null;
|
|
44
|
-
}
|
|
45
|
-
this.#isObserving = false;
|
|
46
|
-
this.#lastHeight = -1;
|
|
47
|
-
this.#scheduled = false;
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* Get the current observed height
|
|
51
|
-
*/
|
|
52
|
-
getLastHeight() {
|
|
53
|
-
return this.#lastHeight;
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* Check if currently observing
|
|
57
|
-
*/
|
|
58
|
-
isObserving() {
|
|
59
|
-
return this.#isObserving;
|
|
60
|
-
}
|
|
61
|
-
#startObserver = () => {
|
|
62
|
-
this.#observer = new ResizeObserver((entries) => {
|
|
63
|
-
this.#handleResize(entries);
|
|
64
|
-
});
|
|
65
|
-
this.#observer.observe(this.#targetElement, { box: "border-box" });
|
|
66
|
-
this.#isObserving = true;
|
|
67
|
-
// Invoke ready callback if provided
|
|
68
|
-
if (this.#onReady) {
|
|
69
|
-
this.#onReady();
|
|
70
|
-
}
|
|
71
|
-
};
|
|
72
|
-
#handleResize = (entries) => {
|
|
73
|
-
if (!entries || entries.length === 0) {
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
const entry = entries[0];
|
|
77
|
-
const measuredHeight = this.#extractHeight(entry);
|
|
78
|
-
const heightPx = Math.max(0, Math.ceil(Number(measuredHeight)));
|
|
79
|
-
if (!Number.isFinite(heightPx)) {
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
if (heightPx === this.#lastHeight) {
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
|
-
this.#lastHeight = heightPx;
|
|
86
|
-
if (!this.#scheduled) {
|
|
87
|
-
this.#scheduled = true;
|
|
88
|
-
requestAnimationFrame(() => {
|
|
89
|
-
this.#scheduled = false;
|
|
90
|
-
this.#onResize(heightPx);
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
};
|
|
94
|
-
#extractHeight = (entry) => {
|
|
95
|
-
// Try borderBoxSize first (more accurate)
|
|
96
|
-
if (entry.borderBoxSize) {
|
|
97
|
-
if (Array.isArray(entry.borderBoxSize)) {
|
|
98
|
-
return entry.borderBoxSize[0]?.blockSize || 0;
|
|
99
|
-
}
|
|
100
|
-
// Some browsers return a single object instead of array
|
|
101
|
-
return entry.borderBoxSize.blockSize || 0;
|
|
102
|
-
}
|
|
103
|
-
// Fallback to contentRect
|
|
104
|
-
if (entry.contentRect && typeof entry.contentRect.height === "number") {
|
|
105
|
-
return entry.contentRect.height;
|
|
106
|
-
}
|
|
107
|
-
// Last resort: getBoundingClientRect
|
|
108
|
-
if (entry.target && typeof entry.target.getBoundingClientRect === "function") {
|
|
109
|
-
return entry.target.getBoundingClientRect().height;
|
|
110
|
-
}
|
|
111
|
-
return 0;
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* ExternalEmbedBridge - EventTarget-based iframe ↔ host communication
|
|
117
|
-
* Provides secure, structured interface for widget development
|
|
118
|
-
* Auto-handles theme synchronization and error telemetry
|
|
119
|
-
*/
|
|
120
|
-
class ExternalEmbedBridge extends EventTarget {
|
|
121
|
-
#connected = false;
|
|
122
|
-
#hostAppOrigin = null;
|
|
123
|
-
#instanceId = null;
|
|
124
|
-
#currentTheme = {};
|
|
125
|
-
#currentData = {};
|
|
126
|
-
#resizer = null;
|
|
127
|
-
constructor() {
|
|
128
|
-
super();
|
|
129
|
-
window.addEventListener("message", (e) => this.#handleHostMessage(e));
|
|
130
|
-
this.#setupErrorCapture();
|
|
131
|
-
this.#sendToHost("bridge-ready");
|
|
132
|
-
this.#setupResizeObserver();
|
|
133
|
-
// eslint-disable-next-line no-console
|
|
134
|
-
console.log("[Bridge] Initialized and ready for communication");
|
|
135
|
-
}
|
|
136
|
-
#handleHostMessage(event) {
|
|
137
|
-
if (event.source !== window.parent)
|
|
138
|
-
return;
|
|
139
|
-
if (this.#hostAppOrigin && event.origin !== this.#hostAppOrigin)
|
|
140
|
-
return;
|
|
141
|
-
const payload = event.data || {};
|
|
142
|
-
const { type, data, id } = payload;
|
|
143
|
-
if (typeof type !== "string" || !type.startsWith("salesforce-"))
|
|
144
|
-
return;
|
|
145
|
-
if (this.#instanceId && id !== this.#instanceId)
|
|
146
|
-
return;
|
|
147
|
-
// eslint-disable-next-line no-console
|
|
148
|
-
console.log("[Bridge] host->widget", type, data);
|
|
149
|
-
switch (type) {
|
|
150
|
-
case "salesforce-theme":
|
|
151
|
-
this.#handleThemeUpdate(data);
|
|
152
|
-
break;
|
|
153
|
-
case "salesforce-data":
|
|
154
|
-
this.#handleDataUpdate(data);
|
|
155
|
-
break;
|
|
156
|
-
case "salesforce-shell-ready":
|
|
157
|
-
this.#handleConnectionReady(event.origin, id);
|
|
158
|
-
break;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
#handleThemeUpdate(themeData) {
|
|
162
|
-
this.#currentTheme = { ...themeData };
|
|
163
|
-
this.#applyThemeToDocument(themeData);
|
|
164
|
-
// use super to escape the override
|
|
165
|
-
super.dispatchEvent(new CustomEvent("theme", { detail: themeData }));
|
|
166
|
-
}
|
|
167
|
-
#handleDataUpdate(payload) {
|
|
168
|
-
this.#currentData = { ...payload };
|
|
169
|
-
// use super to escape the override
|
|
170
|
-
super.dispatchEvent(new CustomEvent("data", { detail: payload }));
|
|
171
|
-
}
|
|
172
|
-
#handleConnectionReady(origin, id) {
|
|
173
|
-
this.#connected = true;
|
|
174
|
-
this.#hostAppOrigin = origin;
|
|
175
|
-
this.#instanceId = id;
|
|
176
|
-
// use super to escape the override
|
|
177
|
-
super.dispatchEvent(new CustomEvent("connected"));
|
|
178
|
-
}
|
|
179
|
-
#applyThemeToDocument(themeData) {
|
|
180
|
-
const documentElement = document.documentElement;
|
|
181
|
-
requestAnimationFrame(() => {
|
|
182
|
-
Object.entries(themeData).forEach(([property, value]) => {
|
|
183
|
-
if (property.startsWith("--")) {
|
|
184
|
-
documentElement.style.setProperty(property, String(value));
|
|
185
|
-
}
|
|
186
|
-
});
|
|
187
|
-
});
|
|
188
|
-
}
|
|
189
|
-
#setupErrorCapture() {
|
|
190
|
-
// this allows salesforce to collect telemetry about errors in your app
|
|
191
|
-
window.addEventListener("error", (event) => {
|
|
192
|
-
this.#sendToHost("bridge-error", {
|
|
193
|
-
type: "javascript-error",
|
|
194
|
-
message: event.message,
|
|
195
|
-
filename: event.filename,
|
|
196
|
-
lineno: event.lineno,
|
|
197
|
-
colno: event.colno,
|
|
198
|
-
stack: event.error?.stack,
|
|
199
|
-
timestamp: Date.now(),
|
|
200
|
-
});
|
|
201
|
-
});
|
|
202
|
-
window.addEventListener("unhandledrejection", (event) => {
|
|
203
|
-
this.#sendToHost("bridge-error", {
|
|
204
|
-
type: "unhandled-rejection",
|
|
205
|
-
reason: event.reason?.toString?.() || "Unknown rejection",
|
|
206
|
-
stack: event.reason?.stack,
|
|
207
|
-
timestamp: Date.now(),
|
|
208
|
-
});
|
|
209
|
-
});
|
|
210
|
-
}
|
|
211
|
-
#setupResizeObserver() {
|
|
212
|
-
this.#resizer = new EmbeddingResizer({
|
|
213
|
-
targetElement: document.body,
|
|
214
|
-
onResize: (height) => {
|
|
215
|
-
this.#sendToHost("bridge-event", { eventType: "resize", detail: { height } });
|
|
216
|
-
},
|
|
217
|
-
onReady: () => {
|
|
218
|
-
this.#sendToHost("bridge-event", {
|
|
219
|
-
eventType: "widget-ready",
|
|
220
|
-
detail: { bridge: "ExternalEmbedBridge", version: "1.0.0", timestamp: Date.now() },
|
|
221
|
-
});
|
|
222
|
-
},
|
|
223
|
-
waitForDOMReady: true,
|
|
224
|
-
});
|
|
225
|
-
this.#resizer.start();
|
|
226
|
-
}
|
|
227
|
-
#getHostAppOrigin(type) {
|
|
228
|
-
return this.#hostAppOrigin || (type === "bridge-ready" ? "*" : null);
|
|
229
|
-
}
|
|
230
|
-
#sendToHost(type, data) {
|
|
231
|
-
const origin = this.#getHostAppOrigin(type);
|
|
232
|
-
if (!origin)
|
|
233
|
-
return;
|
|
234
|
-
try {
|
|
235
|
-
const message = this.#instanceId ? { type, data, id: this.#instanceId } : { type, data };
|
|
236
|
-
// eslint-disable-next-line no-console
|
|
237
|
-
console.log("[Bridge] Sending message to host:", message);
|
|
238
|
-
window.parent.postMessage(message, origin);
|
|
239
|
-
}
|
|
240
|
-
catch (error) {
|
|
241
|
-
// eslint-disable-next-line no-console
|
|
242
|
-
console.warn("[Bridge] Failed to send message to host:", error);
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
// Override dispatchEvent to forward custom events to the host via post message
|
|
246
|
-
dispatchEvent(event) {
|
|
247
|
-
const result = super.dispatchEvent(event);
|
|
248
|
-
this.#sendToHost("custom-event", {
|
|
249
|
-
eventType: event.type,
|
|
250
|
-
detail: event.detail,
|
|
251
|
-
});
|
|
252
|
-
return result;
|
|
253
|
-
}
|
|
254
|
-
getTheme() {
|
|
255
|
-
return { ...this.#currentTheme };
|
|
256
|
-
}
|
|
257
|
-
getData() {
|
|
258
|
-
return { ...this.#currentData };
|
|
259
|
-
}
|
|
260
|
-
get instanceId() {
|
|
261
|
-
return this.#instanceId;
|
|
262
|
-
}
|
|
263
|
-
isConnected() {
|
|
264
|
-
return this.#connected;
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
/**
|
|
269
|
-
* Bridge Package Entry Point
|
|
270
|
-
* Exports the bridge singleton for iframe ↔ host communication
|
|
271
|
-
*/
|
|
272
|
-
// Create and export a singleton instance for convenience
|
|
273
|
-
const bridge = new ExternalEmbedBridge();
|
|
274
|
-
|
|
275
|
-
exports.default = bridge;
|
|
276
|
-
|
|
277
|
-
Object.defineProperty(exports, '__esModule', { value: true });
|
|
278
|
-
|
|
279
|
-
return exports;
|
|
280
|
-
|
|
281
|
-
})({});
|
|
282
|
-
//# sourceMappingURL=index.iife.js.map
|
package/dist/index.iife.prod.js
DELETED
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
/*! @lightning-out/bridge v2.2.0-rc.1 (2026-03-11) */
|
|
2
|
-
var LightningBridge=function(e){"use strict";class t{#e=null;#t;#s;#n;#i;#r=-1;#a=!1;#o=!1;constructor(e){this.#t=e.targetElement||document.body,this.#s=e.onResize,this.#n=e.onReady,this.#i=e.waitForDOMReady??!0}start(){this.#o||(this.#i&&"loading"===document.readyState?document.addEventListener("DOMContentLoaded",()=>this.#d(),{once:!0}):this.#d())}stop(){this.#e&&(this.#e.disconnect(),this.#e=null),this.#o=!1,this.#r=-1,this.#a=!1}getLastHeight(){return this.#r}isObserving(){return this.#o}#d=()=>{this.#e=new ResizeObserver(e=>{this.#h(e)}),this.#e.observe(this.#t,{box:"border-box"}),this.#o=!0,this.#n&&this.#n()};#h=e=>{if(!e||0===e.length)return;const t=e[0],s=this.#c(t),n=Math.max(0,Math.ceil(Number(s)));Number.isFinite(n)&&n!==this.#r&&(this.#r=n,this.#a||(this.#a=!0,requestAnimationFrame(()=>{this.#a=!1,this.#s(n)})))};#c=e=>e.borderBoxSize?Array.isArray(e.borderBoxSize)?e.borderBoxSize[0]?.blockSize||0:e.borderBoxSize.blockSize||0:e.contentRect&&"number"==typeof e.contentRect.height?e.contentRect.height:e.target&&"function"==typeof e.target.getBoundingClientRect?e.target.getBoundingClientRect().height:0}class s extends EventTarget{#l=!1;#g=null;#u=null;#p={};#m={};#b=null;constructor(){super(),window.addEventListener("message",e=>this.#v(e)),this.#y(),this.#w("bridge-ready"),this.#R(),console.log("[Bridge] Initialized and ready for communication")}#v(e){if(e.source!==window.parent)return;if(this.#g&&e.origin!==this.#g)return;const t=e.data||{},{type:s,data:n,id:i}=t;if("string"==typeof s&&s.startsWith("salesforce-")&&(!this.#u||i===this.#u))switch(console.log("[Bridge] host->widget",s,n),s){case"salesforce-theme":this.#O(n);break;case"salesforce-data":this.#E(n);break;case"salesforce-shell-ready":this.#z(e.origin,i)}}#O(e){this.#p={...e},this.#T(e),super.dispatchEvent(new CustomEvent("theme",{detail:e}))}#E(e){this.#m={...e},super.dispatchEvent(new CustomEvent("data",{detail:e}))}#z(e,t){this.#l=!0,this.#g=e,this.#u=t,super.dispatchEvent(new CustomEvent("connected"))}#T(e){const t=document.documentElement;requestAnimationFrame(()=>{Object.entries(e).forEach(([e,s])=>{e.startsWith("--")&&t.style.setProperty(e,String(s))})})}#y(){window.addEventListener("error",e=>{this.#w("bridge-error",{type:"javascript-error",message:e.message,filename:e.filename,lineno:e.lineno,colno:e.colno,stack:e.error?.stack,timestamp:Date.now()})}),window.addEventListener("unhandledrejection",e=>{this.#w("bridge-error",{type:"unhandled-rejection",reason:e.reason?.toString?.()||"Unknown rejection",stack:e.reason?.stack,timestamp:Date.now()})})}#R(){this.#b=new t({targetElement:document.body,onResize:e=>{this.#w("bridge-event",{eventType:"resize",detail:{height:e}})},onReady:()=>{this.#w("bridge-event",{eventType:"widget-ready",detail:{bridge:"ExternalEmbedBridge",version:"1.0.0",timestamp:Date.now()}})},waitForDOMReady:!0}),this.#b.start()}#f(e){return this.#g||("bridge-ready"===e?"*":null)}#w(e,t){const s=this.#f(e);if(s)try{const n=this.#u?{type:e,data:t,id:this.#u}:{type:e,data:t};console.log("[Bridge] Sending message to host:",n),window.parent.postMessage(n,s)}catch(e){console.warn("[Bridge] Failed to send message to host:",e)}}dispatchEvent(e){const t=super.dispatchEvent(e);return this.#w("custom-event",{eventType:e.type,detail:e.detail}),t}getTheme(){return{...this.#p}}getData(){return{...this.#m}}get instanceId(){return this.#u}isConnected(){return this.#l}}const n=new s;return e.default=n,Object.defineProperty(e,"__esModule",{value:!0}),e}({});
|
|
3
|
-
//# sourceMappingURL=index.iife.prod.js.map
|