@benji-money/connect-sdk 1.1.0-beta.1 → 1.1.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +63 -0
- package/dist/connect-sdk.umd.d.ts +14 -0
- package/dist/connect-sdk.umd.global.js +318 -25
- package/dist/connect-sdk.umd.global.js.map +1 -1
- package/dist/index.cjs +326 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +40 -1
- package/dist/index.d.ts +40 -1
- package/dist/index.js +325 -25
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -90,6 +90,69 @@ The SDK accepts the following configuration options:
|
|
|
90
90
|
- `onError` (optional): Callback function called when error occurs in the connect flow
|
|
91
91
|
- `onExit` (optional): Callback function called when the user exits the connect flow
|
|
92
92
|
- `onEvent` (optional): Callback function for handling various events
|
|
93
|
+
- `anchor` (optional): Live anchor binding — `HTMLElement`, CSS selector, getter `() => HTMLElement | null`, or ref `{ value: HTMLElement | null }`. Re-resolved on every layout pass. Falls back to centered when missing or invalid. See [Placement](#placement)
|
|
94
|
+
- `placement` (optional): Placement relative to `anchor` — see [Placement](#placement) below
|
|
95
|
+
- `offset` (optional): Pixel gap after placement — `{ top?: number; left?: number }` (default `{ top: 0, left: 0 }`)
|
|
96
|
+
|
|
97
|
+
### Placement
|
|
98
|
+
|
|
99
|
+
Placement uses [Floating UI](https://floating-ui.com/docs/computePosition#placement) / CSS logical naming (`start` / `end`). In **LTR** layouts:
|
|
100
|
+
|
|
101
|
+
| Value | Meaning |
|
|
102
|
+
| ----- | ------- |
|
|
103
|
+
| `center` (default) | Full-viewport backdrop with iframe centered |
|
|
104
|
+
| `bottom-end` | Below the anchor, right edge aligned with anchor's right edge |
|
|
105
|
+
| `bottom-start` | Below the anchor, left edge aligned with anchor's left edge |
|
|
106
|
+
|
|
107
|
+
**Defaults:**
|
|
108
|
+
|
|
109
|
+
- No `anchor` → centered modal (unchanged behavior for existing integrations)
|
|
110
|
+
- `anchor` set, no `placement` → `bottom-end`
|
|
111
|
+
- If the anchor is missing or invalid on **initial open**, there is not enough viewport space below, or the viewport is narrower than the iframe (400px + padding), the SDK falls back to centered
|
|
112
|
+
- While the modal is **already open**, a temporarily hidden or detached anchor (e.g. crossing a responsive layout breakpoint) keeps the last anchored position instead of jumping to center; when the anchor becomes visible again, placement re-anchors automatically
|
|
113
|
+
|
|
114
|
+
**Live anchor bindings** (re-resolved on scroll, resize, and visual viewport changes):
|
|
115
|
+
|
|
116
|
+
| Form | Example | When to use |
|
|
117
|
+
| ---- | ------- | ----------- |
|
|
118
|
+
| CSS selector | `'#login-btn'` | Stable id on the anchor element |
|
|
119
|
+
| Ref object | `loginButtonRef` (Vue `{ value: el }`) | Anchor may re-render after async work |
|
|
120
|
+
| Getter | `() => document.querySelector('#login-btn')` | Custom lookup |
|
|
121
|
+
| `HTMLElement` | Snapshot at click time | Only when the node will not be replaced before `open()` |
|
|
122
|
+
|
|
123
|
+
Prefer selector, ref, or getter when the anchor can re-render (e.g. disabled/loading state) before the modal opens. A stale `HTMLElement` snapshot falls back to a centered modal on open instead of clipping to the top-left; while open, resize across breakpoints preserves the last anchored position until the anchor is visible again or the modal is closed.
|
|
124
|
+
|
|
125
|
+
**Viewport sizing:**
|
|
126
|
+
|
|
127
|
+
- Design size is **400×645** px (`IFRAME_WIDTH` / `IFRAME_HEIGHT`)
|
|
128
|
+
- **Centered** modals (default, explicit, or fallback) scale down proportionally when the viewport is smaller than the design size so the modal fits with 8px padding on each side
|
|
129
|
+
- **Anchored** popovers use the full design size when width and height checks pass; otherwise they fall back to a scaled centered modal
|
|
130
|
+
- Scroll, resize, and visual viewport changes while open recompute placement and size
|
|
131
|
+
|
|
132
|
+
**LOGIN popover example** (dropdown under a top-right button):
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
import {
|
|
136
|
+
ConnectSDK,
|
|
137
|
+
BenjiConnectMode,
|
|
138
|
+
BenjiConnectPlacement,
|
|
139
|
+
} from "@benji-money/connect-sdk";
|
|
140
|
+
|
|
141
|
+
// Prefer a live binding (selector or ref) when the button may re-render before open()
|
|
142
|
+
const sdk = new ConnectSDK({
|
|
143
|
+
environment: "sandbox",
|
|
144
|
+
token: connectToken,
|
|
145
|
+
mode: BenjiConnectMode.LOGIN,
|
|
146
|
+
anchor: "#login-btn",
|
|
147
|
+
placement: BenjiConnectPlacement.BOTTOM_END,
|
|
148
|
+
offset: { top: 8 },
|
|
149
|
+
onSuccess: (token) => { /* ... */ },
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
await sdk.open();
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
> **`bottom-end`** opens below the anchor with the modal's right edge aligned to the anchor's right edge — matching a dropdown under a top-right LOGIN button.
|
|
93
156
|
|
|
94
157
|
### Environments
|
|
95
158
|
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// These are compile-time constants replaced by tsup's `define` option.
|
|
2
|
+
// Declaring them globally prevents TypeScript errors.
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
declare global {
|
|
6
|
+
const __VERSION__: string;
|
|
7
|
+
const __NAMESPACE__: string;
|
|
8
|
+
|
|
9
|
+
// Global browser exposure for UMD builds
|
|
10
|
+
interface Window {
|
|
11
|
+
// SDK main class (UMD builds attach this)
|
|
12
|
+
ConnectSDK?: any;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -110,7 +110,7 @@ var ConnectSDK = (() => {
|
|
|
110
110
|
// src/utils/config.ts
|
|
111
111
|
var buildContext = () => ({
|
|
112
112
|
namespace: "benji-connect-sdk" ? "benji-connect-sdk" : "benji-connect-sdk",
|
|
113
|
-
version: "1.1.0-beta.
|
|
113
|
+
version: "1.1.0-beta.2" ? String("1.1.0-beta.2") : "0.0.0"
|
|
114
114
|
});
|
|
115
115
|
function isBenjiConnectEnvironment(environment) {
|
|
116
116
|
return environment === "local" /* LOCAL */ || environment === "development" /* DEVELOPMENT */ || environment === "sandbox" /* SANDBOX */ || environment === "production" /* PRODUCTION */;
|
|
@@ -130,6 +130,287 @@ var ConnectSDK = (() => {
|
|
|
130
130
|
return defaultEnvironment;
|
|
131
131
|
}
|
|
132
132
|
|
|
133
|
+
// src/utils/placement.ts
|
|
134
|
+
var IFRAME_WIDTH = 400;
|
|
135
|
+
var IFRAME_HEIGHT = 645;
|
|
136
|
+
var IFRAME_STATIC_STYLE = {
|
|
137
|
+
border: "none",
|
|
138
|
+
borderRadius: "20px",
|
|
139
|
+
overflow: "hidden"
|
|
140
|
+
};
|
|
141
|
+
var CONTAINER_BASE_STYLE = {
|
|
142
|
+
position: "fixed",
|
|
143
|
+
top: "0",
|
|
144
|
+
left: "0",
|
|
145
|
+
width: "100%",
|
|
146
|
+
height: "100%",
|
|
147
|
+
backgroundColor: "rgba(0,0,0,0.5)",
|
|
148
|
+
zIndex: "9999"
|
|
149
|
+
};
|
|
150
|
+
var VIEWPORT_PADDING = 8;
|
|
151
|
+
function isPreservableAnchoredLayout(layout) {
|
|
152
|
+
return layout != null && layout.placement !== "center" /* CENTER */;
|
|
153
|
+
}
|
|
154
|
+
function clampPreservedAnchoredLayout(layout, viewport) {
|
|
155
|
+
const maxLeft = viewport.width - layout.width - VIEWPORT_PADDING;
|
|
156
|
+
const maxTop = viewport.height - layout.height - VIEWPORT_PADDING;
|
|
157
|
+
const minLeft = VIEWPORT_PADDING;
|
|
158
|
+
const minTop = VIEWPORT_PADDING;
|
|
159
|
+
return {
|
|
160
|
+
...layout,
|
|
161
|
+
left: maxLeft < minLeft ? minLeft : Math.min(Math.max(layout.left, minLeft), maxLeft),
|
|
162
|
+
top: maxTop < minTop ? minTop : Math.min(Math.max(layout.top, minTop), maxTop)
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
function preservedAnchoredLayoutOrCenter(viewport, options) {
|
|
166
|
+
const { preserveAnchoredLayout } = options;
|
|
167
|
+
if (isPreservableAnchoredLayout(preserveAnchoredLayout)) {
|
|
168
|
+
return clampPreservedAnchoredLayout(preserveAnchoredLayout, viewport);
|
|
169
|
+
}
|
|
170
|
+
return centerLayout(viewport);
|
|
171
|
+
}
|
|
172
|
+
function isRefLikeAnchor(anchor) {
|
|
173
|
+
return typeof anchor === "object" && anchor !== null && !(anchor instanceof HTMLElement) && "value" in anchor;
|
|
174
|
+
}
|
|
175
|
+
function resolveAnchor(anchor) {
|
|
176
|
+
if (!anchor) {
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
if (typeof anchor === "string") {
|
|
180
|
+
return document.querySelector(anchor);
|
|
181
|
+
}
|
|
182
|
+
if (typeof anchor === "function") {
|
|
183
|
+
const resolved = anchor();
|
|
184
|
+
return resolved instanceof HTMLElement ? resolved : null;
|
|
185
|
+
}
|
|
186
|
+
if (isRefLikeAnchor(anchor)) {
|
|
187
|
+
const el = anchor.value;
|
|
188
|
+
return el instanceof HTMLElement ? el : null;
|
|
189
|
+
}
|
|
190
|
+
return anchor instanceof HTMLElement ? anchor : null;
|
|
191
|
+
}
|
|
192
|
+
function isAnchorVisible(el) {
|
|
193
|
+
if (!el.isConnected) {
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
196
|
+
const style = window.getComputedStyle(el);
|
|
197
|
+
if (style.display === "none" || style.visibility === "hidden") {
|
|
198
|
+
return false;
|
|
199
|
+
}
|
|
200
|
+
const rect = el.getBoundingClientRect();
|
|
201
|
+
return rect.width > 0 || rect.height > 0;
|
|
202
|
+
}
|
|
203
|
+
function resolveEffectivePlacement(config) {
|
|
204
|
+
var _a;
|
|
205
|
+
if (!config.anchor) {
|
|
206
|
+
return "center" /* CENTER */;
|
|
207
|
+
}
|
|
208
|
+
return (_a = config.placement) != null ? _a : "bottom-end" /* BOTTOM_END */;
|
|
209
|
+
}
|
|
210
|
+
function defaultOffset(offset) {
|
|
211
|
+
var _a, _b;
|
|
212
|
+
return {
|
|
213
|
+
top: (_a = offset == null ? void 0 : offset.top) != null ? _a : 0,
|
|
214
|
+
left: (_b = offset == null ? void 0 : offset.left) != null ? _b : 0
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
function resolveIframeDimensions(viewport) {
|
|
218
|
+
const maxW = viewport.width - 2 * VIEWPORT_PADDING;
|
|
219
|
+
const maxH = viewport.height - 2 * VIEWPORT_PADDING;
|
|
220
|
+
const scale = Math.min(1, maxW / IFRAME_WIDTH, maxH / IFRAME_HEIGHT);
|
|
221
|
+
return {
|
|
222
|
+
width: Math.floor(IFRAME_WIDTH * scale),
|
|
223
|
+
height: Math.floor(IFRAME_HEIGHT * scale)
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
function iframeFitsHorizontally(viewportWidth, iframeWidth = IFRAME_WIDTH) {
|
|
227
|
+
return viewportWidth >= iframeWidth + 2 * VIEWPORT_PADDING;
|
|
228
|
+
}
|
|
229
|
+
function centerLayout(viewport) {
|
|
230
|
+
const { width, height } = resolveIframeDimensions(viewport);
|
|
231
|
+
return {
|
|
232
|
+
top: 0,
|
|
233
|
+
left: 0,
|
|
234
|
+
width,
|
|
235
|
+
height,
|
|
236
|
+
placement: "center" /* CENTER */
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
function fitsBelow(anchorBottom, offsetTop, viewportHeight, iframeHeight = IFRAME_HEIGHT) {
|
|
240
|
+
const top = anchorBottom + offsetTop;
|
|
241
|
+
const bottom = top + iframeHeight;
|
|
242
|
+
return top >= VIEWPORT_PADDING && bottom <= viewportHeight - VIEWPORT_PADDING;
|
|
243
|
+
}
|
|
244
|
+
function clampHorizontal(left, viewportWidth) {
|
|
245
|
+
const min = VIEWPORT_PADDING;
|
|
246
|
+
const max = viewportWidth - IFRAME_WIDTH - VIEWPORT_PADDING;
|
|
247
|
+
if (max < min) {
|
|
248
|
+
return min;
|
|
249
|
+
}
|
|
250
|
+
return Math.min(Math.max(left, min), max);
|
|
251
|
+
}
|
|
252
|
+
function warnInvalidAnchor(message) {
|
|
253
|
+
console.warn(`[Benji Connect SDK] ${message}`);
|
|
254
|
+
}
|
|
255
|
+
function computeIframeRect(anchorElement, placement, offset, viewport, options = {}) {
|
|
256
|
+
const { warnOnInvalidAnchor = false } = options;
|
|
257
|
+
const resolvedOffset = defaultOffset(offset);
|
|
258
|
+
if (placement === "center" /* CENTER */) {
|
|
259
|
+
return centerLayout(viewport);
|
|
260
|
+
}
|
|
261
|
+
if (!isAnchorVisible(anchorElement)) {
|
|
262
|
+
if (isPreservableAnchoredLayout(options.preserveAnchoredLayout)) {
|
|
263
|
+
return clampPreservedAnchoredLayout(
|
|
264
|
+
options.preserveAnchoredLayout,
|
|
265
|
+
viewport
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
if (warnOnInvalidAnchor) {
|
|
269
|
+
warnInvalidAnchor(
|
|
270
|
+
"anchor is hidden or detached; falling back to centered modal"
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
return centerLayout(viewport);
|
|
274
|
+
}
|
|
275
|
+
const rect = anchorElement.getBoundingClientRect();
|
|
276
|
+
if (!fitsBelow(rect.bottom, resolvedOffset.top, viewport.height)) {
|
|
277
|
+
return centerLayout(viewport);
|
|
278
|
+
}
|
|
279
|
+
if (!iframeFitsHorizontally(viewport.width)) {
|
|
280
|
+
return centerLayout(viewport);
|
|
281
|
+
}
|
|
282
|
+
const top = rect.bottom + resolvedOffset.top;
|
|
283
|
+
const idealLeft = placement === "bottom-end" /* BOTTOM_END */ ? rect.right - IFRAME_WIDTH + resolvedOffset.left : rect.left + resolvedOffset.left;
|
|
284
|
+
if (idealLeft < VIEWPORT_PADDING) {
|
|
285
|
+
if (warnOnInvalidAnchor) {
|
|
286
|
+
warnInvalidAnchor(
|
|
287
|
+
"anchor rect is unusable for placement; falling back to centered modal"
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
return centerLayout(viewport);
|
|
291
|
+
}
|
|
292
|
+
const left = clampHorizontal(idealLeft, viewport.width);
|
|
293
|
+
return {
|
|
294
|
+
top,
|
|
295
|
+
left,
|
|
296
|
+
width: IFRAME_WIDTH,
|
|
297
|
+
height: IFRAME_HEIGHT,
|
|
298
|
+
placement
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
function resolveIframeLayout(config, viewport = {
|
|
302
|
+
width: window.innerWidth,
|
|
303
|
+
height: window.innerHeight
|
|
304
|
+
}, options = {}) {
|
|
305
|
+
const { warnOnInvalidAnchor = true } = options;
|
|
306
|
+
const placement = resolveEffectivePlacement(config);
|
|
307
|
+
const anchorElement = resolveAnchor(config.anchor);
|
|
308
|
+
if (warnOnInvalidAnchor && placement !== "center" /* CENTER */ && !anchorElement) {
|
|
309
|
+
warnInvalidAnchor("anchor not found; falling back to centered modal");
|
|
310
|
+
return preservedAnchoredLayoutOrCenter(viewport, options);
|
|
311
|
+
}
|
|
312
|
+
if (placement === "center" /* CENTER */) {
|
|
313
|
+
return centerLayout(viewport);
|
|
314
|
+
}
|
|
315
|
+
if (!anchorElement) {
|
|
316
|
+
return preservedAnchoredLayoutOrCenter(viewport, options);
|
|
317
|
+
}
|
|
318
|
+
return computeIframeRect(
|
|
319
|
+
anchorElement,
|
|
320
|
+
placement,
|
|
321
|
+
config.offset,
|
|
322
|
+
viewport,
|
|
323
|
+
options
|
|
324
|
+
);
|
|
325
|
+
}
|
|
326
|
+
function applyOverlayBaseStyle(container) {
|
|
327
|
+
Object.assign(container.style, CONTAINER_BASE_STYLE);
|
|
328
|
+
}
|
|
329
|
+
function getVisualViewportOffset() {
|
|
330
|
+
const vv = window.visualViewport;
|
|
331
|
+
if (!vv) {
|
|
332
|
+
return { top: 0, left: 0 };
|
|
333
|
+
}
|
|
334
|
+
return { top: vv.offsetTop, left: vv.offsetLeft };
|
|
335
|
+
}
|
|
336
|
+
function getRepositionScrollTargets(anchor) {
|
|
337
|
+
const targets = /* @__PURE__ */ new Set([window]);
|
|
338
|
+
const anchorElement = resolveAnchor(anchor);
|
|
339
|
+
if (!anchorElement) {
|
|
340
|
+
return [...targets];
|
|
341
|
+
}
|
|
342
|
+
targets.add(anchorElement);
|
|
343
|
+
let parent = anchorElement.parentElement;
|
|
344
|
+
while (parent) {
|
|
345
|
+
const { overflow, overflowX, overflowY } = window.getComputedStyle(parent);
|
|
346
|
+
const overflowValue = `${overflow} ${overflowX} ${overflowY}`;
|
|
347
|
+
if (/(auto|scroll|overlay)/.test(overflowValue)) {
|
|
348
|
+
targets.add(parent);
|
|
349
|
+
}
|
|
350
|
+
parent = parent.parentElement;
|
|
351
|
+
}
|
|
352
|
+
return [...targets];
|
|
353
|
+
}
|
|
354
|
+
function applyIframeLayoutToElements(config, container, iframe, state, options = { warnOnInvalidAnchor: false }) {
|
|
355
|
+
state.layout = resolveIframeLayout(config, void 0, {
|
|
356
|
+
...options,
|
|
357
|
+
preserveAnchoredLayout: state.lastValidAnchoredLayout
|
|
358
|
+
});
|
|
359
|
+
if (state.layout.placement !== "center" /* CENTER */) {
|
|
360
|
+
state.lastValidAnchoredLayout = state.layout;
|
|
361
|
+
}
|
|
362
|
+
const iframeStyle = {
|
|
363
|
+
...IFRAME_STATIC_STYLE,
|
|
364
|
+
width: `${state.layout.width}px`,
|
|
365
|
+
height: `${state.layout.height}px`
|
|
366
|
+
};
|
|
367
|
+
if (state.layout.placement === "center" /* CENTER */) {
|
|
368
|
+
Object.assign(container.style, {
|
|
369
|
+
display: "flex",
|
|
370
|
+
alignItems: "center",
|
|
371
|
+
justifyContent: "center",
|
|
372
|
+
overflow: "auto"
|
|
373
|
+
});
|
|
374
|
+
Object.assign(iframe.style, iframeStyle, {
|
|
375
|
+
position: "relative",
|
|
376
|
+
top: "",
|
|
377
|
+
left: ""
|
|
378
|
+
});
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
Object.assign(container.style, {
|
|
382
|
+
display: "block",
|
|
383
|
+
overflow: "auto"
|
|
384
|
+
});
|
|
385
|
+
const viewportOffset = getVisualViewportOffset();
|
|
386
|
+
Object.assign(iframe.style, iframeStyle, {
|
|
387
|
+
position: "fixed",
|
|
388
|
+
top: `${state.layout.top + viewportOffset.top}px`,
|
|
389
|
+
left: `${state.layout.left + viewportOffset.left}px`
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
function attachRepositionListeners(config, onReposition) {
|
|
393
|
+
const repositionHandler = onReposition;
|
|
394
|
+
const repositionScrollTargets = getRepositionScrollTargets(config.anchor);
|
|
395
|
+
repositionScrollTargets.forEach((target) => {
|
|
396
|
+
target.addEventListener("scroll", repositionHandler, { passive: true });
|
|
397
|
+
});
|
|
398
|
+
window.addEventListener("resize", repositionHandler);
|
|
399
|
+
const visualViewport = window.visualViewport;
|
|
400
|
+
visualViewport == null ? void 0 : visualViewport.addEventListener("resize", repositionHandler);
|
|
401
|
+
visualViewport == null ? void 0 : visualViewport.addEventListener("scroll", repositionHandler);
|
|
402
|
+
return {
|
|
403
|
+
remove() {
|
|
404
|
+
repositionScrollTargets.forEach((target) => {
|
|
405
|
+
target.removeEventListener("scroll", repositionHandler);
|
|
406
|
+
});
|
|
407
|
+
window.removeEventListener("resize", repositionHandler);
|
|
408
|
+
visualViewport == null ? void 0 : visualViewport.removeEventListener("resize", repositionHandler);
|
|
409
|
+
visualViewport == null ? void 0 : visualViewport.removeEventListener("scroll", repositionHandler);
|
|
410
|
+
}
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
|
|
133
414
|
// src/types/event.ts
|
|
134
415
|
var BenjiConnectEventType = /* @__PURE__ */ ((BenjiConnectEventType2) => {
|
|
135
416
|
BenjiConnectEventType2["AUTH_SUCCESS"] = "AUTH_SUCCESS";
|
|
@@ -369,18 +650,21 @@ var ConnectSDK = (() => {
|
|
|
369
650
|
var MessageRouter = _MessageRouter;
|
|
370
651
|
|
|
371
652
|
// src/connect-sdk.ts
|
|
372
|
-
var IFRAME_STYLE = {
|
|
373
|
-
position: "relative",
|
|
374
|
-
width: "400px",
|
|
375
|
-
height: "645px",
|
|
376
|
-
border: "none",
|
|
377
|
-
borderRadius: "20px",
|
|
378
|
-
overflow: "hidden"
|
|
379
|
-
};
|
|
380
653
|
var ConnectSDK = class {
|
|
381
654
|
constructor(config) {
|
|
382
655
|
this.iframe = null;
|
|
383
656
|
this.container = null;
|
|
657
|
+
this.layoutState = {
|
|
658
|
+
layout: {
|
|
659
|
+
top: 0,
|
|
660
|
+
left: 0,
|
|
661
|
+
width: IFRAME_WIDTH,
|
|
662
|
+
height: IFRAME_HEIGHT,
|
|
663
|
+
placement: "center" /* CENTER */
|
|
664
|
+
},
|
|
665
|
+
lastValidAnchoredLayout: null
|
|
666
|
+
};
|
|
667
|
+
this.repositionListeners = null;
|
|
384
668
|
this.sdkConfig = config;
|
|
385
669
|
if (!this.sdkConfig.environment) throw new Error("Environment is required");
|
|
386
670
|
if (!this.sdkConfig.token) throw new Error("Connect token is required");
|
|
@@ -407,19 +691,7 @@ var ConnectSDK = (() => {
|
|
|
407
691
|
openUI() {
|
|
408
692
|
if (this.iframe) return;
|
|
409
693
|
this.container = document.createElement("div");
|
|
410
|
-
|
|
411
|
-
position: "fixed",
|
|
412
|
-
top: "0",
|
|
413
|
-
left: "0",
|
|
414
|
-
width: "100%",
|
|
415
|
-
height: "100%",
|
|
416
|
-
backgroundColor: "rgba(0,0,0,0.5)",
|
|
417
|
-
zIndex: "9999",
|
|
418
|
-
display: "flex",
|
|
419
|
-
alignItems: "center",
|
|
420
|
-
justifyContent: "center",
|
|
421
|
-
overflow: "auto"
|
|
422
|
-
});
|
|
694
|
+
applyOverlayBaseStyle(this.container);
|
|
423
695
|
console.debug("[Connect SDK] endpoints", Endpoints);
|
|
424
696
|
console.log("[Connect SDK] opeining URL", Endpoints.benji_connect_auth_url);
|
|
425
697
|
const url = new URL(Endpoints.benji_connect_auth_url);
|
|
@@ -430,10 +702,28 @@ var ConnectSDK = (() => {
|
|
|
430
702
|
url.searchParams.set("mode", String(this.sdkConfig.mode));
|
|
431
703
|
}
|
|
432
704
|
this.iframe = document.createElement("iframe");
|
|
433
|
-
Object.assign(this.iframe.style, IFRAME_STYLE);
|
|
434
705
|
this.iframe.src = url.toString();
|
|
435
706
|
this.container.appendChild(this.iframe);
|
|
436
707
|
document.body.appendChild(this.container);
|
|
708
|
+
applyIframeLayoutToElements(
|
|
709
|
+
this.sdkConfig,
|
|
710
|
+
this.container,
|
|
711
|
+
this.iframe,
|
|
712
|
+
this.layoutState,
|
|
713
|
+
{ warnOnInvalidAnchor: true }
|
|
714
|
+
);
|
|
715
|
+
this.repositionListeners = attachRepositionListeners(
|
|
716
|
+
this.sdkConfig,
|
|
717
|
+
() => {
|
|
718
|
+
if (!this.iframe || !this.container) return;
|
|
719
|
+
applyIframeLayoutToElements(
|
|
720
|
+
this.sdkConfig,
|
|
721
|
+
this.container,
|
|
722
|
+
this.iframe,
|
|
723
|
+
this.layoutState
|
|
724
|
+
);
|
|
725
|
+
}
|
|
726
|
+
);
|
|
437
727
|
this.container.addEventListener("click", (e) => {
|
|
438
728
|
var _a, _b;
|
|
439
729
|
if (e.target === this.container) {
|
|
@@ -446,9 +736,12 @@ var ConnectSDK = (() => {
|
|
|
446
736
|
});
|
|
447
737
|
}
|
|
448
738
|
close() {
|
|
449
|
-
var _a;
|
|
739
|
+
var _a, _b;
|
|
450
740
|
if (!this.iframe) return;
|
|
451
|
-
|
|
741
|
+
(_a = this.repositionListeners) == null ? void 0 : _a.remove();
|
|
742
|
+
this.repositionListeners = null;
|
|
743
|
+
this.layoutState.lastValidAnchoredLayout = null;
|
|
744
|
+
if ((_b = this.container) == null ? void 0 : _b.parentNode) {
|
|
452
745
|
this.container.parentNode.removeChild(this.container);
|
|
453
746
|
}
|
|
454
747
|
MessageRouter.removeEventListeners();
|