@yuno-payments/dashboard-embed-sdk 1.3.0 → 1.4.0-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/README.md +14 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +37 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -291,6 +291,20 @@ content resizes; the SDK applies that height to the iframe and its wrapper. Mess
|
|
|
291
291
|
accepted only from the configured `baseUrl` origin. Your container must allow vertical growth
|
|
292
292
|
(avoid a fixed `height` / `overflow: hidden`) for the effect to be visible.
|
|
293
293
|
|
|
294
|
+
## Overlays (modals & drawers)
|
|
295
|
+
|
|
296
|
+
An embedded overlay is positioned relative to **its iframe**, not the host page — so a
|
|
297
|
+
modal would appear centered to the iframe panel, not the browser viewport. To fix this,
|
|
298
|
+
the embedded dashboard signals the SDK when an overlay opens or closes
|
|
299
|
+
(`embed-event` with `domain: "ui"`, `action: "overlay-open" | "overlay-close"`), and the
|
|
300
|
+
**SDK expands the iframe to the full viewport** (`position: fixed; inset: 0`, top
|
|
301
|
+
`z-index`) for as long as any overlay is open, then restores it. This is automatic — no
|
|
302
|
+
host code required. Signals are ref-counted, so stacked overlays are handled correctly.
|
|
303
|
+
|
|
304
|
+
**Host/iframe contract:** while an overlay is open the iframe covers the whole viewport.
|
|
305
|
+
Ensure no host element needs to sit above it during that time (the SDK uses a maximal
|
|
306
|
+
`z-index`). Messages are accepted only from the configured `baseUrl` origin.
|
|
307
|
+
|
|
294
308
|
## Migrating from 0.x to 1.0
|
|
295
309
|
|
|
296
310
|
`1.0.0` drops the `Yuno` brand prefix from the public API so the SDK reads cleanly
|
package/dist/index.d.ts
CHANGED
|
@@ -90,6 +90,8 @@ declare class Dashboard {
|
|
|
90
90
|
private onSessionExpiredCallback?;
|
|
91
91
|
private events?;
|
|
92
92
|
private autoHeight;
|
|
93
|
+
private overlayCount;
|
|
94
|
+
private savedIframeCss;
|
|
93
95
|
constructor(config: DashboardConfig);
|
|
94
96
|
setTheme(theme: DashboardTheme): void;
|
|
95
97
|
setLang(lang: string): void;
|
|
@@ -99,6 +101,9 @@ declare class Dashboard {
|
|
|
99
101
|
destroy(): void;
|
|
100
102
|
private invokeCallback;
|
|
101
103
|
private dispatchEmbedEvent;
|
|
104
|
+
private handleOverlaySignal;
|
|
105
|
+
private expandToViewport;
|
|
106
|
+
private restoreIframe;
|
|
102
107
|
private post;
|
|
103
108
|
private flush;
|
|
104
109
|
private onReady;
|
package/dist/index.js
CHANGED
|
@@ -22,6 +22,11 @@ var Dashboard = class {
|
|
|
22
22
|
this.overlay = null;
|
|
23
23
|
this.ready = false;
|
|
24
24
|
this.queue = [];
|
|
25
|
+
// Overlay (modal/drawer) mode: while >0 the iframe is expanded to the full
|
|
26
|
+
// viewport so the dashboard's overlay centers to the host page, not the
|
|
27
|
+
// iframe. Ref-counted to survive stacked overlays.
|
|
28
|
+
this.overlayCount = 0;
|
|
29
|
+
this.savedIframeCss = null;
|
|
25
30
|
this.baseUrl = config.baseUrl;
|
|
26
31
|
this.initialTheme = config.theme;
|
|
27
32
|
this.initialLang = config.lang;
|
|
@@ -108,6 +113,8 @@ var Dashboard = class {
|
|
|
108
113
|
this.wrapper.remove();
|
|
109
114
|
this.queue = [];
|
|
110
115
|
this.ready = false;
|
|
116
|
+
this.overlayCount = 0;
|
|
117
|
+
this.savedIframeCss = null;
|
|
111
118
|
}
|
|
112
119
|
// Runs a host callback, swallowing sync throws and async rejections so a
|
|
113
120
|
// misbehaving host handler can never break the SDK's message loop.
|
|
@@ -131,6 +138,10 @@ var Dashboard = class {
|
|
|
131
138
|
const domain = data?.domain;
|
|
132
139
|
const action = data?.action;
|
|
133
140
|
if (typeof domain !== "string" || typeof action !== "string") return;
|
|
141
|
+
if (domain === "ui") {
|
|
142
|
+
this.handleOverlaySignal(action);
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
134
145
|
const groups = this.events;
|
|
135
146
|
const handler = groups?.[domain]?.[action];
|
|
136
147
|
if (!handler) return;
|
|
@@ -139,6 +150,32 @@ var Dashboard = class {
|
|
|
139
150
|
() => handler({ status: data?.status, payload: data?.payload })
|
|
140
151
|
);
|
|
141
152
|
}
|
|
153
|
+
// Expands the iframe to the full viewport on the first open and restores it
|
|
154
|
+
// once the last overlay closes (ref-counted for stacked overlays).
|
|
155
|
+
handleOverlaySignal(action) {
|
|
156
|
+
if (action === "overlay-open") {
|
|
157
|
+
if (this.overlayCount === 0) this.expandToViewport();
|
|
158
|
+
this.overlayCount += 1;
|
|
159
|
+
} else if (action === "overlay-close") {
|
|
160
|
+
if (this.overlayCount === 0) return;
|
|
161
|
+
this.overlayCount -= 1;
|
|
162
|
+
if (this.overlayCount === 0) this.restoreIframe();
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
expandToViewport() {
|
|
166
|
+
this.savedIframeCss = this.iframe.style.cssText;
|
|
167
|
+
Object.assign(this.iframe.style, {
|
|
168
|
+
position: "fixed",
|
|
169
|
+
inset: "0",
|
|
170
|
+
width: "100%",
|
|
171
|
+
height: "100%",
|
|
172
|
+
zIndex: "2147483647"
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
restoreIframe() {
|
|
176
|
+
this.iframe.style.cssText = this.savedIframeCss ?? "";
|
|
177
|
+
this.savedIframeCss = null;
|
|
178
|
+
}
|
|
142
179
|
post(message) {
|
|
143
180
|
if (this.ready && this.iframe.contentWindow) {
|
|
144
181
|
this.iframe.contentWindow.postMessage(message, this.baseUrl);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/dashboard.ts","../src/singleton.ts"],"sourcesContent":["import type { DashboardTheme, DashboardConfig, DashboardEvents } from \"./types\";\n\nconst EMBED_EVENT_MESSAGE_TYPE = \"yuno-dashboard:embed-event\";\nconst HOST_CAPABILITIES_MESSAGE_TYPE = \"yuno-dashboard:host-capabilities\";\n\ntype EmbedEventHandler = (event: {\n status?: unknown;\n payload?: unknown;\n}) => void | Promise<void>;\n\n// Build the capability map the dashboard reads to decide which actions the\n// host owns: { connections: { created: true }, ... } for every provided handler.\nfunction buildCapabilities(\n events?: DashboardEvents,\n): Record<string, Record<string, boolean>> {\n const capabilities: Record<string, Record<string, boolean>> = {};\n if (!events) return capabilities;\n const groups = events as Record<string, Record<string, unknown> | undefined>;\n for (const domain of Object.keys(groups)) {\n const group = groups[domain];\n if (!group) continue;\n for (const action of Object.keys(group)) {\n if (typeof group[action] === \"function\") {\n capabilities[domain] = capabilities[domain] ?? {};\n capabilities[domain][action] = true;\n }\n }\n }\n return capabilities;\n}\n\nexport class Dashboard {\n private iframe: HTMLIFrameElement;\n private wrapper: HTMLDivElement;\n private overlay: HTMLElement | null = null;\n private baseUrl: string;\n private ready = false;\n private queue: Record<string, unknown>[] = [];\n private messageHandler: (e: MessageEvent) => void;\n private initialTheme?: DashboardTheme;\n private initialLang?: string;\n private initialPath: string;\n private initialTestMode?: boolean;\n private token?: string;\n private onReadyCallback?: () => void;\n private onSessionExpiredCallback?: () => void | Promise<void>;\n private events?: DashboardEvents;\n private autoHeight: boolean;\n\n constructor(config: DashboardConfig) {\n this.baseUrl = config.baseUrl;\n this.initialTheme = config.theme;\n this.initialLang = config.lang;\n this.initialPath = config.path ?? \"/\";\n this.initialTestMode = config.testMode;\n this.token = config.token;\n this.onReadyCallback = config.onReady;\n this.onSessionExpiredCallback = config.onSessionExpired;\n this.events = config.events;\n this.autoHeight = config.autoHeight ?? false;\n\n this.wrapper = document.createElement(\"div\");\n this.wrapper.style.position = \"relative\";\n this.wrapper.style.width = \"100%\";\n this.wrapper.style.height = \"100%\";\n\n this.iframe = document.createElement(\"iframe\");\n this.iframe.style.width = \"100%\";\n this.iframe.style.height = \"100%\";\n this.iframe.style.border = \"none\";\n this.iframe.title = \"Yuno Dashboard\";\n this.iframe.src = this.buildSrc();\n\n this.wrapper.appendChild(this.iframe);\n\n this.overlay = config.loading instanceof HTMLElement\n ? config.loading\n : this.createDefaultOverlay();\n this.overlay.style.position = \"absolute\";\n this.overlay.style.inset = \"0\";\n this.overlay.style.zIndex = \"1\";\n this.wrapper.appendChild(this.overlay);\n\n this.messageHandler = (e: MessageEvent) => {\n if (e.origin !== this.baseUrl) return;\n if (\n this.autoHeight &&\n e.data?.action === \"resize\" &&\n typeof e.data?.height === \"number\"\n ) {\n this.iframe.style.height = `${e.data.height}px`;\n this.wrapper.style.height = `${e.data.height}px`;\n return;\n }\n if (e.data?.type === \"yuno-dashboard:session-expired\") {\n this.invokeCallback(\"onSessionExpired\", () =>\n this.onSessionExpiredCallback?.(),\n );\n return;\n }\n if (e.data?.type === EMBED_EVENT_MESSAGE_TYPE) {\n this.dispatchEmbedEvent(e.data);\n return;\n }\n if (e.data?.action === \"ready\") {\n this.onReady();\n }\n if (e.data?.action === \"tokenApplied\") {\n this.onTokenApplied();\n }\n };\n window.addEventListener(\"message\", this.messageHandler);\n\n config.container.appendChild(this.wrapper);\n }\n\n setTheme(theme: DashboardTheme): void {\n if (theme.tokens || theme.typography) {\n const themePayload: Record<string, unknown> = {};\n if (theme.tokens) themePayload.colors = theme.tokens;\n if (theme.typography) themePayload.typography = theme.typography;\n this.post({ action: \"setTheme\", theme: themePayload });\n }\n if (theme.mode) {\n this.post({ action: \"setMode\", mode: theme.mode });\n }\n if (theme.styles !== undefined) {\n this.post({ action: \"setExternalStyles\", css: theme.styles });\n }\n }\n\n setLang(lang: string): void {\n this.post({ action: \"setLang\", lang });\n }\n\n setToken(token: string): void {\n this.token = token;\n this.post({ action: \"setToken\", token });\n }\n\n navigate(path: string): void {\n this.post({ action: \"navigate\", path });\n }\n\n setTestMode(enabled: boolean): void {\n this.post({ action: \"setTestMode\", testMode: enabled });\n }\n\n destroy(): void {\n window.removeEventListener(\"message\", this.messageHandler);\n this.wrapper.remove();\n this.queue = [];\n this.ready = false;\n }\n\n // Runs a host callback, swallowing sync throws and async rejections so a\n // misbehaving host handler can never break the SDK's message loop.\n private invokeCallback(\n name: string,\n run: () => void | Promise<void> | undefined,\n ): void {\n try {\n const result = run();\n if (result && typeof (result as Promise<unknown>).catch === \"function\") {\n (result as Promise<unknown>).catch((err) =>\n // eslint-disable-next-line no-console\n console.warn(`[yuno-dashboard-sdk] ${name} async callback rejected`, err),\n );\n }\n } catch (err) {\n // eslint-disable-next-line no-console\n console.warn(`[yuno-dashboard-sdk] ${name} callback threw`, err);\n }\n }\n\n // Routes an embed-event envelope to the host's events[domain][action] handler.\n private dispatchEmbedEvent(data: Record<string, unknown>): void {\n const domain = data?.domain;\n const action = data?.action;\n if (typeof domain !== \"string\" || typeof action !== \"string\") return;\n\n const groups = this.events as\n | Record<string, Record<string, EmbedEventHandler | undefined> | undefined>\n | undefined;\n const handler = groups?.[domain]?.[action];\n if (!handler) return;\n\n this.invokeCallback(`events.${domain}.${action}`, () =>\n handler({ status: data?.status, payload: data?.payload }),\n );\n }\n\n private post(message: Record<string, unknown>): void {\n if (this.ready && this.iframe.contentWindow) {\n this.iframe.contentWindow.postMessage(message, this.baseUrl);\n } else {\n this.queue.push(message);\n }\n }\n\n private flush(): void {\n const pending = this.queue.splice(0);\n for (const message of pending) {\n if (this.iframe.contentWindow) {\n this.iframe.contentWindow.postMessage(message, this.baseUrl);\n }\n }\n }\n\n private onReady(): void {\n this.ready = true;\n const capabilities = buildCapabilities(this.events);\n if (Object.keys(capabilities).length > 0) {\n this.post({ type: HOST_CAPABILITIES_MESSAGE_TYPE, capabilities });\n }\n if (this.token) {\n this.post({ action: \"setToken\", token: this.token });\n }\n if (this.initialTheme) {\n this.setTheme(this.initialTheme);\n }\n if (this.initialLang) {\n this.setLang(this.initialLang);\n }\n this.flush();\n }\n\n private onTokenApplied(): void {\n setTimeout(() => {\n this.hideOverlay();\n this.onReadyCallback?.();\n }, 1000);\n }\n\n private hideOverlay(): void {\n if (!this.overlay) return;\n this.overlay.style.transition = \"opacity 0.3s\";\n this.overlay.style.opacity = \"0\";\n setTimeout(() => this.overlay?.remove(), 300);\n }\n\n private createDefaultOverlay(): HTMLElement {\n const overlay = document.createElement(\"div\");\n overlay.style.background = \"#ffffff\";\n overlay.style.display = \"flex\";\n overlay.style.alignItems = \"center\";\n overlay.style.justifyContent = \"center\";\n\n const spinner = document.createElement(\"div\");\n spinner.style.width = \"32px\";\n spinner.style.height = \"32px\";\n spinner.style.border = \"3px solid #e0e0e0\";\n spinner.style.borderTopColor = \"#666\";\n spinner.style.borderRadius = \"50%\";\n spinner.style.animation = \"yuno-spin 0.8s linear infinite\";\n\n const style = document.createElement(\"style\");\n style.textContent = \"@keyframes yuno-spin { to { transform: rotate(360deg); } }\";\n\n overlay.appendChild(style);\n overlay.appendChild(spinner);\n return overlay;\n }\n\n private buildSrc(): string {\n const params = new URLSearchParams({\n embed: \"true\",\n theme: this.initialTheme?.mode ?? \"light\",\n lang: this.initialLang ?? \"en\",\n });\n if (this.initialTestMode !== undefined) {\n params.set(\"test\", String(this.initialTestMode));\n }\n const path = !this.initialPath || this.initialPath === \"/\" ? \"/\" : this.initialPath;\n return `${this.baseUrl}${path}?${params.toString()}`;\n }\n}\n","import { Dashboard } from \"./dashboard\";\nimport type { DashboardConfig } from \"./types\";\n\nlet instance: Dashboard | null = null;\n\nexport function initDashboard(config: DashboardConfig): Dashboard {\n if (instance) {\n instance.destroy();\n }\n instance = new Dashboard(config);\n return instance;\n}\n\nexport function getDashboard(): Dashboard | null {\n return instance;\n}\n\nexport function destroyDashboard(): void {\n if (instance) {\n instance.destroy();\n instance = null;\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/dashboard.ts","../src/singleton.ts"],"sourcesContent":["import type { DashboardTheme, DashboardConfig, DashboardEvents } from \"./types\";\n\nconst EMBED_EVENT_MESSAGE_TYPE = \"yuno-dashboard:embed-event\";\nconst HOST_CAPABILITIES_MESSAGE_TYPE = \"yuno-dashboard:host-capabilities\";\n\ntype EmbedEventHandler = (event: {\n status?: unknown;\n payload?: unknown;\n}) => void | Promise<void>;\n\n// Build the capability map the dashboard reads to decide which actions the\n// host owns: { connections: { created: true }, ... } for every provided handler.\nfunction buildCapabilities(\n events?: DashboardEvents,\n): Record<string, Record<string, boolean>> {\n const capabilities: Record<string, Record<string, boolean>> = {};\n if (!events) return capabilities;\n const groups = events as Record<string, Record<string, unknown> | undefined>;\n for (const domain of Object.keys(groups)) {\n const group = groups[domain];\n if (!group) continue;\n for (const action of Object.keys(group)) {\n if (typeof group[action] === \"function\") {\n capabilities[domain] = capabilities[domain] ?? {};\n capabilities[domain][action] = true;\n }\n }\n }\n return capabilities;\n}\n\nexport class Dashboard {\n private iframe: HTMLIFrameElement;\n private wrapper: HTMLDivElement;\n private overlay: HTMLElement | null = null;\n private baseUrl: string;\n private ready = false;\n private queue: Record<string, unknown>[] = [];\n private messageHandler: (e: MessageEvent) => void;\n private initialTheme?: DashboardTheme;\n private initialLang?: string;\n private initialPath: string;\n private initialTestMode?: boolean;\n private token?: string;\n private onReadyCallback?: () => void;\n private onSessionExpiredCallback?: () => void | Promise<void>;\n private events?: DashboardEvents;\n private autoHeight: boolean;\n // Overlay (modal/drawer) mode: while >0 the iframe is expanded to the full\n // viewport so the dashboard's overlay centers to the host page, not the\n // iframe. Ref-counted to survive stacked overlays.\n private overlayCount = 0;\n private savedIframeCss: string | null = null;\n\n constructor(config: DashboardConfig) {\n this.baseUrl = config.baseUrl;\n this.initialTheme = config.theme;\n this.initialLang = config.lang;\n this.initialPath = config.path ?? \"/\";\n this.initialTestMode = config.testMode;\n this.token = config.token;\n this.onReadyCallback = config.onReady;\n this.onSessionExpiredCallback = config.onSessionExpired;\n this.events = config.events;\n this.autoHeight = config.autoHeight ?? false;\n\n this.wrapper = document.createElement(\"div\");\n this.wrapper.style.position = \"relative\";\n this.wrapper.style.width = \"100%\";\n this.wrapper.style.height = \"100%\";\n\n this.iframe = document.createElement(\"iframe\");\n this.iframe.style.width = \"100%\";\n this.iframe.style.height = \"100%\";\n this.iframe.style.border = \"none\";\n this.iframe.title = \"Yuno Dashboard\";\n this.iframe.src = this.buildSrc();\n\n this.wrapper.appendChild(this.iframe);\n\n this.overlay = config.loading instanceof HTMLElement\n ? config.loading\n : this.createDefaultOverlay();\n this.overlay.style.position = \"absolute\";\n this.overlay.style.inset = \"0\";\n this.overlay.style.zIndex = \"1\";\n this.wrapper.appendChild(this.overlay);\n\n this.messageHandler = (e: MessageEvent) => {\n if (e.origin !== this.baseUrl) return;\n if (\n this.autoHeight &&\n e.data?.action === \"resize\" &&\n typeof e.data?.height === \"number\"\n ) {\n this.iframe.style.height = `${e.data.height}px`;\n this.wrapper.style.height = `${e.data.height}px`;\n return;\n }\n if (e.data?.type === \"yuno-dashboard:session-expired\") {\n this.invokeCallback(\"onSessionExpired\", () =>\n this.onSessionExpiredCallback?.(),\n );\n return;\n }\n if (e.data?.type === EMBED_EVENT_MESSAGE_TYPE) {\n this.dispatchEmbedEvent(e.data);\n return;\n }\n if (e.data?.action === \"ready\") {\n this.onReady();\n }\n if (e.data?.action === \"tokenApplied\") {\n this.onTokenApplied();\n }\n };\n window.addEventListener(\"message\", this.messageHandler);\n\n config.container.appendChild(this.wrapper);\n }\n\n setTheme(theme: DashboardTheme): void {\n if (theme.tokens || theme.typography) {\n const themePayload: Record<string, unknown> = {};\n if (theme.tokens) themePayload.colors = theme.tokens;\n if (theme.typography) themePayload.typography = theme.typography;\n this.post({ action: \"setTheme\", theme: themePayload });\n }\n if (theme.mode) {\n this.post({ action: \"setMode\", mode: theme.mode });\n }\n if (theme.styles !== undefined) {\n this.post({ action: \"setExternalStyles\", css: theme.styles });\n }\n }\n\n setLang(lang: string): void {\n this.post({ action: \"setLang\", lang });\n }\n\n setToken(token: string): void {\n this.token = token;\n this.post({ action: \"setToken\", token });\n }\n\n navigate(path: string): void {\n this.post({ action: \"navigate\", path });\n }\n\n setTestMode(enabled: boolean): void {\n this.post({ action: \"setTestMode\", testMode: enabled });\n }\n\n destroy(): void {\n window.removeEventListener(\"message\", this.messageHandler);\n this.wrapper.remove();\n this.queue = [];\n this.ready = false;\n this.overlayCount = 0;\n this.savedIframeCss = null;\n }\n\n // Runs a host callback, swallowing sync throws and async rejections so a\n // misbehaving host handler can never break the SDK's message loop.\n private invokeCallback(\n name: string,\n run: () => void | Promise<void> | undefined,\n ): void {\n try {\n const result = run();\n if (result && typeof (result as Promise<unknown>).catch === \"function\") {\n (result as Promise<unknown>).catch((err) =>\n // eslint-disable-next-line no-console\n console.warn(`[yuno-dashboard-sdk] ${name} async callback rejected`, err),\n );\n }\n } catch (err) {\n // eslint-disable-next-line no-console\n console.warn(`[yuno-dashboard-sdk] ${name} callback threw`, err);\n }\n }\n\n // Routes an embed-event envelope to the host's events[domain][action] handler.\n private dispatchEmbedEvent(data: Record<string, unknown>): void {\n const domain = data?.domain;\n const action = data?.action;\n if (typeof domain !== \"string\" || typeof action !== \"string\") return;\n\n // UI signals are handled by the SDK itself (iframe sizing), not routed to\n // a host callback.\n if (domain === \"ui\") {\n this.handleOverlaySignal(action);\n return;\n }\n\n const groups = this.events as\n | Record<string, Record<string, EmbedEventHandler | undefined> | undefined>\n | undefined;\n const handler = groups?.[domain]?.[action];\n if (!handler) return;\n\n this.invokeCallback(`events.${domain}.${action}`, () =>\n handler({ status: data?.status, payload: data?.payload }),\n );\n }\n\n // Expands the iframe to the full viewport on the first open and restores it\n // once the last overlay closes (ref-counted for stacked overlays).\n private handleOverlaySignal(action: string): void {\n if (action === \"overlay-open\") {\n if (this.overlayCount === 0) this.expandToViewport();\n this.overlayCount += 1;\n } else if (action === \"overlay-close\") {\n if (this.overlayCount === 0) return;\n this.overlayCount -= 1;\n if (this.overlayCount === 0) this.restoreIframe();\n }\n }\n\n private expandToViewport(): void {\n this.savedIframeCss = this.iframe.style.cssText;\n Object.assign(this.iframe.style, {\n position: \"fixed\",\n inset: \"0\",\n width: \"100%\",\n height: \"100%\",\n zIndex: \"2147483647\",\n });\n }\n\n private restoreIframe(): void {\n this.iframe.style.cssText = this.savedIframeCss ?? \"\";\n this.savedIframeCss = null;\n }\n\n private post(message: Record<string, unknown>): void {\n if (this.ready && this.iframe.contentWindow) {\n this.iframe.contentWindow.postMessage(message, this.baseUrl);\n } else {\n this.queue.push(message);\n }\n }\n\n private flush(): void {\n const pending = this.queue.splice(0);\n for (const message of pending) {\n if (this.iframe.contentWindow) {\n this.iframe.contentWindow.postMessage(message, this.baseUrl);\n }\n }\n }\n\n private onReady(): void {\n this.ready = true;\n const capabilities = buildCapabilities(this.events);\n if (Object.keys(capabilities).length > 0) {\n this.post({ type: HOST_CAPABILITIES_MESSAGE_TYPE, capabilities });\n }\n if (this.token) {\n this.post({ action: \"setToken\", token: this.token });\n }\n if (this.initialTheme) {\n this.setTheme(this.initialTheme);\n }\n if (this.initialLang) {\n this.setLang(this.initialLang);\n }\n this.flush();\n }\n\n private onTokenApplied(): void {\n setTimeout(() => {\n this.hideOverlay();\n this.onReadyCallback?.();\n }, 1000);\n }\n\n private hideOverlay(): void {\n if (!this.overlay) return;\n this.overlay.style.transition = \"opacity 0.3s\";\n this.overlay.style.opacity = \"0\";\n setTimeout(() => this.overlay?.remove(), 300);\n }\n\n private createDefaultOverlay(): HTMLElement {\n const overlay = document.createElement(\"div\");\n overlay.style.background = \"#ffffff\";\n overlay.style.display = \"flex\";\n overlay.style.alignItems = \"center\";\n overlay.style.justifyContent = \"center\";\n\n const spinner = document.createElement(\"div\");\n spinner.style.width = \"32px\";\n spinner.style.height = \"32px\";\n spinner.style.border = \"3px solid #e0e0e0\";\n spinner.style.borderTopColor = \"#666\";\n spinner.style.borderRadius = \"50%\";\n spinner.style.animation = \"yuno-spin 0.8s linear infinite\";\n\n const style = document.createElement(\"style\");\n style.textContent = \"@keyframes yuno-spin { to { transform: rotate(360deg); } }\";\n\n overlay.appendChild(style);\n overlay.appendChild(spinner);\n return overlay;\n }\n\n private buildSrc(): string {\n const params = new URLSearchParams({\n embed: \"true\",\n theme: this.initialTheme?.mode ?? \"light\",\n lang: this.initialLang ?? \"en\",\n });\n if (this.initialTestMode !== undefined) {\n params.set(\"test\", String(this.initialTestMode));\n }\n const path = !this.initialPath || this.initialPath === \"/\" ? \"/\" : this.initialPath;\n return `${this.baseUrl}${path}?${params.toString()}`;\n }\n}\n","import { Dashboard } from \"./dashboard\";\nimport type { DashboardConfig } from \"./types\";\n\nlet instance: Dashboard | null = null;\n\nexport function initDashboard(config: DashboardConfig): Dashboard {\n if (instance) {\n instance.destroy();\n }\n instance = new Dashboard(config);\n return instance;\n}\n\nexport function getDashboard(): Dashboard | null {\n return instance;\n}\n\nexport function destroyDashboard(): void {\n if (instance) {\n instance.destroy();\n instance = null;\n }\n}\n"],"mappings":"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","names":[]}
|