@civic/auth 0.6.0 → 0.6.1-beta.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/shared/components/CivicAuthIframeContainer.js +1 -1
- package/dist/shared/components/CivicAuthIframeContainer.js.map +1 -1
- package/dist/shared/lib/BrowserAuthenticationRefresher.d.ts +7 -1
- package/dist/shared/lib/BrowserAuthenticationRefresher.d.ts.map +1 -1
- package/dist/shared/lib/BrowserAuthenticationRefresher.js +15 -2
- package/dist/shared/lib/BrowserAuthenticationRefresher.js.map +1 -1
- package/dist/shared/lib/util.d.ts +1 -1
- package/dist/shared/lib/util.d.ts.map +1 -1
- package/dist/shared/lib/util.js +6 -1
- package/dist/shared/lib/util.js.map +1 -1
- package/dist/shared/version.d.ts +1 -1
- package/dist/shared/version.d.ts.map +1 -1
- package/dist/shared/version.js +1 -1
- package/dist/shared/version.js.map +1 -1
- package/dist/vanillajs/auth/CivicAuth.d.ts +63 -5
- package/dist/vanillajs/auth/CivicAuth.d.ts.map +1 -1
- package/dist/vanillajs/auth/CivicAuth.js +202 -26
- package/dist/vanillajs/auth/CivicAuth.js.map +1 -1
- package/dist/vanillajs/auth/OAuthCallbackHandler.d.ts +90 -0
- package/dist/vanillajs/auth/OAuthCallbackHandler.d.ts.map +1 -0
- package/dist/vanillajs/auth/OAuthCallbackHandler.js +143 -0
- package/dist/vanillajs/auth/OAuthCallbackHandler.js.map +1 -0
- package/dist/vanillajs/auth/SessionManager.d.ts +40 -9
- package/dist/vanillajs/auth/SessionManager.d.ts.map +1 -1
- package/dist/vanillajs/auth/SessionManager.js +96 -61
- package/dist/vanillajs/auth/SessionManager.js.map +1 -1
- package/dist/vanillajs/auth/TokenRefresher.d.ts +54 -0
- package/dist/vanillajs/auth/TokenRefresher.d.ts.map +1 -0
- package/dist/vanillajs/auth/TokenRefresher.js +166 -0
- package/dist/vanillajs/auth/TokenRefresher.js.map +1 -0
- package/dist/vanillajs/iframe/IframeManager.d.ts +82 -0
- package/dist/vanillajs/iframe/IframeManager.d.ts.map +1 -0
- package/dist/vanillajs/iframe/IframeManager.js +487 -0
- package/dist/vanillajs/iframe/IframeManager.js.map +1 -0
- package/dist/vanillajs/iframe/IframeResizer.d.ts +15 -0
- package/dist/vanillajs/iframe/IframeResizer.d.ts.map +1 -0
- package/dist/vanillajs/iframe/IframeResizer.js +127 -0
- package/dist/vanillajs/iframe/IframeResizer.js.map +1 -0
- package/dist/vanillajs/index.d.ts +8 -7
- package/dist/vanillajs/index.d.ts.map +1 -1
- package/dist/vanillajs/index.js +10 -7
- package/dist/vanillajs/index.js.map +1 -1
- package/dist/vanillajs/types/index.d.ts +2 -2
- package/dist/vanillajs/types/index.d.ts.map +1 -1
- package/dist/vanillajs/types/index.js.map +1 -1
- package/dist/vanillajs/ui/LoadingComponents.d.ts +51 -0
- package/dist/vanillajs/ui/LoadingComponents.d.ts.map +1 -0
- package/dist/vanillajs/ui/LoadingComponents.js +363 -0
- package/dist/vanillajs/ui/LoadingComponents.js.map +1 -0
- package/package.json +1 -1
- package/dist/vanillajs/iframe/domUtils.d.ts +0 -4
- package/dist/vanillajs/iframe/domUtils.d.ts.map +0 -1
- package/dist/vanillajs/iframe/domUtils.js +0 -25
- package/dist/vanillajs/iframe/domUtils.js.map +0 -1
- package/dist/vanillajs/storage/BrowserCookieStorageAdapter.d.ts +0 -19
- package/dist/vanillajs/storage/BrowserCookieStorageAdapter.d.ts.map +0 -1
- package/dist/vanillajs/storage/BrowserCookieStorageAdapter.js +0 -101
- package/dist/vanillajs/storage/BrowserCookieStorageAdapter.js.map +0 -1
- package/dist/vanillajs/storage/BrowserLocalStorageAdapter.d.ts +0 -9
- package/dist/vanillajs/storage/BrowserLocalStorageAdapter.d.ts.map +0 -1
- package/dist/vanillajs/storage/BrowserLocalStorageAdapter.js +0 -36
- package/dist/vanillajs/storage/BrowserLocalStorageAdapter.js.map +0 -1
- package/dist/vanillajs/storage/InMemoryStorageAdapter.d.ts +0 -9
- package/dist/vanillajs/storage/InMemoryStorageAdapter.d.ts.map +0 -1
- package/dist/vanillajs/storage/InMemoryStorageAdapter.js +0 -16
- package/dist/vanillajs/storage/InMemoryStorageAdapter.js.map +0 -1
- package/dist/vanillajs/storage/StorageAdapter.d.ts +0 -15
- package/dist/vanillajs/storage/StorageAdapter.d.ts.map +0 -1
- package/dist/vanillajs/storage/StorageAdapter.js +0 -16
- package/dist/vanillajs/storage/StorageAdapter.js.map +0 -1
- package/dist/vanillajs/utils/page-handlers.d.ts +0 -29
- package/dist/vanillajs/utils/page-handlers.d.ts.map +0 -1
- package/dist/vanillajs/utils/page-handlers.js +0 -165
- package/dist/vanillajs/utils/page-handlers.js.map +0 -1
|
@@ -0,0 +1,487 @@
|
|
|
1
|
+
import { CivicIframeResizer } from "./IframeResizer.js";
|
|
2
|
+
import { createIframeShimmerLoader, createCloseButton, } from "../ui/LoadingComponents.js";
|
|
3
|
+
import { createLogger } from "../utils/logger.js";
|
|
4
|
+
export class IframeManager {
|
|
5
|
+
// Constants for styling and configuration
|
|
6
|
+
static MODAL_Z_INDEX = "1050";
|
|
7
|
+
static MODAL_WIDTH = "20rem"; // 320px
|
|
8
|
+
static MODAL_BACKDROP_COLOR = "rgba(17, 24, 39, 0.5)";
|
|
9
|
+
static MODAL_BACKDROP_BLUR = "blur(4px)";
|
|
10
|
+
static BORDER_RADIUS = "24px";
|
|
11
|
+
static TRANSITION_DURATION = "250ms";
|
|
12
|
+
static MODAL_MIN_HEIGHT = "26px";
|
|
13
|
+
static EMBEDDED_MIN_HEIGHT = "225px";
|
|
14
|
+
static IFRAME_READY_DELAY = 100; // ms
|
|
15
|
+
iframe = null;
|
|
16
|
+
container;
|
|
17
|
+
resizer = null;
|
|
18
|
+
displayMode;
|
|
19
|
+
keydownHandler;
|
|
20
|
+
clickHandler;
|
|
21
|
+
iframeId;
|
|
22
|
+
onClose;
|
|
23
|
+
shimmerLoader = null;
|
|
24
|
+
closeButton = null;
|
|
25
|
+
isIframeLoaded = false;
|
|
26
|
+
iframeReadyMessageListener;
|
|
27
|
+
logger;
|
|
28
|
+
constructor(config) {
|
|
29
|
+
this.container = config.container;
|
|
30
|
+
this.displayMode = config.displayMode;
|
|
31
|
+
this.iframeId = config.iframeId || "civic-auth-iframe";
|
|
32
|
+
this.onClose = config.onClose;
|
|
33
|
+
this.logger = createLogger("iframe");
|
|
34
|
+
this.initializeContainer(config);
|
|
35
|
+
this.setupKeyboardHandlers();
|
|
36
|
+
}
|
|
37
|
+
initializeContainer(config) {
|
|
38
|
+
if (this.displayMode === "modal") {
|
|
39
|
+
this.applyModalStyles();
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
// Embedded mode
|
|
43
|
+
this.container.style.position = "relative";
|
|
44
|
+
this.container.style.width = config.width || "auto";
|
|
45
|
+
this.container.style.height = config.height || "auto";
|
|
46
|
+
this.container.style.backgroundColor = "white";
|
|
47
|
+
this.container.style.borderRadius = IframeManager.BORDER_RADIUS;
|
|
48
|
+
this.container.style.overflow = "hidden";
|
|
49
|
+
this.container.style.transition = "all 0.5s ease-in-out";
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Applies modal backdrop styles to create a full-screen overlay
|
|
53
|
+
* Uses !important to override any existing styles
|
|
54
|
+
*/
|
|
55
|
+
applyModalStyles() {
|
|
56
|
+
const modalStyles = {
|
|
57
|
+
position: "fixed",
|
|
58
|
+
left: "0",
|
|
59
|
+
top: "0",
|
|
60
|
+
width: "100vw",
|
|
61
|
+
height: "100vh",
|
|
62
|
+
"z-index": IframeManager.MODAL_Z_INDEX,
|
|
63
|
+
display: "flex",
|
|
64
|
+
"align-items": "center",
|
|
65
|
+
"justify-content": "center",
|
|
66
|
+
"background-color": IframeManager.MODAL_BACKDROP_COLOR,
|
|
67
|
+
"backdrop-filter": IframeManager.MODAL_BACKDROP_BLUR,
|
|
68
|
+
opacity: "1",
|
|
69
|
+
transition: `opacity ${IframeManager.TRANSITION_DURATION} ease`,
|
|
70
|
+
// Reset any conflicting styles that might prevent modal from working
|
|
71
|
+
margin: "0",
|
|
72
|
+
padding: "0",
|
|
73
|
+
border: "none",
|
|
74
|
+
"border-radius": "0",
|
|
75
|
+
"min-height": "100vh",
|
|
76
|
+
};
|
|
77
|
+
Object.entries(modalStyles).forEach(([property, value]) => {
|
|
78
|
+
this.container.style.setProperty(property, value, "important");
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
setupKeyboardHandlers() {
|
|
82
|
+
if (this.displayMode === "modal") {
|
|
83
|
+
this.keydownHandler = (event) => {
|
|
84
|
+
if (event.key === "Escape") {
|
|
85
|
+
this.onClose?.();
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
window.addEventListener("keydown", this.keydownHandler);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
createIframe(url) {
|
|
92
|
+
// Clean up any existing iframe content, but preserve container styles for modal mode
|
|
93
|
+
this.cleanupIframeOnly();
|
|
94
|
+
// Create new iframe
|
|
95
|
+
this.iframe = document.createElement("iframe");
|
|
96
|
+
this.iframe.id = this.iframeId;
|
|
97
|
+
this.iframe.src = url;
|
|
98
|
+
// Apply iframe styles
|
|
99
|
+
this.applyIframeStyles();
|
|
100
|
+
// Add attributes that prevent scrollbars
|
|
101
|
+
this.setIframeAttributes();
|
|
102
|
+
// Add CSS to prevent scrollbars
|
|
103
|
+
this.addScrollbarHidingStyles();
|
|
104
|
+
// Set up message listener for iframe ready events (more reliable than onload)
|
|
105
|
+
this.setupIframeMessageListener();
|
|
106
|
+
// Set up iframe onload handler
|
|
107
|
+
this.setupIframeOnloadHandler();
|
|
108
|
+
if (this.displayMode === "modal") {
|
|
109
|
+
this.setupModalIframe();
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
this.setupEmbeddedIframe();
|
|
113
|
+
}
|
|
114
|
+
// Initialize resizer - this will handle all the message-based resizing
|
|
115
|
+
this.resizer = new CivicIframeResizer(this.iframe, this.container);
|
|
116
|
+
return this.iframe;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Applies base styles to the iframe element
|
|
120
|
+
*/
|
|
121
|
+
applyIframeStyles() {
|
|
122
|
+
if (!this.iframe)
|
|
123
|
+
return;
|
|
124
|
+
const baseStyles = {
|
|
125
|
+
border: "none",
|
|
126
|
+
display: "block",
|
|
127
|
+
pointerEvents: "auto",
|
|
128
|
+
width: "100%",
|
|
129
|
+
minWidth: "100%",
|
|
130
|
+
overflow: "hidden",
|
|
131
|
+
overflowX: "hidden",
|
|
132
|
+
overflowY: "hidden",
|
|
133
|
+
opacity: "0",
|
|
134
|
+
transition: `opacity ${IframeManager.TRANSITION_DURATION} ease, height ${IframeManager.TRANSITION_DURATION} ease`,
|
|
135
|
+
};
|
|
136
|
+
Object.entries(baseStyles).forEach(([property, value]) => {
|
|
137
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Required to handle dynamic CSS property assignment since CSSStyleDeclaration type doesn't fully capture all possible properties
|
|
138
|
+
this.iframe.style[property] = value;
|
|
139
|
+
});
|
|
140
|
+
// Set initial height based on display mode
|
|
141
|
+
if (this.displayMode === "modal") {
|
|
142
|
+
this.iframe.style.height = IframeManager.MODAL_MIN_HEIGHT;
|
|
143
|
+
this.iframe.style.minHeight = IframeManager.MODAL_MIN_HEIGHT;
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
this.iframe.style.height = "auto";
|
|
147
|
+
this.iframe.style.minHeight = IframeManager.EMBEDDED_MIN_HEIGHT; // Embedded mode minimum
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Sets iframe attributes to prevent scrollbars
|
|
152
|
+
*/
|
|
153
|
+
setIframeAttributes() {
|
|
154
|
+
if (!this.iframe)
|
|
155
|
+
return;
|
|
156
|
+
this.iframe.setAttribute("scrolling", "no");
|
|
157
|
+
this.iframe.setAttribute("frameborder", "0");
|
|
158
|
+
this.iframe.setAttribute("seamless", "seamless");
|
|
159
|
+
// Add additional CSS to prevent scrollbars
|
|
160
|
+
this.iframe.style.cssText +=
|
|
161
|
+
"; -ms-overflow-style: none; scrollbar-width: none;";
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Adds CSS styles to hide scrollbars across different browsers
|
|
165
|
+
*/
|
|
166
|
+
addScrollbarHidingStyles() {
|
|
167
|
+
const iframeStyle = document.createElement("style");
|
|
168
|
+
iframeStyle.textContent = `
|
|
169
|
+
iframe[id="${this.iframeId}"] {
|
|
170
|
+
-webkit-overflow-scrolling: touch !important;
|
|
171
|
+
}
|
|
172
|
+
iframe[id="${this.iframeId}"]::webkit-scrollbar {
|
|
173
|
+
display: none !important;
|
|
174
|
+
width: 0 !important;
|
|
175
|
+
height: 0 !important;
|
|
176
|
+
}
|
|
177
|
+
`;
|
|
178
|
+
document.head.appendChild(iframeStyle);
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Sets up the message listener for iframe ready events
|
|
182
|
+
*/
|
|
183
|
+
setupIframeMessageListener() {
|
|
184
|
+
this.iframeReadyMessageListener = (event) => {
|
|
185
|
+
try {
|
|
186
|
+
// Only handle messages from our iframe
|
|
187
|
+
if (!this.iframe?.contentWindow ||
|
|
188
|
+
event.source !== this.iframe.contentWindow) {
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
const message = event.data;
|
|
192
|
+
// Handle ready message from iframe resizer
|
|
193
|
+
if (message.type === "civic-iframe-ready") {
|
|
194
|
+
this.logger.debug("Iframe content is ready - hiding shimmer loader");
|
|
195
|
+
this.markIframeAsLoaded();
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
catch (error) {
|
|
199
|
+
this.logger.debug("Error processing iframe ready message:", error);
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
window.addEventListener("message", this.iframeReadyMessageListener);
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Sets up the iframe onload handler with CSS injection
|
|
206
|
+
*/
|
|
207
|
+
setupIframeOnloadHandler() {
|
|
208
|
+
if (!this.iframe)
|
|
209
|
+
return;
|
|
210
|
+
this.iframe.onload = () => {
|
|
211
|
+
// Use a small delay to allow ready message to arrive first
|
|
212
|
+
setTimeout(() => {
|
|
213
|
+
if (!this.isIframeLoaded) {
|
|
214
|
+
this.logger.debug("Iframe onload fired - hiding shimmer loader (fallback)");
|
|
215
|
+
this.markIframeAsLoaded();
|
|
216
|
+
}
|
|
217
|
+
}, IframeManager.IFRAME_READY_DELAY);
|
|
218
|
+
try {
|
|
219
|
+
const iframeDoc = this.iframe?.contentDocument || this.iframe?.contentWindow?.document;
|
|
220
|
+
if (iframeDoc && iframeDoc.head) {
|
|
221
|
+
const style = iframeDoc.createElement("style");
|
|
222
|
+
style.textContent = `
|
|
223
|
+
html, body {
|
|
224
|
+
overflow: hidden !important;
|
|
225
|
+
overflow-x: hidden !important;
|
|
226
|
+
overflow-y: hidden !important;
|
|
227
|
+
-ms-overflow-style: none !important;
|
|
228
|
+
scrollbar-width: none !important;
|
|
229
|
+
margin: 0 !important;
|
|
230
|
+
padding: 0 !important;
|
|
231
|
+
}
|
|
232
|
+
body::-webkit-scrollbar {
|
|
233
|
+
display: none !important;
|
|
234
|
+
}
|
|
235
|
+
* {
|
|
236
|
+
box-sizing: border-box !important;
|
|
237
|
+
}
|
|
238
|
+
`;
|
|
239
|
+
iframeDoc.head.appendChild(style);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
catch (error) {
|
|
243
|
+
this.logger.debug("Could not inject CSS into iframe (likely cross-origin):", error);
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Sets up the iframe for modal display mode
|
|
249
|
+
*/
|
|
250
|
+
setupModalIframe() {
|
|
251
|
+
if (!this.iframe)
|
|
252
|
+
return;
|
|
253
|
+
// Ensure modal is visible (in case it was hidden by cleanup)
|
|
254
|
+
this.container.style.setProperty("display", "flex", "important");
|
|
255
|
+
// Create content wrapper for modal
|
|
256
|
+
const contentWrapper = document.createElement("div");
|
|
257
|
+
contentWrapper.style.position = "relative";
|
|
258
|
+
contentWrapper.style.overflow = "hidden";
|
|
259
|
+
contentWrapper.style.width = IframeManager.MODAL_WIDTH; // 320px like React version
|
|
260
|
+
contentWrapper.style.borderRadius = IframeManager.BORDER_RADIUS;
|
|
261
|
+
contentWrapper.style.boxShadow =
|
|
262
|
+
"0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)";
|
|
263
|
+
// Stop propagation on content wrapper to prevent backdrop clicks
|
|
264
|
+
contentWrapper.addEventListener("click", (e) => {
|
|
265
|
+
e.stopPropagation();
|
|
266
|
+
});
|
|
267
|
+
// Create inner iframe wrapper to match React structure
|
|
268
|
+
const iframeWrapper = document.createElement("div");
|
|
269
|
+
iframeWrapper.style.position = "relative";
|
|
270
|
+
iframeWrapper.style.borderRadius = IframeManager.BORDER_RADIUS;
|
|
271
|
+
iframeWrapper.style.overflow = "hidden";
|
|
272
|
+
iframeWrapper.style.overflowX = "hidden";
|
|
273
|
+
iframeWrapper.style.overflowY = "hidden";
|
|
274
|
+
iframeWrapper.style.transition = `all ${IframeManager.TRANSITION_DURATION} ease`;
|
|
275
|
+
iframeWrapper.style.width = "100%";
|
|
276
|
+
iframeWrapper.style.height = "auto";
|
|
277
|
+
iframeWrapper.style.minHeight = IframeManager.MODAL_MIN_HEIGHT; // Start small for modal mode
|
|
278
|
+
// Add shimmer loader for modal mode
|
|
279
|
+
this.showShimmerLoader(iframeWrapper, "white");
|
|
280
|
+
// Add close button for modal mode (initially hidden)
|
|
281
|
+
if (this.onClose) {
|
|
282
|
+
this.closeButton = createCloseButton(this.onClose);
|
|
283
|
+
contentWrapper.appendChild(this.closeButton);
|
|
284
|
+
}
|
|
285
|
+
// Add iframe to wrapper, then wrapper to content, then content to container
|
|
286
|
+
iframeWrapper.appendChild(this.iframe);
|
|
287
|
+
contentWrapper.appendChild(iframeWrapper);
|
|
288
|
+
this.container.appendChild(contentWrapper);
|
|
289
|
+
// Add click-to-close functionality after content is added
|
|
290
|
+
this.clickHandler = (e) => {
|
|
291
|
+
if (e.target === this.container) {
|
|
292
|
+
// Only close if clicking the backdrop, not the iframe content
|
|
293
|
+
this.onClose?.();
|
|
294
|
+
}
|
|
295
|
+
};
|
|
296
|
+
this.container.addEventListener("click", this.clickHandler);
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Sets up the iframe for embedded display mode
|
|
300
|
+
*/
|
|
301
|
+
setupEmbeddedIframe() {
|
|
302
|
+
if (!this.iframe)
|
|
303
|
+
return;
|
|
304
|
+
// Embedded mode - create wrapper with border radius and overflow hidden
|
|
305
|
+
const iframeWrapper = document.createElement("div");
|
|
306
|
+
iframeWrapper.style.position = "relative";
|
|
307
|
+
iframeWrapper.style.borderRadius = IframeManager.BORDER_RADIUS;
|
|
308
|
+
iframeWrapper.style.overflow = "hidden";
|
|
309
|
+
iframeWrapper.style.overflowX = "hidden";
|
|
310
|
+
iframeWrapper.style.overflowY = "hidden";
|
|
311
|
+
iframeWrapper.style.transition = "all 0.5s ease-in-out";
|
|
312
|
+
iframeWrapper.style.width = "100%";
|
|
313
|
+
iframeWrapper.style.height = "auto";
|
|
314
|
+
iframeWrapper.style.minHeight = IframeManager.EMBEDDED_MIN_HEIGHT; // Embedded mode minimum
|
|
315
|
+
// Add shimmer loader for embedded mode with max width
|
|
316
|
+
this.showShimmerLoader(iframeWrapper, "white", IframeManager.MODAL_WIDTH);
|
|
317
|
+
// Add iframe to wrapper, then wrapper to container
|
|
318
|
+
iframeWrapper.appendChild(this.iframe);
|
|
319
|
+
this.container.appendChild(iframeWrapper);
|
|
320
|
+
}
|
|
321
|
+
showShimmerLoader(parentElement, backgroundColor = "white", maxWidth) {
|
|
322
|
+
if (!this.isIframeLoaded && !this.shimmerLoader) {
|
|
323
|
+
this.shimmerLoader = createIframeShimmerLoader(backgroundColor, maxWidth);
|
|
324
|
+
parentElement.appendChild(this.shimmerLoader);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
hideShimmerLoader() {
|
|
328
|
+
if (this.shimmerLoader && this.shimmerLoader.parentNode) {
|
|
329
|
+
// Add fade-out transition before removing
|
|
330
|
+
this.shimmerLoader.style.opacity = "0";
|
|
331
|
+
this.shimmerLoader.style.transition = `opacity ${IframeManager.TRANSITION_DURATION} ease`;
|
|
332
|
+
// Remove after transition completes
|
|
333
|
+
setTimeout(() => {
|
|
334
|
+
if (this.shimmerLoader && this.shimmerLoader.parentNode) {
|
|
335
|
+
this.shimmerLoader.parentNode.removeChild(this.shimmerLoader);
|
|
336
|
+
this.shimmerLoader = null;
|
|
337
|
+
}
|
|
338
|
+
}, parseInt(IframeManager.TRANSITION_DURATION));
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
markIframeAsLoaded() {
|
|
342
|
+
if (!this.isIframeLoaded) {
|
|
343
|
+
this.isIframeLoaded = true;
|
|
344
|
+
this.hideShimmerLoader();
|
|
345
|
+
this.updateWrapperForLoadedContent();
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
updateWrapperForLoadedContent() {
|
|
349
|
+
// Fade in the iframe
|
|
350
|
+
if (this.iframe) {
|
|
351
|
+
this.iframe.style.opacity = "1";
|
|
352
|
+
}
|
|
353
|
+
// Show close button for modal mode when content is loaded
|
|
354
|
+
if (this.displayMode === "modal" && this.closeButton) {
|
|
355
|
+
this.closeButton.style.opacity = "1";
|
|
356
|
+
}
|
|
357
|
+
// Find the iframe wrapper and update its styles for loaded content
|
|
358
|
+
const iframeWrapper = this.iframe?.parentElement;
|
|
359
|
+
if (iframeWrapper) {
|
|
360
|
+
// Remove minimum height constraints to allow natural sizing
|
|
361
|
+
if (this.displayMode === "modal") {
|
|
362
|
+
iframeWrapper.style.minHeight = "auto";
|
|
363
|
+
}
|
|
364
|
+
else {
|
|
365
|
+
// For embedded mode, keep some minimum but allow natural growth
|
|
366
|
+
iframeWrapper.style.minHeight = "auto";
|
|
367
|
+
}
|
|
368
|
+
// Add border radius transition for loaded state (matching React implementation)
|
|
369
|
+
iframeWrapper.style.borderRadius = IframeManager.BORDER_RADIUS;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
hide() {
|
|
373
|
+
if (this.displayMode === "modal") {
|
|
374
|
+
// Add fade-out transition for modal backdrop
|
|
375
|
+
this.container.style.opacity = "0";
|
|
376
|
+
this.container.style.transition = `opacity ${IframeManager.TRANSITION_DURATION} ease`;
|
|
377
|
+
// Hide after transition completes
|
|
378
|
+
setTimeout(() => {
|
|
379
|
+
this.container.style.display = "none";
|
|
380
|
+
}, parseInt(IframeManager.TRANSITION_DURATION));
|
|
381
|
+
}
|
|
382
|
+
else {
|
|
383
|
+
// For embedded mode, just hide immediately
|
|
384
|
+
this.container.style.display = "none";
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
cleanupIframeOnly() {
|
|
388
|
+
if (this.resizer) {
|
|
389
|
+
this.resizer.cleanup();
|
|
390
|
+
this.resizer = null;
|
|
391
|
+
}
|
|
392
|
+
// Clean up shimmer loader
|
|
393
|
+
this.hideShimmerLoader();
|
|
394
|
+
// Clean up close button
|
|
395
|
+
if (this.closeButton && this.closeButton.parentNode) {
|
|
396
|
+
this.closeButton.parentNode.removeChild(this.closeButton);
|
|
397
|
+
this.closeButton = null;
|
|
398
|
+
}
|
|
399
|
+
// Clean up message listener
|
|
400
|
+
if (this.iframeReadyMessageListener) {
|
|
401
|
+
window.removeEventListener("message", this.iframeReadyMessageListener);
|
|
402
|
+
this.iframeReadyMessageListener = undefined;
|
|
403
|
+
}
|
|
404
|
+
if (this.iframe && this.iframe.parentNode) {
|
|
405
|
+
this.iframe.parentNode.removeChild(this.iframe);
|
|
406
|
+
this.iframe = null;
|
|
407
|
+
}
|
|
408
|
+
// Reset loading state
|
|
409
|
+
this.isIframeLoaded = false;
|
|
410
|
+
// Clear container content but DON'T reset styles for modal mode
|
|
411
|
+
this.container.innerHTML = "";
|
|
412
|
+
}
|
|
413
|
+
cleanup() {
|
|
414
|
+
if (this.resizer) {
|
|
415
|
+
this.resizer.cleanup();
|
|
416
|
+
this.resizer = null;
|
|
417
|
+
}
|
|
418
|
+
// Clean up shimmer loader
|
|
419
|
+
this.hideShimmerLoader();
|
|
420
|
+
// Clean up close button
|
|
421
|
+
if (this.closeButton && this.closeButton.parentNode) {
|
|
422
|
+
this.closeButton.parentNode.removeChild(this.closeButton);
|
|
423
|
+
this.closeButton = null;
|
|
424
|
+
}
|
|
425
|
+
// Clean up message listener
|
|
426
|
+
if (this.iframeReadyMessageListener) {
|
|
427
|
+
window.removeEventListener("message", this.iframeReadyMessageListener);
|
|
428
|
+
this.iframeReadyMessageListener = undefined;
|
|
429
|
+
}
|
|
430
|
+
if (this.iframe && this.iframe.parentNode) {
|
|
431
|
+
this.iframe.parentNode.removeChild(this.iframe);
|
|
432
|
+
this.iframe = null;
|
|
433
|
+
}
|
|
434
|
+
// Reset loading state
|
|
435
|
+
this.isIframeLoaded = false;
|
|
436
|
+
// Remove keyboard event listener
|
|
437
|
+
if (this.keydownHandler) {
|
|
438
|
+
window.removeEventListener("keydown", this.keydownHandler);
|
|
439
|
+
this.keydownHandler = undefined;
|
|
440
|
+
}
|
|
441
|
+
// Remove click event listener
|
|
442
|
+
if (this.clickHandler) {
|
|
443
|
+
this.container.removeEventListener("click", this.clickHandler);
|
|
444
|
+
this.clickHandler = undefined;
|
|
445
|
+
}
|
|
446
|
+
// Clear container content and reset styles
|
|
447
|
+
this.container.innerHTML = "";
|
|
448
|
+
if (this.displayMode === "modal") {
|
|
449
|
+
// Reset all modal-specific styles to ensure clean state
|
|
450
|
+
this.resetModalStyles();
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
/**
|
|
454
|
+
* Resets all modal-specific styles by removing CSS properties that were set with !important
|
|
455
|
+
*/
|
|
456
|
+
resetModalStyles() {
|
|
457
|
+
const modalStyleProperties = [
|
|
458
|
+
"position",
|
|
459
|
+
"left",
|
|
460
|
+
"top",
|
|
461
|
+
"width",
|
|
462
|
+
"height",
|
|
463
|
+
"z-index",
|
|
464
|
+
"display",
|
|
465
|
+
"align-items",
|
|
466
|
+
"justify-content",
|
|
467
|
+
"background-color",
|
|
468
|
+
"backdrop-filter",
|
|
469
|
+
"opacity",
|
|
470
|
+
"transition",
|
|
471
|
+
"margin",
|
|
472
|
+
"padding",
|
|
473
|
+
"border",
|
|
474
|
+
"border-radius",
|
|
475
|
+
"min-height",
|
|
476
|
+
];
|
|
477
|
+
modalStyleProperties.forEach((property) => {
|
|
478
|
+
this.container.style.removeProperty(property);
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
resize() {
|
|
482
|
+
if (this.resizer) {
|
|
483
|
+
this.resizer.resize();
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
//# sourceMappingURL=IframeManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IframeManager.js","sourceRoot":"","sources":["../../../src/vanillajs/iframe/IframeManager.ts"],"names":[],"mappings":"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","sourcesContent":["import { CivicIframeResizer } from \"./IframeResizer.js\";\nimport {\n createIframeShimmerLoader,\n createCloseButton,\n} from \"../ui/LoadingComponents.js\";\nimport { createLogger } from \"../utils/logger.js\";\n\nexport interface IframeConfig {\n container: HTMLElement;\n displayMode: \"embedded\" | \"modal\";\n width?: string;\n height?: string;\n iframeId?: string;\n onClose?: () => void;\n}\n\nexport class IframeManager {\n // Constants for styling and configuration\n private static readonly MODAL_Z_INDEX = \"1050\";\n private static readonly MODAL_WIDTH = \"20rem\"; // 320px\n private static readonly MODAL_BACKDROP_COLOR = \"rgba(17, 24, 39, 0.5)\";\n private static readonly MODAL_BACKDROP_BLUR = \"blur(4px)\";\n private static readonly BORDER_RADIUS = \"24px\";\n private static readonly TRANSITION_DURATION = \"250ms\";\n private static readonly MODAL_MIN_HEIGHT = \"26px\";\n private static readonly EMBEDDED_MIN_HEIGHT = \"225px\";\n private static readonly IFRAME_READY_DELAY = 100; // ms\n\n private iframe: HTMLIFrameElement | null = null;\n private container: HTMLElement;\n private resizer: CivicIframeResizer | null = null;\n private displayMode: \"embedded\" | \"modal\";\n private keydownHandler?: (event: KeyboardEvent) => void;\n private clickHandler?: (event: MouseEvent) => void;\n private iframeId: string;\n private onClose?: () => void;\n private shimmerLoader: HTMLElement | null = null;\n private closeButton: HTMLButtonElement | null = null;\n private isIframeLoaded = false;\n private iframeReadyMessageListener?: (event: MessageEvent) => void;\n private logger: ReturnType<typeof createLogger>;\n\n constructor(config: IframeConfig) {\n this.container = config.container;\n this.displayMode = config.displayMode;\n this.iframeId = config.iframeId || \"civic-auth-iframe\";\n this.onClose = config.onClose;\n this.logger = createLogger(\"iframe\");\n this.initializeContainer(config);\n this.setupKeyboardHandlers();\n }\n\n private initializeContainer(config: IframeConfig): void {\n if (this.displayMode === \"modal\") {\n this.applyModalStyles();\n return;\n }\n\n // Embedded mode\n this.container.style.position = \"relative\";\n this.container.style.width = config.width || \"auto\";\n this.container.style.height = config.height || \"auto\";\n this.container.style.backgroundColor = \"white\";\n this.container.style.borderRadius = IframeManager.BORDER_RADIUS;\n this.container.style.overflow = \"hidden\";\n this.container.style.transition = \"all 0.5s ease-in-out\";\n }\n\n /**\n * Applies modal backdrop styles to create a full-screen overlay\n * Uses !important to override any existing styles\n */\n private applyModalStyles(): void {\n const modalStyles = {\n position: \"fixed\",\n left: \"0\",\n top: \"0\",\n width: \"100vw\",\n height: \"100vh\",\n \"z-index\": IframeManager.MODAL_Z_INDEX,\n display: \"flex\",\n \"align-items\": \"center\",\n \"justify-content\": \"center\",\n \"background-color\": IframeManager.MODAL_BACKDROP_COLOR,\n \"backdrop-filter\": IframeManager.MODAL_BACKDROP_BLUR,\n opacity: \"1\",\n transition: `opacity ${IframeManager.TRANSITION_DURATION} ease`,\n // Reset any conflicting styles that might prevent modal from working\n margin: \"0\",\n padding: \"0\",\n border: \"none\",\n \"border-radius\": \"0\",\n \"min-height\": \"100vh\",\n };\n\n Object.entries(modalStyles).forEach(([property, value]) => {\n this.container.style.setProperty(property, value, \"important\");\n });\n }\n\n private setupKeyboardHandlers(): void {\n if (this.displayMode === \"modal\") {\n this.keydownHandler = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n this.onClose?.();\n }\n };\n window.addEventListener(\"keydown\", this.keydownHandler);\n }\n }\n\n public createIframe(url: string): HTMLIFrameElement {\n // Clean up any existing iframe content, but preserve container styles for modal mode\n this.cleanupIframeOnly();\n\n // Create new iframe\n this.iframe = document.createElement(\"iframe\");\n this.iframe.id = this.iframeId;\n this.iframe.src = url;\n\n // Apply iframe styles\n this.applyIframeStyles();\n\n // Add attributes that prevent scrollbars\n this.setIframeAttributes();\n\n // Add CSS to prevent scrollbars\n this.addScrollbarHidingStyles();\n\n // Set up message listener for iframe ready events (more reliable than onload)\n this.setupIframeMessageListener();\n\n // Set up iframe onload handler\n this.setupIframeOnloadHandler();\n\n if (this.displayMode === \"modal\") {\n this.setupModalIframe();\n } else {\n this.setupEmbeddedIframe();\n }\n\n // Initialize resizer - this will handle all the message-based resizing\n this.resizer = new CivicIframeResizer(this.iframe, this.container);\n\n return this.iframe;\n }\n\n /**\n * Applies base styles to the iframe element\n */\n private applyIframeStyles(): void {\n if (!this.iframe) return;\n\n const baseStyles = {\n border: \"none\",\n display: \"block\",\n pointerEvents: \"auto\",\n width: \"100%\",\n minWidth: \"100%\",\n overflow: \"hidden\",\n overflowX: \"hidden\",\n overflowY: \"hidden\",\n opacity: \"0\",\n transition: `opacity ${IframeManager.TRANSITION_DURATION} ease, height ${IframeManager.TRANSITION_DURATION} ease`,\n };\n\n Object.entries(baseStyles).forEach(([property, value]) => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Required to handle dynamic CSS property assignment since CSSStyleDeclaration type doesn't fully capture all possible properties\n this.iframe!.style[property as any] = value;\n });\n\n // Set initial height based on display mode\n if (this.displayMode === \"modal\") {\n this.iframe!.style.height = IframeManager.MODAL_MIN_HEIGHT;\n this.iframe!.style.minHeight = IframeManager.MODAL_MIN_HEIGHT;\n } else {\n this.iframe!.style.height = \"auto\";\n this.iframe!.style.minHeight = IframeManager.EMBEDDED_MIN_HEIGHT; // Embedded mode minimum\n }\n }\n\n /**\n * Sets iframe attributes to prevent scrollbars\n */\n private setIframeAttributes(): void {\n if (!this.iframe) return;\n\n this.iframe.setAttribute(\"scrolling\", \"no\");\n this.iframe.setAttribute(\"frameborder\", \"0\");\n this.iframe.setAttribute(\"seamless\", \"seamless\");\n\n // Add additional CSS to prevent scrollbars\n this.iframe.style.cssText +=\n \"; -ms-overflow-style: none; scrollbar-width: none;\";\n }\n\n /**\n * Adds CSS styles to hide scrollbars across different browsers\n */\n private addScrollbarHidingStyles(): void {\n const iframeStyle = document.createElement(\"style\");\n iframeStyle.textContent = `\n iframe[id=\"${this.iframeId}\"] {\n -webkit-overflow-scrolling: touch !important;\n }\n iframe[id=\"${this.iframeId}\"]::webkit-scrollbar {\n display: none !important;\n width: 0 !important;\n height: 0 !important;\n }\n `;\n document.head.appendChild(iframeStyle);\n }\n\n /**\n * Sets up the message listener for iframe ready events\n */\n private setupIframeMessageListener(): void {\n this.iframeReadyMessageListener = (event: MessageEvent) => {\n try {\n // Only handle messages from our iframe\n if (\n !this.iframe?.contentWindow ||\n event.source !== this.iframe.contentWindow\n ) {\n return;\n }\n\n const message = event.data;\n\n // Handle ready message from iframe resizer\n if (message.type === \"civic-iframe-ready\") {\n this.logger.debug(\"Iframe content is ready - hiding shimmer loader\");\n this.markIframeAsLoaded();\n }\n } catch (error) {\n this.logger.debug(\"Error processing iframe ready message:\", error);\n }\n };\n\n window.addEventListener(\"message\", this.iframeReadyMessageListener);\n }\n\n /**\n * Sets up the iframe onload handler with CSS injection\n */\n private setupIframeOnloadHandler(): void {\n if (!this.iframe) return;\n\n this.iframe.onload = () => {\n // Use a small delay to allow ready message to arrive first\n setTimeout(() => {\n if (!this.isIframeLoaded) {\n this.logger.debug(\n \"Iframe onload fired - hiding shimmer loader (fallback)\",\n );\n this.markIframeAsLoaded();\n }\n }, IframeManager.IFRAME_READY_DELAY);\n\n try {\n const iframeDoc =\n this.iframe?.contentDocument || this.iframe?.contentWindow?.document;\n if (iframeDoc && iframeDoc.head) {\n const style = iframeDoc.createElement(\"style\");\n style.textContent = `\n html, body {\n overflow: hidden !important;\n overflow-x: hidden !important;\n overflow-y: hidden !important;\n -ms-overflow-style: none !important;\n scrollbar-width: none !important;\n margin: 0 !important;\n padding: 0 !important;\n }\n body::-webkit-scrollbar {\n display: none !important;\n }\n * {\n box-sizing: border-box !important;\n }\n `;\n iframeDoc.head.appendChild(style);\n }\n } catch (error) {\n this.logger.debug(\n \"Could not inject CSS into iframe (likely cross-origin):\",\n error,\n );\n }\n };\n }\n\n /**\n * Sets up the iframe for modal display mode\n */\n private setupModalIframe(): void {\n if (!this.iframe) return;\n\n // Ensure modal is visible (in case it was hidden by cleanup)\n this.container.style.setProperty(\"display\", \"flex\", \"important\");\n\n // Create content wrapper for modal\n const contentWrapper = document.createElement(\"div\");\n contentWrapper.style.position = \"relative\";\n contentWrapper.style.overflow = \"hidden\";\n contentWrapper.style.width = IframeManager.MODAL_WIDTH; // 320px like React version\n contentWrapper.style.borderRadius = IframeManager.BORDER_RADIUS;\n contentWrapper.style.boxShadow =\n \"0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)\";\n\n // Stop propagation on content wrapper to prevent backdrop clicks\n contentWrapper.addEventListener(\"click\", (e) => {\n e.stopPropagation();\n });\n\n // Create inner iframe wrapper to match React structure\n const iframeWrapper = document.createElement(\"div\");\n iframeWrapper.style.position = \"relative\";\n iframeWrapper.style.borderRadius = IframeManager.BORDER_RADIUS;\n iframeWrapper.style.overflow = \"hidden\";\n iframeWrapper.style.overflowX = \"hidden\";\n iframeWrapper.style.overflowY = \"hidden\";\n iframeWrapper.style.transition = `all ${IframeManager.TRANSITION_DURATION} ease`;\n iframeWrapper.style.width = \"100%\";\n iframeWrapper.style.height = \"auto\";\n iframeWrapper.style.minHeight = IframeManager.MODAL_MIN_HEIGHT; // Start small for modal mode\n\n // Add shimmer loader for modal mode\n this.showShimmerLoader(iframeWrapper, \"white\");\n\n // Add close button for modal mode (initially hidden)\n if (this.onClose) {\n this.closeButton = createCloseButton(this.onClose);\n contentWrapper.appendChild(this.closeButton);\n }\n\n // Add iframe to wrapper, then wrapper to content, then content to container\n iframeWrapper.appendChild(this.iframe);\n contentWrapper.appendChild(iframeWrapper);\n this.container.appendChild(contentWrapper);\n\n // Add click-to-close functionality after content is added\n this.clickHandler = (e: MouseEvent) => {\n if (e.target === this.container) {\n // Only close if clicking the backdrop, not the iframe content\n this.onClose?.();\n }\n };\n this.container.addEventListener(\"click\", this.clickHandler);\n }\n\n /**\n * Sets up the iframe for embedded display mode\n */\n private setupEmbeddedIframe(): void {\n if (!this.iframe) return;\n\n // Embedded mode - create wrapper with border radius and overflow hidden\n const iframeWrapper = document.createElement(\"div\");\n iframeWrapper.style.position = \"relative\";\n iframeWrapper.style.borderRadius = IframeManager.BORDER_RADIUS;\n iframeWrapper.style.overflow = \"hidden\";\n iframeWrapper.style.overflowX = \"hidden\";\n iframeWrapper.style.overflowY = \"hidden\";\n iframeWrapper.style.transition = \"all 0.5s ease-in-out\";\n iframeWrapper.style.width = \"100%\";\n iframeWrapper.style.height = \"auto\";\n iframeWrapper.style.minHeight = IframeManager.EMBEDDED_MIN_HEIGHT; // Embedded mode minimum\n\n // Add shimmer loader for embedded mode with max width\n this.showShimmerLoader(iframeWrapper, \"white\", IframeManager.MODAL_WIDTH);\n\n // Add iframe to wrapper, then wrapper to container\n iframeWrapper.appendChild(this.iframe);\n this.container.appendChild(iframeWrapper);\n }\n\n private showShimmerLoader(\n parentElement: HTMLElement,\n backgroundColor = \"white\",\n maxWidth?: string,\n ): void {\n if (!this.isIframeLoaded && !this.shimmerLoader) {\n this.shimmerLoader = createIframeShimmerLoader(backgroundColor, maxWidth);\n parentElement.appendChild(this.shimmerLoader);\n }\n }\n\n private hideShimmerLoader(): void {\n if (this.shimmerLoader && this.shimmerLoader.parentNode) {\n // Add fade-out transition before removing\n this.shimmerLoader.style.opacity = \"0\";\n this.shimmerLoader.style.transition = `opacity ${IframeManager.TRANSITION_DURATION} ease`;\n\n // Remove after transition completes\n setTimeout(() => {\n if (this.shimmerLoader && this.shimmerLoader.parentNode) {\n this.shimmerLoader.parentNode.removeChild(this.shimmerLoader);\n this.shimmerLoader = null;\n }\n }, parseInt(IframeManager.TRANSITION_DURATION));\n }\n }\n\n private markIframeAsLoaded(): void {\n if (!this.isIframeLoaded) {\n this.isIframeLoaded = true;\n this.hideShimmerLoader();\n this.updateWrapperForLoadedContent();\n }\n }\n\n private updateWrapperForLoadedContent(): void {\n // Fade in the iframe\n if (this.iframe) {\n this.iframe.style.opacity = \"1\";\n }\n\n // Show close button for modal mode when content is loaded\n if (this.displayMode === \"modal\" && this.closeButton) {\n this.closeButton.style.opacity = \"1\";\n }\n\n // Find the iframe wrapper and update its styles for loaded content\n const iframeWrapper = this.iframe?.parentElement;\n if (iframeWrapper) {\n // Remove minimum height constraints to allow natural sizing\n if (this.displayMode === \"modal\") {\n iframeWrapper.style.minHeight = \"auto\";\n } else {\n // For embedded mode, keep some minimum but allow natural growth\n iframeWrapper.style.minHeight = \"auto\";\n }\n\n // Add border radius transition for loaded state (matching React implementation)\n iframeWrapper.style.borderRadius = IframeManager.BORDER_RADIUS;\n }\n }\n\n public hide(): void {\n if (this.displayMode === \"modal\") {\n // Add fade-out transition for modal backdrop\n this.container.style.opacity = \"0\";\n this.container.style.transition = `opacity ${IframeManager.TRANSITION_DURATION} ease`;\n\n // Hide after transition completes\n setTimeout(() => {\n this.container.style.display = \"none\";\n }, parseInt(IframeManager.TRANSITION_DURATION));\n } else {\n // For embedded mode, just hide immediately\n this.container.style.display = \"none\";\n }\n }\n\n private cleanupIframeOnly(): void {\n if (this.resizer) {\n this.resizer.cleanup();\n this.resizer = null;\n }\n\n // Clean up shimmer loader\n this.hideShimmerLoader();\n\n // Clean up close button\n if (this.closeButton && this.closeButton.parentNode) {\n this.closeButton.parentNode.removeChild(this.closeButton);\n this.closeButton = null;\n }\n\n // Clean up message listener\n if (this.iframeReadyMessageListener) {\n window.removeEventListener(\"message\", this.iframeReadyMessageListener);\n this.iframeReadyMessageListener = undefined;\n }\n\n if (this.iframe && this.iframe.parentNode) {\n this.iframe.parentNode.removeChild(this.iframe);\n this.iframe = null;\n }\n\n // Reset loading state\n this.isIframeLoaded = false;\n\n // Clear container content but DON'T reset styles for modal mode\n this.container.innerHTML = \"\";\n }\n\n public cleanup(): void {\n if (this.resizer) {\n this.resizer.cleanup();\n this.resizer = null;\n }\n\n // Clean up shimmer loader\n this.hideShimmerLoader();\n\n // Clean up close button\n if (this.closeButton && this.closeButton.parentNode) {\n this.closeButton.parentNode.removeChild(this.closeButton);\n this.closeButton = null;\n }\n\n // Clean up message listener\n if (this.iframeReadyMessageListener) {\n window.removeEventListener(\"message\", this.iframeReadyMessageListener);\n this.iframeReadyMessageListener = undefined;\n }\n\n if (this.iframe && this.iframe.parentNode) {\n this.iframe.parentNode.removeChild(this.iframe);\n this.iframe = null;\n }\n\n // Reset loading state\n this.isIframeLoaded = false;\n\n // Remove keyboard event listener\n if (this.keydownHandler) {\n window.removeEventListener(\"keydown\", this.keydownHandler);\n this.keydownHandler = undefined;\n }\n\n // Remove click event listener\n if (this.clickHandler) {\n this.container.removeEventListener(\"click\", this.clickHandler);\n this.clickHandler = undefined;\n }\n\n // Clear container content and reset styles\n this.container.innerHTML = \"\";\n\n if (this.displayMode === \"modal\") {\n // Reset all modal-specific styles to ensure clean state\n this.resetModalStyles();\n }\n }\n\n /**\n * Resets all modal-specific styles by removing CSS properties that were set with !important\n */\n private resetModalStyles(): void {\n const modalStyleProperties = [\n \"position\",\n \"left\",\n \"top\",\n \"width\",\n \"height\",\n \"z-index\",\n \"display\",\n \"align-items\",\n \"justify-content\",\n \"background-color\",\n \"backdrop-filter\",\n \"opacity\",\n \"transition\",\n \"margin\",\n \"padding\",\n \"border\",\n \"border-radius\",\n \"min-height\",\n ];\n\n modalStyleProperties.forEach((property) => {\n this.container.style.removeProperty(property);\n });\n }\n\n public resize(): void {\n if (this.resizer) {\n this.resizer.resize();\n }\n }\n}\n"]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare class CivicIframeResizer {
|
|
2
|
+
private iframe;
|
|
3
|
+
private container;
|
|
4
|
+
private logger;
|
|
5
|
+
private messageListener;
|
|
6
|
+
private requestSizeTimeouts;
|
|
7
|
+
constructor(iframe: HTMLIFrameElement, container: HTMLElement);
|
|
8
|
+
private initializeResizer;
|
|
9
|
+
private handleMessage;
|
|
10
|
+
private requestSizeFromChild;
|
|
11
|
+
private resizeIframe;
|
|
12
|
+
cleanup(): void;
|
|
13
|
+
resize(): void;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=IframeResizer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IframeResizer.d.ts","sourceRoot":"","sources":["../../../src/vanillajs/iframe/IframeResizer.ts"],"names":[],"mappings":"AAeA,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,SAAS,CAAc;IAC/B,OAAO,CAAC,MAAM,CAAkC;IAChD,OAAO,CAAC,eAAe,CAAgD;IACvE,OAAO,CAAC,mBAAmB,CAAgB;gBAE/B,MAAM,EAAE,iBAAiB,EAAE,SAAS,EAAE,WAAW;IAQ7D,OAAO,CAAC,iBAAiB;IA0BzB,OAAO,CAAC,aAAa;IAiCrB,OAAO,CAAC,oBAAoB;IAW5B,OAAO,CAAC,YAAY;IAyCb,OAAO,IAAI,IAAI;IAef,MAAM,IAAI,IAAI;CAItB"}
|