@eka-care/medassist-widget-embed 0.2.7 → 0.2.9
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/iframe.html +21 -1
- package/dist/iframe.js +36 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +79 -11
- package/iframe.html +21 -1
- package/iframe.ts +32 -0
- package/index.ts +81 -12
- package/package.json +1 -1
- package/test.html +0 -1
package/dist/iframe.html
CHANGED
|
@@ -21,17 +21,37 @@
|
|
|
21
21
|
position: fixed;
|
|
22
22
|
top: 0;
|
|
23
23
|
left: 0;
|
|
24
|
+
background-color: #1a1a1a;
|
|
24
25
|
}
|
|
25
26
|
#root {
|
|
26
27
|
width: 100vw;
|
|
27
28
|
height: 100vh;
|
|
28
29
|
height: 100dvh; /* Dynamic viewport height for mobile */
|
|
29
30
|
position: relative;
|
|
31
|
+
display: flex;
|
|
32
|
+
align-items: center;
|
|
33
|
+
justify-content: center;
|
|
34
|
+
background-color: #1a1a1a;
|
|
35
|
+
}
|
|
36
|
+
.loader {
|
|
37
|
+
width: 48px;
|
|
38
|
+
height: 48px;
|
|
39
|
+
border: 3px solid rgba(255, 255, 255, 0.1);
|
|
40
|
+
border-top-color: #09FBD3;
|
|
41
|
+
border-radius: 50%;
|
|
42
|
+
animation: loader-spin 0.8s linear infinite;
|
|
43
|
+
}
|
|
44
|
+
@keyframes loader-spin {
|
|
45
|
+
to {
|
|
46
|
+
transform: rotate(360deg);
|
|
47
|
+
}
|
|
30
48
|
}
|
|
31
49
|
</style>
|
|
32
50
|
</head>
|
|
33
51
|
<body>
|
|
34
|
-
<div id="root"
|
|
52
|
+
<div id="root">
|
|
53
|
+
<div class="loader" aria-hidden="true"></div>
|
|
54
|
+
</div>
|
|
35
55
|
<!-- for local development -->
|
|
36
56
|
<!-- <script src="./iframe.js" data-widget-assets="local" async></script> -->
|
|
37
57
|
|
package/dist/iframe.js
CHANGED
|
@@ -40,6 +40,22 @@
|
|
|
40
40
|
...(apiTheme.title_img && { titleImg: apiTheme.title_img }),
|
|
41
41
|
};
|
|
42
42
|
}
|
|
43
|
+
/** Preload an image by URL so it is cached and loads faster when the widget uses it. */
|
|
44
|
+
function preloadImage(url) {
|
|
45
|
+
if (!url || typeof document === "undefined")
|
|
46
|
+
return;
|
|
47
|
+
try {
|
|
48
|
+
const link = document.createElement("link");
|
|
49
|
+
link.rel = "preload";
|
|
50
|
+
link.as = "image";
|
|
51
|
+
link.href = url;
|
|
52
|
+
document.head.appendChild(link);
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
const img = new Image();
|
|
56
|
+
img.src = url;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
43
59
|
/** Fetch agent-config from API with timeout; aborts if pending > 10s */
|
|
44
60
|
async function fetchAgentConfig(baseUrl, agentId) {
|
|
45
61
|
var _a;
|
|
@@ -142,6 +158,26 @@
|
|
|
142
158
|
const agentConfigPromise = earlyAgentId && earlyBaseUrl
|
|
143
159
|
? fetchAgentConfig(earlyBaseUrl, earlyAgentId)
|
|
144
160
|
: Promise.resolve(undefined);
|
|
161
|
+
// Preload background image when available (theme URL param or agent-config)
|
|
162
|
+
if (typeof document !== "undefined" && document.head) {
|
|
163
|
+
const themeParam = urlParams.get("theme");
|
|
164
|
+
if (themeParam) {
|
|
165
|
+
try {
|
|
166
|
+
const theme = JSON.parse(themeParam);
|
|
167
|
+
if (theme.backgroundImage)
|
|
168
|
+
preloadImage(theme.backgroundImage);
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
// ignore
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
agentConfigPromise.then((agentConfig) => {
|
|
175
|
+
var _a;
|
|
176
|
+
const url = (_a = agentConfig === null || agentConfig === void 0 ? void 0 : agentConfig.theme) === null || _a === void 0 ? void 0 : _a.background_img;
|
|
177
|
+
if (url)
|
|
178
|
+
preloadImage(url);
|
|
179
|
+
});
|
|
180
|
+
}
|
|
145
181
|
// Auto-initialize from URL parameters (no shadow DOM needed in iframe)
|
|
146
182
|
const initializeFromUrlParams = async () => {
|
|
147
183
|
var _a, _b, _c, _d, _e;
|
package/dist/index.d.ts
CHANGED
|
@@ -34,6 +34,8 @@ type MedAssistInitConfig = {
|
|
|
34
34
|
};
|
|
35
35
|
/** Map agent-config API theme to widget theme (mode → textColor: dark→black, light→white) */
|
|
36
36
|
declare function mapAgentConfigThemeToWidgetTheme(apiTheme: AgentConfig["theme"] | undefined): MedAssistInitConfig["theme"];
|
|
37
|
+
/** Preload an image by URL so it is cached and loads faster when the widget uses it. */
|
|
38
|
+
declare function preloadImage(url: string): void;
|
|
37
39
|
/** Fetch agent-config from API and return theme from response data */
|
|
38
40
|
declare function fetchAgentConfig(baseUrl: string, agentId: string): Promise<AgentConfig | undefined>;
|
|
39
41
|
interface EkaMedAssistWindow extends Window {
|
|
@@ -51,6 +53,8 @@ declare const WIDGET_JS_URL: string;
|
|
|
51
53
|
declare const WIDGET_CSS_URL: string;
|
|
52
54
|
declare let widgetScriptPromise: Promise<void> | null;
|
|
53
55
|
declare let widgetCssTextPromise: Promise<string> | null;
|
|
56
|
+
/** Start fetching widget CSS (shared promise). Used for preload and by loadWidgetCss. */
|
|
57
|
+
declare function getWidgetCssTextPromise(): Promise<string>;
|
|
54
58
|
declare class MedAssistWidgetLoader extends HTMLElement {
|
|
55
59
|
private defaultIconUrl;
|
|
56
60
|
private widgetLoaded;
|
|
@@ -59,6 +63,10 @@ declare class MedAssistWidgetLoader extends HTMLElement {
|
|
|
59
63
|
static get observedAttributes(): string[];
|
|
60
64
|
connectedCallback(): void;
|
|
61
65
|
attributeChangedCallback(name: string): void;
|
|
66
|
+
/** When in widget mode, start loading JS and CSS on page load so first open is faster. */
|
|
67
|
+
private preloadWidgetAssets;
|
|
68
|
+
/** Preload theme background image from init config, theme attribute, or agent-config API. */
|
|
69
|
+
private preloadBackgroundImage;
|
|
62
70
|
private setupAuthExpirationListener;
|
|
63
71
|
openFromBridge(): void;
|
|
64
72
|
renderButton(): void;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,QAAA,MAAM,gBAAgB,QAAO,iBAAiB,GAAG,IAahD,CAAC;AAEF,KAAK,iBAAiB,GAAG,YAAY,GAAG,aAAa,GAAG,SAAS,CAAC;AAElE,QAAA,MAAM,cAAc,GAClB,OAAO,MAAM,GAAG,IAAI,KACnB,iBAAiB,GAAG,SAStB,CAAC;AAEF,QAAA,MAAM,QAAQ,0BAAqB,CAAC;AAGpC,QAAA,MAAM,yBAAyB,QAK3B,CAAC;AAEL,6FAA6F;AAC7F,KAAK,WAAW,GAAG;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,CAAC,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,EAAE,CAAC;IACxC,KAAK,CAAC,EAAE;QACN,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;QACxB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAA;KAClB,CAAA;CACF,CAAC;AAEF,KAAK,mBAAmB,GAAG;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,CAAC,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,EAAE,CAAC;IACxC,KAAK,CAAC,EAAE;QACN,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,SAAS,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;KAC/B,CAAC;IACF,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC;AAEF,6FAA6F;AAC7F,iBAAS,gCAAgC,CAAC,QAAQ,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,SAAS,GAAG,mBAAmB,CAAC,OAAO,CAAC,CAUlH;AAED,sEAAsE;AACtE,iBAAe,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC,CAYlG;AAED,UAAU,kBAAmB,SAAQ,MAAM;IACzC,YAAY,CAAC,EAAE;QACb,IAAI,EAAE,CAAC,MAAM,EAAE,mBAAmB,KAAK,IAAI,CAAC;QAC5C,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;KACtB,CAAC;IACF,sBAAsB,CAAC,EAAE,mBAAmB,CAAC;CAC9C;AAED,QAAA,MAAM,qBAAqB,EAAE,mBAAwB,CAAC;AAEtD,QAAA,MAAM,gBAAgB,QAAO,WAAW,GAAG,IAK1C,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -41,6 +41,23 @@ function mapAgentConfigThemeToWidgetTheme(apiTheme) {
|
|
|
41
41
|
...(apiTheme.title_img && { titleImg: apiTheme.title_img }),
|
|
42
42
|
};
|
|
43
43
|
}
|
|
44
|
+
/** Preload an image by URL so it is cached and loads faster when the widget uses it. */
|
|
45
|
+
function preloadImage(url) {
|
|
46
|
+
if (!url || typeof document === "undefined")
|
|
47
|
+
return;
|
|
48
|
+
try {
|
|
49
|
+
const link = document.createElement("link");
|
|
50
|
+
link.rel = "preload";
|
|
51
|
+
link.as = "image";
|
|
52
|
+
link.href = url;
|
|
53
|
+
document.head.appendChild(link);
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
// fallback: use Image to prime cache
|
|
57
|
+
const img = new Image();
|
|
58
|
+
img.src = url;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
44
61
|
/** Fetch agent-config from API and return theme from response data */
|
|
45
62
|
async function fetchAgentConfig(baseUrl, agentId) {
|
|
46
63
|
const url = `${baseUrl.replace(/\/$/, "")}/med-assist/agent-config/${agentId}`;
|
|
@@ -68,7 +85,7 @@ if (typeof window !== "undefined") {
|
|
|
68
85
|
w.__ekaMedAssistConfig__ = globalMedAssistConfig;
|
|
69
86
|
w.EkaMedAssist = {
|
|
70
87
|
init(config) {
|
|
71
|
-
var _a, _b;
|
|
88
|
+
var _a, _b, _c;
|
|
72
89
|
Object.assign(globalMedAssistConfig, config);
|
|
73
90
|
const el = getWidgetElement();
|
|
74
91
|
if (!el)
|
|
@@ -89,7 +106,10 @@ if (typeof window !== "undefined") {
|
|
|
89
106
|
console.warn("Failed to stringify context passed to init");
|
|
90
107
|
}
|
|
91
108
|
}
|
|
92
|
-
|
|
109
|
+
if ((_a = config.theme) === null || _a === void 0 ? void 0 : _a.backgroundImage) {
|
|
110
|
+
preloadImage(config.theme.backgroundImage);
|
|
111
|
+
}
|
|
112
|
+
(_c = (_b = el).openFromBridge) === null || _c === void 0 ? void 0 : _c.call(_b);
|
|
93
113
|
},
|
|
94
114
|
};
|
|
95
115
|
}
|
|
@@ -126,6 +146,18 @@ const WIDGET_JS_URL = `${widgetAssetBaseUrl}medassist-widget.js`;
|
|
|
126
146
|
const WIDGET_CSS_URL = `${widgetAssetBaseUrl}medassist-widget.css`;
|
|
127
147
|
let widgetScriptPromise = null;
|
|
128
148
|
let widgetCssTextPromise = null;
|
|
149
|
+
/** Start fetching widget CSS (shared promise). Used for preload and by loadWidgetCss. */
|
|
150
|
+
function getWidgetCssTextPromise() {
|
|
151
|
+
if (!widgetCssTextPromise) {
|
|
152
|
+
widgetCssTextPromise = fetch(WIDGET_CSS_URL).then((response) => {
|
|
153
|
+
if (!response.ok) {
|
|
154
|
+
throw new Error(`Unable to fetch widget styles from ${WIDGET_CSS_URL}`);
|
|
155
|
+
}
|
|
156
|
+
return response.text();
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
return widgetCssTextPromise;
|
|
160
|
+
}
|
|
129
161
|
class MedAssistWidgetLoader extends HTMLElement {
|
|
130
162
|
constructor() {
|
|
131
163
|
super();
|
|
@@ -145,6 +177,7 @@ class MedAssistWidgetLoader extends HTMLElement {
|
|
|
145
177
|
}
|
|
146
178
|
else {
|
|
147
179
|
this.renderButton();
|
|
180
|
+
this.preloadWidgetAssets();
|
|
148
181
|
}
|
|
149
182
|
}
|
|
150
183
|
attributeChangedCallback(name) {
|
|
@@ -166,6 +199,49 @@ class MedAssistWidgetLoader extends HTMLElement {
|
|
|
166
199
|
}
|
|
167
200
|
}
|
|
168
201
|
}
|
|
202
|
+
/** When in widget mode, start loading JS and CSS on page load so first open is faster. */
|
|
203
|
+
preloadWidgetAssets() {
|
|
204
|
+
getWidgetCssTextPromise(); // start CSS fetch (no inject until open)
|
|
205
|
+
void this.loadWidgetScript(); // start JS load
|
|
206
|
+
void this.preloadBackgroundImage();
|
|
207
|
+
}
|
|
208
|
+
/** Preload theme background image from init config, theme attribute, or agent-config API. */
|
|
209
|
+
preloadBackgroundImage() {
|
|
210
|
+
var _a;
|
|
211
|
+
const initConfig = typeof window !== "undefined"
|
|
212
|
+
? window.__ekaMedAssistConfig__
|
|
213
|
+
: undefined;
|
|
214
|
+
const attributeTheme = this.getAttribute("theme")
|
|
215
|
+
? (() => {
|
|
216
|
+
try {
|
|
217
|
+
return JSON.parse(this.getAttribute("theme") || "{}");
|
|
218
|
+
}
|
|
219
|
+
catch {
|
|
220
|
+
return undefined;
|
|
221
|
+
}
|
|
222
|
+
})()
|
|
223
|
+
: undefined;
|
|
224
|
+
const fromInit = (_a = initConfig === null || initConfig === void 0 ? void 0 : initConfig.theme) === null || _a === void 0 ? void 0 : _a.backgroundImage;
|
|
225
|
+
const fromAttr = attributeTheme === null || attributeTheme === void 0 ? void 0 : attributeTheme.backgroundImage;
|
|
226
|
+
if (fromInit)
|
|
227
|
+
preloadImage(fromInit);
|
|
228
|
+
if (fromAttr && fromAttr !== fromInit)
|
|
229
|
+
preloadImage(fromAttr);
|
|
230
|
+
const baseUrl = (initConfig === null || initConfig === void 0 ? void 0 : initConfig.baseUrl) || this.getAttribute("base-url") || "";
|
|
231
|
+
const agentId = (initConfig === null || initConfig === void 0 ? void 0 : initConfig.agentId) || this.getAttribute("agent-id") || "";
|
|
232
|
+
if (baseUrl && agentId) {
|
|
233
|
+
fetchAgentConfig(baseUrl, agentId)
|
|
234
|
+
.then((agentConfig) => {
|
|
235
|
+
var _a;
|
|
236
|
+
const url = (_a = agentConfig === null || agentConfig === void 0 ? void 0 : agentConfig.theme) === null || _a === void 0 ? void 0 : _a.background_img;
|
|
237
|
+
if (url)
|
|
238
|
+
preloadImage(url);
|
|
239
|
+
})
|
|
240
|
+
.catch(() => {
|
|
241
|
+
// ignore; widget will load config when it opens
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
}
|
|
169
245
|
setupAuthExpirationListener() {
|
|
170
246
|
if (typeof window === "undefined")
|
|
171
247
|
return;
|
|
@@ -391,15 +467,7 @@ class MedAssistWidgetLoader extends HTMLElement {
|
|
|
391
467
|
if (shadowRoot.querySelector("[data-medassist-style='true']")) {
|
|
392
468
|
return;
|
|
393
469
|
}
|
|
394
|
-
|
|
395
|
-
widgetCssTextPromise = fetch(WIDGET_CSS_URL).then((response) => {
|
|
396
|
-
if (!response.ok) {
|
|
397
|
-
throw new Error(`Unable to fetch widget styles from ${WIDGET_CSS_URL}`);
|
|
398
|
-
}
|
|
399
|
-
return response.text();
|
|
400
|
-
});
|
|
401
|
-
}
|
|
402
|
-
const cssText = await widgetCssTextPromise;
|
|
470
|
+
const cssText = await getWidgetCssTextPromise();
|
|
403
471
|
const styleTag = document.createElement("style");
|
|
404
472
|
styleTag.setAttribute("data-medassist-style", "true");
|
|
405
473
|
styleTag.textContent = cssText;
|
package/iframe.html
CHANGED
|
@@ -21,17 +21,37 @@
|
|
|
21
21
|
position: fixed;
|
|
22
22
|
top: 0;
|
|
23
23
|
left: 0;
|
|
24
|
+
background-color: #1a1a1a;
|
|
24
25
|
}
|
|
25
26
|
#root {
|
|
26
27
|
width: 100vw;
|
|
27
28
|
height: 100vh;
|
|
28
29
|
height: 100dvh; /* Dynamic viewport height for mobile */
|
|
29
30
|
position: relative;
|
|
31
|
+
display: flex;
|
|
32
|
+
align-items: center;
|
|
33
|
+
justify-content: center;
|
|
34
|
+
background-color: #1a1a1a;
|
|
35
|
+
}
|
|
36
|
+
.loader {
|
|
37
|
+
width: 48px;
|
|
38
|
+
height: 48px;
|
|
39
|
+
border: 3px solid rgba(255, 255, 255, 0.1);
|
|
40
|
+
border-top-color: #09FBD3;
|
|
41
|
+
border-radius: 50%;
|
|
42
|
+
animation: loader-spin 0.8s linear infinite;
|
|
43
|
+
}
|
|
44
|
+
@keyframes loader-spin {
|
|
45
|
+
to {
|
|
46
|
+
transform: rotate(360deg);
|
|
47
|
+
}
|
|
30
48
|
}
|
|
31
49
|
</style>
|
|
32
50
|
</head>
|
|
33
51
|
<body>
|
|
34
|
-
<div id="root"
|
|
52
|
+
<div id="root">
|
|
53
|
+
<div class="loader" aria-hidden="true"></div>
|
|
54
|
+
</div>
|
|
35
55
|
<!-- for local development -->
|
|
36
56
|
<!-- <script src="./iframe.js" data-widget-assets="local" async></script> -->
|
|
37
57
|
|
package/iframe.ts
CHANGED
|
@@ -74,6 +74,21 @@
|
|
|
74
74
|
};
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
+
/** Preload an image by URL so it is cached and loads faster when the widget uses it. */
|
|
78
|
+
function preloadImage(url: string): void {
|
|
79
|
+
if (!url || typeof document === "undefined") return;
|
|
80
|
+
try {
|
|
81
|
+
const link = document.createElement("link");
|
|
82
|
+
link.rel = "preload";
|
|
83
|
+
link.as = "image";
|
|
84
|
+
link.href = url;
|
|
85
|
+
document.head.appendChild(link);
|
|
86
|
+
} catch {
|
|
87
|
+
const img = new Image();
|
|
88
|
+
img.src = url;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
77
92
|
/** Fetch agent-config from API with timeout; aborts if pending > 10s */
|
|
78
93
|
async function fetchAgentConfig(
|
|
79
94
|
baseUrl: string,
|
|
@@ -188,6 +203,23 @@
|
|
|
188
203
|
? fetchAgentConfig(earlyBaseUrl, earlyAgentId)
|
|
189
204
|
: Promise.resolve(undefined);
|
|
190
205
|
|
|
206
|
+
// Preload background image when available (theme URL param or agent-config)
|
|
207
|
+
if (typeof document !== "undefined" && document.head) {
|
|
208
|
+
const themeParam = urlParams.get("theme");
|
|
209
|
+
if (themeParam) {
|
|
210
|
+
try {
|
|
211
|
+
const theme = JSON.parse(themeParam) as WidgetTheme;
|
|
212
|
+
if (theme.backgroundImage) preloadImage(theme.backgroundImage);
|
|
213
|
+
} catch {
|
|
214
|
+
// ignore
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
agentConfigPromise.then((agentConfig) => {
|
|
218
|
+
const url = agentConfig?.theme?.background_img;
|
|
219
|
+
if (url) preloadImage(url);
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
|
|
191
223
|
// Auto-initialize from URL parameters (no shadow DOM needed in iframe)
|
|
192
224
|
const initializeFromUrlParams = async (): Promise<void> => {
|
|
193
225
|
const agentId = urlParams.get("agentId");
|
package/index.ts
CHANGED
|
@@ -82,6 +82,22 @@ function mapAgentConfigThemeToWidgetTheme(apiTheme: AgentConfig["theme"] | undef
|
|
|
82
82
|
};
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
+
/** Preload an image by URL so it is cached and loads faster when the widget uses it. */
|
|
86
|
+
function preloadImage(url: string): void {
|
|
87
|
+
if (!url || typeof document === "undefined") return;
|
|
88
|
+
try {
|
|
89
|
+
const link = document.createElement("link");
|
|
90
|
+
link.rel = "preload";
|
|
91
|
+
link.as = "image";
|
|
92
|
+
link.href = url;
|
|
93
|
+
document.head.appendChild(link);
|
|
94
|
+
} catch {
|
|
95
|
+
// fallback: use Image to prime cache
|
|
96
|
+
const img = new Image();
|
|
97
|
+
img.src = url;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
85
101
|
/** Fetch agent-config from API and return theme from response data */
|
|
86
102
|
async function fetchAgentConfig(baseUrl: string, agentId: string): Promise<AgentConfig | undefined> {
|
|
87
103
|
const url = `${baseUrl.replace(/\/$/, "")}/med-assist/agent-config/${agentId}`;
|
|
@@ -136,6 +152,10 @@ if (typeof window !== "undefined") {
|
|
|
136
152
|
}
|
|
137
153
|
}
|
|
138
154
|
|
|
155
|
+
if (config.theme?.backgroundImage) {
|
|
156
|
+
preloadImage(config.theme.backgroundImage);
|
|
157
|
+
}
|
|
158
|
+
|
|
139
159
|
(el as any).openFromBridge?.();
|
|
140
160
|
},
|
|
141
161
|
};
|
|
@@ -179,6 +199,21 @@ const WIDGET_CSS_URL = `${widgetAssetBaseUrl}medassist-widget.css`;
|
|
|
179
199
|
let widgetScriptPromise: Promise<void> | null = null;
|
|
180
200
|
let widgetCssTextPromise: Promise<string> | null = null;
|
|
181
201
|
|
|
202
|
+
/** Start fetching widget CSS (shared promise). Used for preload and by loadWidgetCss. */
|
|
203
|
+
function getWidgetCssTextPromise(): Promise<string> {
|
|
204
|
+
if (!widgetCssTextPromise) {
|
|
205
|
+
widgetCssTextPromise = fetch(WIDGET_CSS_URL).then((response) => {
|
|
206
|
+
if (!response.ok) {
|
|
207
|
+
throw new Error(
|
|
208
|
+
`Unable to fetch widget styles from ${WIDGET_CSS_URL}`
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
return response.text();
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
return widgetCssTextPromise;
|
|
215
|
+
}
|
|
216
|
+
|
|
182
217
|
class MedAssistWidgetLoader extends HTMLElement {
|
|
183
218
|
private defaultIconUrl: string;
|
|
184
219
|
private widgetLoaded: boolean;
|
|
@@ -204,6 +239,7 @@ class MedAssistWidgetLoader extends HTMLElement {
|
|
|
204
239
|
this.initializeFullMode();
|
|
205
240
|
} else {
|
|
206
241
|
this.renderButton();
|
|
242
|
+
this.preloadWidgetAssets();
|
|
207
243
|
}
|
|
208
244
|
}
|
|
209
245
|
|
|
@@ -226,6 +262,50 @@ class MedAssistWidgetLoader extends HTMLElement {
|
|
|
226
262
|
}
|
|
227
263
|
}
|
|
228
264
|
|
|
265
|
+
/** When in widget mode, start loading JS and CSS on page load so first open is faster. */
|
|
266
|
+
private preloadWidgetAssets(): void {
|
|
267
|
+
getWidgetCssTextPromise(); // start CSS fetch (no inject until open)
|
|
268
|
+
void this.loadWidgetScript(); // start JS load
|
|
269
|
+
void this.preloadBackgroundImage();
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/** Preload theme background image from init config, theme attribute, or agent-config API. */
|
|
273
|
+
private preloadBackgroundImage(): void {
|
|
274
|
+
const initConfig =
|
|
275
|
+
typeof window !== "undefined"
|
|
276
|
+
? (window as EkaMedAssistWindow).__ekaMedAssistConfig__
|
|
277
|
+
: undefined;
|
|
278
|
+
const attributeTheme = this.getAttribute("theme")
|
|
279
|
+
? (() => {
|
|
280
|
+
try {
|
|
281
|
+
return JSON.parse(this.getAttribute("theme") || "{}") as { backgroundImage?: string };
|
|
282
|
+
} catch {
|
|
283
|
+
return undefined;
|
|
284
|
+
}
|
|
285
|
+
})()
|
|
286
|
+
: undefined;
|
|
287
|
+
|
|
288
|
+
const fromInit = initConfig?.theme?.backgroundImage;
|
|
289
|
+
const fromAttr = attributeTheme?.backgroundImage;
|
|
290
|
+
if (fromInit) preloadImage(fromInit);
|
|
291
|
+
if (fromAttr && fromAttr !== fromInit) preloadImage(fromAttr);
|
|
292
|
+
|
|
293
|
+
const baseUrl =
|
|
294
|
+
(initConfig?.baseUrl as string) || this.getAttribute("base-url") || "";
|
|
295
|
+
const agentId =
|
|
296
|
+
(initConfig?.agentId as string) || this.getAttribute("agent-id") || "";
|
|
297
|
+
if (baseUrl && agentId) {
|
|
298
|
+
fetchAgentConfig(baseUrl, agentId)
|
|
299
|
+
.then((agentConfig) => {
|
|
300
|
+
const url = agentConfig?.theme?.background_img;
|
|
301
|
+
if (url) preloadImage(url);
|
|
302
|
+
})
|
|
303
|
+
.catch(() => {
|
|
304
|
+
// ignore; widget will load config when it opens
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
229
309
|
private setupAuthExpirationListener(): void {
|
|
230
310
|
if (typeof window === "undefined") return;
|
|
231
311
|
|
|
@@ -470,18 +550,7 @@ class MedAssistWidgetLoader extends HTMLElement {
|
|
|
470
550
|
return;
|
|
471
551
|
}
|
|
472
552
|
|
|
473
|
-
|
|
474
|
-
widgetCssTextPromise = fetch(WIDGET_CSS_URL).then((response) => {
|
|
475
|
-
if (!response.ok) {
|
|
476
|
-
throw new Error(
|
|
477
|
-
`Unable to fetch widget styles from ${WIDGET_CSS_URL}`
|
|
478
|
-
);
|
|
479
|
-
}
|
|
480
|
-
return response.text();
|
|
481
|
-
});
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
const cssText = await widgetCssTextPromise;
|
|
553
|
+
const cssText = await getWidgetCssTextPromise();
|
|
485
554
|
const styleTag = document.createElement("style");
|
|
486
555
|
styleTag.setAttribute("data-medassist-style", "true");
|
|
487
556
|
styleTag.textContent = cssText;
|
package/package.json
CHANGED
package/test.html
CHANGED
|
@@ -30,7 +30,6 @@
|
|
|
30
30
|
agent-id="MmE3Y2Y0NDctNTM4Mi00MDUzLWFmODgtZDRiOWM2NmMzMDBlIzcxNzY5NjA3ODkzNjIyNzg="
|
|
31
31
|
icon-url="https://cdn.eka.care/bot-icon.svg" //add your own icon url here
|
|
32
32
|
title="Moolchand Assist"
|
|
33
|
-
environment="development"
|
|
34
33
|
base-url="https://e3b3-125-17-125-117.ngrok-free.app/reloaded"
|
|
35
34
|
</eka-medassist-widget>
|
|
36
35
|
<!-- <script>
|