@lukso/up-connector 0.4.0-dev.a8c9315
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/LICENSE +201 -0
- package/README.md +280 -0
- package/dist/account-modal.cjs +9 -0
- package/dist/account-modal.cjs.map +1 -0
- package/dist/account-modal.d.cts +16 -0
- package/dist/account-modal.d.ts +16 -0
- package/dist/account-modal.js +9 -0
- package/dist/account-modal.js.map +1 -0
- package/dist/auto-setup.cjs +17 -0
- package/dist/auto-setup.cjs.map +1 -0
- package/dist/auto-setup.d.cts +123 -0
- package/dist/auto-setup.d.ts +123 -0
- package/dist/auto-setup.js +17 -0
- package/dist/auto-setup.js.map +1 -0
- package/dist/avatar-CmUCtW_w.d.cts +205 -0
- package/dist/avatar-CmUCtW_w.d.ts +205 -0
- package/dist/avatar.cjs +12 -0
- package/dist/avatar.cjs.map +1 -0
- package/dist/avatar.d.cts +1 -0
- package/dist/avatar.d.ts +1 -0
- package/dist/avatar.js +12 -0
- package/dist/avatar.js.map +1 -0
- package/dist/backup-modal.cjs +9 -0
- package/dist/backup-modal.cjs.map +1 -0
- package/dist/backup-modal.d.cts +41 -0
- package/dist/backup-modal.d.ts +41 -0
- package/dist/backup-modal.js +9 -0
- package/dist/backup-modal.js.map +1 -0
- package/dist/chunk-3SGSPHOZ.js +595 -0
- package/dist/chunk-3SGSPHOZ.js.map +1 -0
- package/dist/chunk-6AYZOIFY.js +181 -0
- package/dist/chunk-6AYZOIFY.js.map +1 -0
- package/dist/chunk-6N35TCFT.js +852 -0
- package/dist/chunk-6N35TCFT.js.map +1 -0
- package/dist/chunk-7ETKG6KR.cjs +387 -0
- package/dist/chunk-7ETKG6KR.cjs.map +1 -0
- package/dist/chunk-EUXUH3YW.js +15 -0
- package/dist/chunk-EUXUH3YW.js.map +1 -0
- package/dist/chunk-GFVUWAG4.cjs +158 -0
- package/dist/chunk-GFVUWAG4.cjs.map +1 -0
- package/dist/chunk-IAKQFHFD.cjs +595 -0
- package/dist/chunk-IAKQFHFD.cjs.map +1 -0
- package/dist/chunk-MH7MP7XK.cjs +181 -0
- package/dist/chunk-MH7MP7XK.cjs.map +1 -0
- package/dist/chunk-NWCNJSG3.js +387 -0
- package/dist/chunk-NWCNJSG3.js.map +1 -0
- package/dist/chunk-NXU2DQAV.js +1128 -0
- package/dist/chunk-NXU2DQAV.js.map +1 -0
- package/dist/chunk-ORJK2YGG.cjs +852 -0
- package/dist/chunk-ORJK2YGG.cjs.map +1 -0
- package/dist/chunk-RFA6SEIS.cjs +1128 -0
- package/dist/chunk-RFA6SEIS.cjs.map +1 -0
- package/dist/chunk-XGIT7YUY.js +31 -0
- package/dist/chunk-XGIT7YUY.js.map +1 -0
- package/dist/chunk-XOKG3KIL.cjs +31 -0
- package/dist/chunk-XOKG3KIL.cjs.map +1 -0
- package/dist/chunk-YIWSPI4I.js +158 -0
- package/dist/chunk-YIWSPI4I.js.map +1 -0
- package/dist/chunk-ZBDE64SD.cjs +15 -0
- package/dist/chunk-ZBDE64SD.cjs.map +1 -0
- package/dist/connect-modal/index.cjs +20 -0
- package/dist/connect-modal/index.cjs.map +1 -0
- package/dist/connect-modal/index.d.cts +9 -0
- package/dist/connect-modal/index.d.ts +9 -0
- package/dist/connect-modal/index.js +20 -0
- package/dist/connect-modal/index.js.map +1 -0
- package/dist/index-D2orHGFi.d.cts +8 -0
- package/dist/index-D2orHGFi.d.ts +8 -0
- package/dist/index.cjs +793 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +189 -0
- package/dist/index.d.ts +189 -0
- package/dist/index.js +793 -0
- package/dist/index.js.map +1 -0
- package/dist/restore-modal.cjs +9 -0
- package/dist/restore-modal.cjs.map +1 -0
- package/dist/restore-modal.d.cts +68 -0
- package/dist/restore-modal.d.ts +68 -0
- package/dist/restore-modal.js +9 -0
- package/dist/restore-modal.js.map +1 -0
- package/dist/wagmi-CVuDs_0h.d.cts +386 -0
- package/dist/wagmi-CVuDs_0h.d.ts +386 -0
- package/package.json +158 -0
- package/src/account-modal.ts +142 -0
- package/src/auto-setup.ts +362 -0
- package/src/avatar.ts +1135 -0
- package/src/backup-modal.ts +439 -0
- package/src/connect-modal/components/connection-view.ts +398 -0
- package/src/connect-modal/components/eoa-connection-view.ts +408 -0
- package/src/connect-modal/components/qr-code-view.ts +71 -0
- package/src/connect-modal/connect-modal.base.ts +18 -0
- package/src/connect-modal/connect-modal.config.ts +27 -0
- package/src/connect-modal/connect-modal.templates.ts +21 -0
- package/src/connect-modal/connect-modal.ts +270 -0
- package/src/connect-modal/connect-modal.types.ts +104 -0
- package/src/connect-modal/images/up-cube-glass.png +0 -0
- package/src/connect-modal/index.ts +23 -0
- package/src/connect-modal/services/wagmi.ts +266 -0
- package/src/connect-modal/styles/styles.css +1 -0
- package/src/connect-modal/utils/walletConnectDeepLinkUrl.ts +43 -0
- package/src/connector.ts +544 -0
- package/src/index.ts +62 -0
- package/src/popup-instance.ts +537 -0
- package/src/restore-modal.ts +702 -0
- package/src/styles/index.ts +28 -0
- package/src/styles/styles.css +1 -0
- package/src/types/css-raw.d.ts +4 -0
- package/src/types/images.d.ts +4 -0
- package/src/types.ts +168 -0
|
@@ -0,0 +1,537 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enhanced Popup System for UP Connector
|
|
3
|
+
* Provides unified interface for both popup windows and modal dialogs
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface PopupRequest {
|
|
7
|
+
mode: 'popup' | 'modal' // popup = window.open, modal = iframe in modal
|
|
8
|
+
url?: string // If present = external, if not = local content
|
|
9
|
+
size?: { width: number; height: number }
|
|
10
|
+
position?: 'center' | 'top-right'
|
|
11
|
+
allowedOrigins?: string[] // Security for message passing
|
|
12
|
+
reuseExisting?: boolean // Whether to reuse existing popups (default: true)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface PopupInstance {
|
|
16
|
+
// Lifecycle Management
|
|
17
|
+
show(): Promise<void> // Show the popup/modal - async for consistency
|
|
18
|
+
hide(): void // Hide but preserve state
|
|
19
|
+
close(): void // Actually destroy
|
|
20
|
+
|
|
21
|
+
// Message Passing
|
|
22
|
+
postMessage(data: any): void // Send to popup/iframe
|
|
23
|
+
onMessage(handler: (data: any) => void): void // Receive from popup/iframe
|
|
24
|
+
removeMessageHandler(handler: (data: any) => void): void // Remove handler
|
|
25
|
+
|
|
26
|
+
// State Queries
|
|
27
|
+
isVisible: boolean // Whether currently visible
|
|
28
|
+
isClosed: boolean // Whether destroyed
|
|
29
|
+
contentWindow?: Window // For advanced use
|
|
30
|
+
|
|
31
|
+
// Events
|
|
32
|
+
on(
|
|
33
|
+
event: 'show' | 'hide' | 'close' | 'message',
|
|
34
|
+
handler: (...args: any[]) => void
|
|
35
|
+
): void
|
|
36
|
+
off(
|
|
37
|
+
event: 'show' | 'hide' | 'close' | 'message',
|
|
38
|
+
handler: (...args: any[]) => void
|
|
39
|
+
): void
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface UIDelegate {
|
|
43
|
+
createPopup(request: PopupRequest): PopupInstance
|
|
44
|
+
showPopup(request: PopupRequest): Promise<PopupInstance>
|
|
45
|
+
closeAll(): void
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Internal event emitter for popup instances
|
|
49
|
+
class PopupEventEmitter {
|
|
50
|
+
private handlers = new Map<string, Set<(...args: any[]) => void>>()
|
|
51
|
+
|
|
52
|
+
on(event: string, handler: (...args: any[]) => void): void {
|
|
53
|
+
if (!this.handlers.has(event)) {
|
|
54
|
+
this.handlers.set(event, new Set())
|
|
55
|
+
}
|
|
56
|
+
this.handlers.get(event)!.add(handler)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
off(event: string, handler: (...args: any[]) => void): void {
|
|
60
|
+
this.handlers.get(event)?.delete(handler)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
emit(event: string, ...args: any[]): void {
|
|
64
|
+
this.handlers.get(event)?.forEach((handler) => {
|
|
65
|
+
try {
|
|
66
|
+
handler(...args)
|
|
67
|
+
} catch (error) {
|
|
68
|
+
console.error('Error in popup event handler:', error)
|
|
69
|
+
}
|
|
70
|
+
})
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
clear(): void {
|
|
74
|
+
this.handlers.clear()
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Base class for popup instances
|
|
80
|
+
*/
|
|
81
|
+
abstract class BasePopupInstance implements PopupInstance {
|
|
82
|
+
protected events = new PopupEventEmitter()
|
|
83
|
+
protected messageHandlers = new Set<(data: any) => void>()
|
|
84
|
+
protected _isClosed = false
|
|
85
|
+
protected _isVisible = false
|
|
86
|
+
|
|
87
|
+
constructor(protected request: PopupRequest) {}
|
|
88
|
+
|
|
89
|
+
abstract show(): Promise<void>
|
|
90
|
+
abstract hide(): void
|
|
91
|
+
abstract close(): void
|
|
92
|
+
abstract get contentWindow(): Window | undefined
|
|
93
|
+
|
|
94
|
+
get isVisible(): boolean {
|
|
95
|
+
return this._isVisible && !this._isClosed
|
|
96
|
+
}
|
|
97
|
+
get isClosed(): boolean {
|
|
98
|
+
return this._isClosed
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
postMessage(data: any): void {
|
|
102
|
+
if (!this._isClosed && this.contentWindow) {
|
|
103
|
+
try {
|
|
104
|
+
this.contentWindow.postMessage(data, '*')
|
|
105
|
+
} catch (error) {
|
|
106
|
+
console.error('Failed to post message to popup:', error)
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
onMessage(handler: (data: any) => void): void {
|
|
112
|
+
this.messageHandlers.add(handler)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
removeMessageHandler(handler: (data: any) => void): void {
|
|
116
|
+
this.messageHandlers.delete(handler)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
protected handleMessage(data: any): void {
|
|
120
|
+
this.messageHandlers.forEach((handler) => {
|
|
121
|
+
try {
|
|
122
|
+
handler(data)
|
|
123
|
+
} catch (error) {
|
|
124
|
+
console.error('Error in popup message handler:', error)
|
|
125
|
+
}
|
|
126
|
+
})
|
|
127
|
+
this.events.emit('message', data)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
on(
|
|
131
|
+
event: 'show' | 'hide' | 'close' | 'message',
|
|
132
|
+
handler: (...args: any[]) => void
|
|
133
|
+
): void {
|
|
134
|
+
this.events.on(event, handler)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
off(
|
|
138
|
+
event: 'show' | 'hide' | 'close' | 'message',
|
|
139
|
+
handler: (...args: any[]) => void
|
|
140
|
+
): void {
|
|
141
|
+
this.events.off(event, handler)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
protected cleanup(): void {
|
|
145
|
+
this.messageHandlers.clear()
|
|
146
|
+
this.events.clear()
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Modal popup implementation (iframe in modal dialog)
|
|
152
|
+
*/
|
|
153
|
+
export class ModalPopupInstance extends BasePopupInstance {
|
|
154
|
+
private modalElement?: HTMLDivElement
|
|
155
|
+
private iframeElement?: HTMLIFrameElement
|
|
156
|
+
private messageListener?: (event: MessageEvent) => void
|
|
157
|
+
|
|
158
|
+
async show(): Promise<void> {
|
|
159
|
+
if (this._isClosed) {
|
|
160
|
+
throw new Error('Popup is closed')
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (!this.modalElement) {
|
|
164
|
+
await this.createElement()
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return new Promise((resolve) => {
|
|
168
|
+
if (!this.modalElement) {
|
|
169
|
+
resolve()
|
|
170
|
+
return
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Add to DOM if not already present
|
|
174
|
+
if (!this.modalElement.parentNode) {
|
|
175
|
+
document.body.appendChild(this.modalElement)
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
this._isVisible = true
|
|
179
|
+
|
|
180
|
+
// Force reflow before adding visible class
|
|
181
|
+
this.modalElement.offsetHeight
|
|
182
|
+
this.modalElement.classList.add('visible')
|
|
183
|
+
|
|
184
|
+
this.events.emit('show')
|
|
185
|
+
|
|
186
|
+
// Wait for animation
|
|
187
|
+
setTimeout(() => resolve(), 50)
|
|
188
|
+
})
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
hide(): void {
|
|
192
|
+
if (!this._isVisible || this._isClosed || !this.modalElement) return
|
|
193
|
+
|
|
194
|
+
this._isVisible = false
|
|
195
|
+
this.modalElement.classList.remove('visible')
|
|
196
|
+
this.events.emit('hide')
|
|
197
|
+
|
|
198
|
+
// Remove from DOM after animation
|
|
199
|
+
setTimeout(() => {
|
|
200
|
+
if (this.modalElement && this.modalElement.parentNode) {
|
|
201
|
+
this.modalElement.parentNode.removeChild(this.modalElement)
|
|
202
|
+
}
|
|
203
|
+
}, 300)
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
close(): void {
|
|
207
|
+
if (this._isClosed) return
|
|
208
|
+
|
|
209
|
+
this._isClosed = true
|
|
210
|
+
this._isVisible = false
|
|
211
|
+
|
|
212
|
+
if (this.modalElement) {
|
|
213
|
+
this.modalElement.classList.remove('visible')
|
|
214
|
+
setTimeout(() => {
|
|
215
|
+
if (this.modalElement && this.modalElement.parentNode) {
|
|
216
|
+
this.modalElement.parentNode.removeChild(this.modalElement)
|
|
217
|
+
}
|
|
218
|
+
}, 300)
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (this.messageListener) {
|
|
222
|
+
window.removeEventListener('message', this.messageListener)
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
this.events.emit('close')
|
|
226
|
+
this.cleanup()
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
get contentWindow(): Window | undefined {
|
|
230
|
+
return this.iframeElement?.contentWindow || undefined
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
private async createElement(): Promise<void> {
|
|
234
|
+
if (typeof document === 'undefined') return
|
|
235
|
+
|
|
236
|
+
await this.createStyles()
|
|
237
|
+
|
|
238
|
+
// Create modal structure
|
|
239
|
+
this.modalElement = document.createElement('div')
|
|
240
|
+
this.modalElement.className = 'up-popup-modal'
|
|
241
|
+
|
|
242
|
+
const { width = 480, height = 640 } = this.request.size || {}
|
|
243
|
+
|
|
244
|
+
this.modalElement.innerHTML = `
|
|
245
|
+
<div class="up-popup-modal-content" style="width: ${width}px; height: ${height}px;">
|
|
246
|
+
<button class="up-popup-close" type="button">
|
|
247
|
+
<svg width="20" height="20" viewBox="0 0 20 20" fill="currentColor">
|
|
248
|
+
<path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd" />
|
|
249
|
+
</svg>
|
|
250
|
+
</button>
|
|
251
|
+
<iframe src="${this.request.url || 'about:blank'}" allow="publickey-credentials-get; publickey-credentials-create"></iframe>
|
|
252
|
+
</div>
|
|
253
|
+
`
|
|
254
|
+
|
|
255
|
+
// Get references
|
|
256
|
+
const closeButton = this.modalElement.querySelector(
|
|
257
|
+
'.up-popup-close'
|
|
258
|
+
) as HTMLButtonElement
|
|
259
|
+
this.iframeElement = this.modalElement.querySelector(
|
|
260
|
+
'iframe'
|
|
261
|
+
) as HTMLIFrameElement
|
|
262
|
+
|
|
263
|
+
// Event listeners
|
|
264
|
+
closeButton.addEventListener('click', () => this.hide())
|
|
265
|
+
|
|
266
|
+
this.modalElement.addEventListener('click', (e) => {
|
|
267
|
+
if (e.target === this.modalElement) {
|
|
268
|
+
this.hide()
|
|
269
|
+
}
|
|
270
|
+
})
|
|
271
|
+
|
|
272
|
+
// Message handling
|
|
273
|
+
this.messageListener = (event: MessageEvent) => {
|
|
274
|
+
// Only handle messages from our iframe
|
|
275
|
+
if (event.source === this.iframeElement?.contentWindow) {
|
|
276
|
+
this.handleMessage(event.data)
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
window.addEventListener('message', this.messageListener)
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
private async createStyles(): Promise<void> {
|
|
283
|
+
if (typeof document === 'undefined') return
|
|
284
|
+
|
|
285
|
+
if (document.querySelector('#up-popup-modal-styles')) return
|
|
286
|
+
|
|
287
|
+
const style = document.createElement('style')
|
|
288
|
+
style.id = 'up-popup-modal-styles'
|
|
289
|
+
style.textContent = `
|
|
290
|
+
.up-popup-modal {
|
|
291
|
+
position: fixed;
|
|
292
|
+
top: 0;
|
|
293
|
+
left: 0;
|
|
294
|
+
width: 100vw;
|
|
295
|
+
height: 100vh;
|
|
296
|
+
background: rgba(0, 0, 0, 0.5);
|
|
297
|
+
backdrop-filter: blur(8px);
|
|
298
|
+
z-index: 10000;
|
|
299
|
+
display: flex;
|
|
300
|
+
align-items: center;
|
|
301
|
+
justify-content: center;
|
|
302
|
+
opacity: 0;
|
|
303
|
+
visibility: hidden;
|
|
304
|
+
transition: all 300ms cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
|
305
|
+
padding: 16px;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
.up-popup-modal.visible {
|
|
309
|
+
opacity: 1;
|
|
310
|
+
visibility: visible;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
.up-popup-modal-content {
|
|
314
|
+
background: white;
|
|
315
|
+
border-radius: 12px;
|
|
316
|
+
overflow: hidden;
|
|
317
|
+
position: relative;
|
|
318
|
+
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
|
319
|
+
transform: scale(0.95) translateY(20px);
|
|
320
|
+
transition: all 300ms cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
.up-popup-modal.visible .up-popup-modal-content {
|
|
324
|
+
transform: scale(1) translateY(0);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
.up-popup-close {
|
|
328
|
+
position: absolute;
|
|
329
|
+
top: 12px;
|
|
330
|
+
right: 12px;
|
|
331
|
+
z-index: 10;
|
|
332
|
+
background: rgba(255, 255, 255, 0.9);
|
|
333
|
+
border: none;
|
|
334
|
+
border-radius: 50%;
|
|
335
|
+
width: 32px;
|
|
336
|
+
height: 32px;
|
|
337
|
+
cursor: pointer;
|
|
338
|
+
display: flex;
|
|
339
|
+
align-items: center;
|
|
340
|
+
justify-content: center;
|
|
341
|
+
color: #6b7280;
|
|
342
|
+
transition: all 0.2s ease;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
.up-popup-close:hover {
|
|
346
|
+
background: rgba(255, 255, 255, 1);
|
|
347
|
+
color: #374151;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
.up-popup-modal iframe {
|
|
351
|
+
width: 100%;
|
|
352
|
+
height: 100%;
|
|
353
|
+
border: none;
|
|
354
|
+
border-radius: 12px;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
@media (max-width: 640px) {
|
|
358
|
+
.up-popup-modal {
|
|
359
|
+
padding: 0;
|
|
360
|
+
align-items: flex-end;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
.up-popup-modal-content {
|
|
364
|
+
width: 100% !important;
|
|
365
|
+
height: 85vh !important;
|
|
366
|
+
border-radius: 12px 12px 0 0;
|
|
367
|
+
transform: translateY(100%);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
.up-popup-modal.visible .up-popup-modal-content {
|
|
371
|
+
transform: translateY(0);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
.up-popup-modal iframe {
|
|
375
|
+
border-radius: 12px 12px 0 0;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
@media (max-width: 480px) {
|
|
380
|
+
.up-popup-modal {
|
|
381
|
+
align-items: stretch;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
.up-popup-modal-content {
|
|
385
|
+
height: 100vh !important;
|
|
386
|
+
border-radius: 0;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
.up-popup-modal iframe {
|
|
390
|
+
border-radius: 0;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
`
|
|
394
|
+
document.head.appendChild(style)
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* Window popup implementation (actual popup window)
|
|
400
|
+
*/
|
|
401
|
+
export class WindowPopupInstance extends BasePopupInstance {
|
|
402
|
+
private popupWindow: Window | null = null
|
|
403
|
+
private messageListener?: (event: MessageEvent) => void
|
|
404
|
+
|
|
405
|
+
async show(): Promise<void> {
|
|
406
|
+
if (this._isClosed) {
|
|
407
|
+
throw new Error('Popup is closed')
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
if (!this.popupWindow || this.popupWindow.closed) {
|
|
411
|
+
await this.createPopupWindow()
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
if (this.popupWindow && !this.popupWindow.closed) {
|
|
415
|
+
this.popupWindow.focus()
|
|
416
|
+
this._isVisible = true
|
|
417
|
+
this.events.emit('show')
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
hide(): void {
|
|
422
|
+
// For popup windows, hide typically means minimize or move to background
|
|
423
|
+
// Since we can't directly minimize, we just blur it
|
|
424
|
+
if (this.popupWindow && !this.popupWindow.closed) {
|
|
425
|
+
this.popupWindow.blur()
|
|
426
|
+
}
|
|
427
|
+
this._isVisible = false
|
|
428
|
+
this.events.emit('hide')
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
close(): void {
|
|
432
|
+
if (this._isClosed) return
|
|
433
|
+
|
|
434
|
+
this._isClosed = true
|
|
435
|
+
this._isVisible = false
|
|
436
|
+
|
|
437
|
+
if (this.popupWindow && !this.popupWindow.closed) {
|
|
438
|
+
this.popupWindow.close()
|
|
439
|
+
}
|
|
440
|
+
this.popupWindow = null
|
|
441
|
+
|
|
442
|
+
if (this.messageListener) {
|
|
443
|
+
window.removeEventListener('message', this.messageListener)
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
this.events.emit('close')
|
|
447
|
+
this.cleanup()
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
get contentWindow(): Window | undefined {
|
|
451
|
+
return this.popupWindow && !this.popupWindow.closed
|
|
452
|
+
? this.popupWindow
|
|
453
|
+
: undefined
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
get isVisible(): boolean {
|
|
457
|
+
return !this._isClosed && !!(this.popupWindow && !this.popupWindow.closed)
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
private async createPopupWindow(): Promise<void> {
|
|
461
|
+
if (!this.request.url) {
|
|
462
|
+
throw new Error('URL required for popup windows')
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
const { width = 400, height = 600 } = this.request.size || {}
|
|
466
|
+
const position = this.request.position || 'center'
|
|
467
|
+
const features = [
|
|
468
|
+
`width=${width}`,
|
|
469
|
+
`height=${height}`,
|
|
470
|
+
...this.getPositionFeatures(position, width, height),
|
|
471
|
+
'scrollbars=yes',
|
|
472
|
+
'resizable=yes',
|
|
473
|
+
'status=no',
|
|
474
|
+
'location=no',
|
|
475
|
+
'toolbar=no',
|
|
476
|
+
'menubar=no',
|
|
477
|
+
].join(',')
|
|
478
|
+
|
|
479
|
+
this.popupWindow = window.open(this.request.url, '_blank', features)
|
|
480
|
+
|
|
481
|
+
if (!this.popupWindow) {
|
|
482
|
+
throw new Error('Popup blocked or failed to open')
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
// Setup message listener
|
|
486
|
+
this.messageListener = (event: MessageEvent) => {
|
|
487
|
+
if (event.source === this.popupWindow) {
|
|
488
|
+
this.handleMessage(event.data)
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
window.addEventListener('message', this.messageListener)
|
|
492
|
+
|
|
493
|
+
// Monitor popup close
|
|
494
|
+
const checkClosed = () => {
|
|
495
|
+
if (this.popupWindow?.closed && !this._isClosed) {
|
|
496
|
+
this.close()
|
|
497
|
+
} else if (!this._isClosed) {
|
|
498
|
+
setTimeout(checkClosed, 1000)
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
setTimeout(checkClosed, 1000)
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
private getPositionFeatures(
|
|
505
|
+
position: string,
|
|
506
|
+
width: number,
|
|
507
|
+
height: number
|
|
508
|
+
): string[] {
|
|
509
|
+
const screenLeft =
|
|
510
|
+
window.screenLeft !== undefined ? window.screenLeft : window.screenX
|
|
511
|
+
const screenTop =
|
|
512
|
+
window.screenTop !== undefined ? window.screenTop : window.screenY
|
|
513
|
+
const windowWidth =
|
|
514
|
+
window.innerWidth || document.documentElement.clientWidth || screen.width
|
|
515
|
+
const windowHeight =
|
|
516
|
+
window.innerHeight ||
|
|
517
|
+
document.documentElement.clientHeight ||
|
|
518
|
+
screen.height
|
|
519
|
+
|
|
520
|
+
let left: number
|
|
521
|
+
let top: number
|
|
522
|
+
|
|
523
|
+
switch (position) {
|
|
524
|
+
case 'top-right':
|
|
525
|
+
left = screenLeft + windowWidth - width - 20
|
|
526
|
+
top = screenTop + 20
|
|
527
|
+
break
|
|
528
|
+
case 'center':
|
|
529
|
+
default:
|
|
530
|
+
left = screenLeft + (windowWidth - width) / 2
|
|
531
|
+
top = screenTop + (windowHeight - height) / 2
|
|
532
|
+
break
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
return [`left=${Math.max(0, left)}`, `top=${Math.max(0, top)}`]
|
|
536
|
+
}
|
|
537
|
+
}
|