@mieweb/ui 0.6.1-dev.121 → 0.6.1-dev.123
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 +0 -8
- package/dist/brands/index.cjs +7 -7
- package/dist/brands/index.js +2 -2
- package/dist/{chunk-KJPOFUF5.cjs → chunk-AWUADXYI.cjs} +3 -3
- package/dist/{chunk-KJPOFUF5.cjs.map → chunk-AWUADXYI.cjs.map} +1 -1
- package/dist/{chunk-OXGUG57G.cjs → chunk-JLQTPLSY.cjs} +2 -2
- package/dist/{chunk-OXGUG57G.cjs.map → chunk-JLQTPLSY.cjs.map} +1 -1
- package/dist/{chunk-K3IVCUPP.js → chunk-MV337VA7.js} +2 -2
- package/dist/{chunk-K3IVCUPP.js.map → chunk-MV337VA7.js.map} +1 -1
- package/dist/{chunk-IUFDGB5O.js → chunk-WTDCNXZO.js} +3 -3
- package/dist/{chunk-IUFDGB5O.js.map → chunk-WTDCNXZO.js.map} +1 -1
- package/dist/components/Modal/index.cjs +10 -10
- package/dist/components/Modal/index.js +2 -2
- package/dist/index.cjs +178 -178
- package/dist/index.js +15 -15
- package/dist/styles.css +1 -1
- package/dist/utils/index.cjs +5 -5
- package/dist/utils/index.js +1 -1
- package/package.json +1 -16
- package/dist/ozwell.cjs +0 -385
- package/dist/ozwell.cjs.map +0 -1
- package/dist/ozwell.d.cts +0 -15
- package/dist/ozwell.d.ts +0 -15
- package/dist/ozwell.js +0 -360
- package/dist/ozwell.js.map +0 -1
package/dist/ozwell.js
DELETED
|
@@ -1,360 +0,0 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
|
-
import { OzwellChat } from '@ozwell/react';
|
|
3
|
-
export { useOzwell } from '@ozwell/react';
|
|
4
|
-
import { jsx } from 'react/jsx-runtime';
|
|
5
|
-
|
|
6
|
-
// src/components/AI/OzwellWidget.tsx
|
|
7
|
-
var DEV_SERVER = "https://ozwell-dev-refserver.opensource.mieweb.org";
|
|
8
|
-
var DEFAULT_ENDPOINT = `${DEV_SERVER}/v1/chat/completions`;
|
|
9
|
-
var DEFAULT_WIDGET_URL = `${DEV_SERVER}/embed/ozwell-chat.html`;
|
|
10
|
-
var OZWELL_PRIMARY = "#27aae1";
|
|
11
|
-
var OZWELL_ICON_FALLBACK = "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Ccircle cx='32' cy='32' r='32' fill='%2327aae1'/%3E%3Ctext x='32' y='44' text-anchor='middle' font-size='36' font-family='system-ui,sans-serif' font-weight='700' fill='white'%3EO%3C/text%3E%3C/svg%3E";
|
|
12
|
-
var THEME_OVERRIDES_ID = "ozwell-mieweb-theme-overrides";
|
|
13
|
-
var THEME_OVERRIDES_CSS = `
|
|
14
|
-
/* ============================
|
|
15
|
-
Ozwell Widget \u2013 MIE UI Theme Overrides
|
|
16
|
-
Uses --mieweb-* design tokens for brand + dark mode support.
|
|
17
|
-
============================ */
|
|
18
|
-
|
|
19
|
-
/* --- Floating chat button --- */
|
|
20
|
-
@keyframes ozwellFloat {
|
|
21
|
-
0% { transform: translateY(0) rotate(0deg); }
|
|
22
|
-
10% { transform: translateY(-5px) rotate(-2deg); }
|
|
23
|
-
20% { transform: translateY(3px) rotate(3deg); }
|
|
24
|
-
30% { transform: translateY(-2px) rotate(-1deg); }
|
|
25
|
-
40% { transform: translateY(4px) rotate(2deg); }
|
|
26
|
-
50% { transform: translateY(0) rotate(0deg); }
|
|
27
|
-
60% { transform: translateY(-4px) rotate(2deg); }
|
|
28
|
-
70% { transform: translateY(2px) rotate(-3deg); }
|
|
29
|
-
80% { transform: translateY(5px) rotate(1deg); }
|
|
30
|
-
90% { transform: translateY(-3px) rotate(-2deg); }
|
|
31
|
-
100% { transform: translateY(0) rotate(0deg); }
|
|
32
|
-
}
|
|
33
|
-
.ozwell-chat-button {
|
|
34
|
-
background: color-mix(in srgb, var(--mieweb-primary-500, #27aae1) 45%, transparent) !important;
|
|
35
|
-
box-shadow: 0 4px 16px color-mix(in srgb, var(--mieweb-primary-500, #27aae1) 30%, transparent) !important;
|
|
36
|
-
animation: ozwellFloat 15s ease-in-out infinite !important;
|
|
37
|
-
}
|
|
38
|
-
.ozwell-chat-button:hover {
|
|
39
|
-
background: color-mix(in srgb, var(--mieweb-primary-500, #27aae1) 65%, transparent) !important;
|
|
40
|
-
box-shadow: 0 6px 20px color-mix(in srgb, var(--mieweb-primary-500, #27aae1) 40%, transparent) !important;
|
|
41
|
-
animation-play-state: paused !important;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/* --- Accessibility: respect reduced-motion preference --- */
|
|
45
|
-
@media (prefers-reduced-motion: reduce) {
|
|
46
|
-
.ozwell-chat-button {
|
|
47
|
-
animation: none !important;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/* --- Unread badge --- */
|
|
52
|
-
.ozwell-unread-badge {
|
|
53
|
-
background: var(--mieweb-destructive, #dc2626) !important;
|
|
54
|
-
border-color: var(--mieweb-background, #ffffff) !important;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/* --- Chat window wrapper --- */
|
|
58
|
-
.ozwell-chat-wrapper {
|
|
59
|
-
background: var(--mieweb-card, #ffffff) !important;
|
|
60
|
-
border-color: var(--mieweb-border, #e5e7eb) !important;
|
|
61
|
-
box-shadow: var(--mieweb-shadow-modal, 0 10px 15px -3px rgb(0 0 0 / 0.1)) !important;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/* --- Header bar --- */
|
|
65
|
-
.ozwell-chat-header {
|
|
66
|
-
background: var(--mieweb-primary-500, #27aae1) !important;
|
|
67
|
-
color: var(--mieweb-primary-foreground, #ffffff) !important;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/* --- Header title --- */
|
|
71
|
-
.ozwell-chat-title {
|
|
72
|
-
color: inherit !important;
|
|
73
|
-
font-family: var(--mieweb-font-sans, inherit) !important;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/* --- Hide / minimize button --- */
|
|
77
|
-
.ozwell-hide-btn {
|
|
78
|
-
color: var(--mieweb-primary-foreground, #ffffff) !important;
|
|
79
|
-
opacity: 0.85;
|
|
80
|
-
}
|
|
81
|
-
.ozwell-hide-btn:hover {
|
|
82
|
-
opacity: 1;
|
|
83
|
-
background: color-mix(in srgb, var(--mieweb-primary-foreground, #ffffff) 15%, transparent) !important;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/* --- Chat icon size --- */
|
|
87
|
-
.ozwell-chat-icon {
|
|
88
|
-
width: 56px !important;
|
|
89
|
-
height: 56px !important;
|
|
90
|
-
}
|
|
91
|
-
`;
|
|
92
|
-
function buildIframeThemeCSS() {
|
|
93
|
-
const root = document.documentElement;
|
|
94
|
-
const get = (v, fallback) => getComputedStyle(root).getPropertyValue(v).trim() || fallback;
|
|
95
|
-
const bg = get("--mieweb-background", "#ffffff");
|
|
96
|
-
const fg = get("--mieweb-foreground", "#171717");
|
|
97
|
-
const card = get("--mieweb-card", "#ffffff");
|
|
98
|
-
const cardFg = get("--mieweb-card-foreground", "#171717");
|
|
99
|
-
const muted = get("--mieweb-muted", "#f5f5f5");
|
|
100
|
-
const mutedFg = get("--mieweb-muted-foreground", "#737373");
|
|
101
|
-
const border = get("--mieweb-border", "#e5e7eb");
|
|
102
|
-
const input = get("--mieweb-input", "#e5e7eb");
|
|
103
|
-
const primary = get("--mieweb-primary-500", "#27aae1");
|
|
104
|
-
const primaryFg = get("--mieweb-primary-foreground", "#ffffff");
|
|
105
|
-
const ring = get("--mieweb-ring", "#27aae1");
|
|
106
|
-
const fontSans = get(
|
|
107
|
-
"--mieweb-font-sans",
|
|
108
|
-
"'Nunito', ui-sans-serif, system-ui, sans-serif"
|
|
109
|
-
);
|
|
110
|
-
return `
|
|
111
|
-
/* MIE UI iframe theme overrides \u2014 regenerated on theme change */
|
|
112
|
-
|
|
113
|
-
/* --- Layout --- */
|
|
114
|
-
body, .chat-container {
|
|
115
|
-
background: ${bg} !important;
|
|
116
|
-
color: ${fg} !important;
|
|
117
|
-
font-family: ${fontSans} !important;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/* --- Status strip --- */
|
|
121
|
-
.status-strip {
|
|
122
|
-
background: ${muted} !important;
|
|
123
|
-
border-color: ${border} !important;
|
|
124
|
-
}
|
|
125
|
-
.status { color: ${mutedFg} !important; }
|
|
126
|
-
|
|
127
|
-
/* --- Reasoning controls --- */
|
|
128
|
-
.reasoning-capsule {
|
|
129
|
-
background: ${muted} !important;
|
|
130
|
-
color: ${fg} !important;
|
|
131
|
-
border-color: ${border} !important;
|
|
132
|
-
}
|
|
133
|
-
.reasoning-seg {
|
|
134
|
-
background: ${card} !important;
|
|
135
|
-
border-color: ${border} !important;
|
|
136
|
-
}
|
|
137
|
-
.reasoning-seg-btn {
|
|
138
|
-
color: ${mutedFg} !important;
|
|
139
|
-
}
|
|
140
|
-
.reasoning-seg-btn.active {
|
|
141
|
-
background: ${primary} !important;
|
|
142
|
-
color: ${primaryFg} !important;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/* --- Messages --- */
|
|
146
|
-
.messages { background: ${bg} !important; }
|
|
147
|
-
|
|
148
|
-
.message.user {
|
|
149
|
-
background: ${primary} !important;
|
|
150
|
-
color: ${primaryFg} !important;
|
|
151
|
-
}
|
|
152
|
-
.message.assistant {
|
|
153
|
-
background: ${card} !important;
|
|
154
|
-
color: ${cardFg} !important;
|
|
155
|
-
border: 1px solid ${border} !important;
|
|
156
|
-
}
|
|
157
|
-
.message.system {
|
|
158
|
-
background: ${muted} !important;
|
|
159
|
-
color: ${fg} !important;
|
|
160
|
-
}
|
|
161
|
-
.message.welcome {
|
|
162
|
-
background: ${card} !important;
|
|
163
|
-
color: ${mutedFg} !important;
|
|
164
|
-
border-color: ${border} !important;
|
|
165
|
-
}
|
|
166
|
-
.message.queued {
|
|
167
|
-
border-color: ${border} !important;
|
|
168
|
-
color: ${mutedFg} !important;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
/* --- Input area --- */
|
|
172
|
-
.chat-form {
|
|
173
|
-
background: ${bg} !important;
|
|
174
|
-
border-top: 1px solid ${border} !important;
|
|
175
|
-
}
|
|
176
|
-
.chat-input {
|
|
177
|
-
background: ${input} !important;
|
|
178
|
-
color: ${fg} !important;
|
|
179
|
-
border-color: ${border} !important;
|
|
180
|
-
font-family: ${fontSans} !important;
|
|
181
|
-
}
|
|
182
|
-
.chat-input::placeholder { color: ${mutedFg} !important; }
|
|
183
|
-
.chat-input:focus {
|
|
184
|
-
border-color: ${ring} !important;
|
|
185
|
-
box-shadow: 0 0 0 2px ${ring}33 !important;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
/* --- Send button --- */
|
|
189
|
-
.chat-submit {
|
|
190
|
-
background: ${primary} !important;
|
|
191
|
-
color: ${primaryFg} !important;
|
|
192
|
-
}
|
|
193
|
-
.chat-submit:hover {
|
|
194
|
-
filter: brightness(1.1) !important;
|
|
195
|
-
}
|
|
196
|
-
.chat-submit:disabled {
|
|
197
|
-
background: ${muted} !important;
|
|
198
|
-
color: ${mutedFg} !important;
|
|
199
|
-
filter: none !important;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
/* --- Footer --- */
|
|
203
|
-
.chat-footer {
|
|
204
|
-
background: ${muted} !important;
|
|
205
|
-
color: ${mutedFg} !important;
|
|
206
|
-
border-color: ${border} !important;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
/* --- Tool pills (debug mode) --- */
|
|
210
|
-
.tool-pill {
|
|
211
|
-
background: color-mix(in srgb, ${primary} 15%, ${bg}) !important;
|
|
212
|
-
color: ${fg} !important;
|
|
213
|
-
border-color: ${border} !important;
|
|
214
|
-
}
|
|
215
|
-
.tool-details {
|
|
216
|
-
background: ${card} !important;
|
|
217
|
-
border-color: ${border} !important;
|
|
218
|
-
}
|
|
219
|
-
.tool-details-header {
|
|
220
|
-
background: ${muted} !important;
|
|
221
|
-
color: ${fg} !important;
|
|
222
|
-
}
|
|
223
|
-
.tool-details-content {
|
|
224
|
-
color: ${cardFg} !important;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
/* --- Thinking bubble --- */
|
|
228
|
-
.thinking-bubble { color: ${fg} !important; }
|
|
229
|
-
.thinking-content {
|
|
230
|
-
background: ${muted} !important;
|
|
231
|
-
border-color: ${border} !important;
|
|
232
|
-
color: ${mutedFg} !important;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
/* --- Queued message actions --- */
|
|
236
|
-
.queued-input {
|
|
237
|
-
background: ${input} !important;
|
|
238
|
-
color: ${fg} !important;
|
|
239
|
-
border-color: ${border} !important;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
/* --- Scrollbar (WebKit) --- */
|
|
243
|
-
::-webkit-scrollbar { width: 6px; }
|
|
244
|
-
::-webkit-scrollbar-track { background: ${bg}; }
|
|
245
|
-
::-webkit-scrollbar-thumb {
|
|
246
|
-
background: ${border};
|
|
247
|
-
border-radius: 3px;
|
|
248
|
-
}
|
|
249
|
-
`;
|
|
250
|
-
}
|
|
251
|
-
function OzwellWidget({
|
|
252
|
-
endpoint = DEFAULT_ENDPOINT,
|
|
253
|
-
widgetUrl = DEFAULT_WIDGET_URL,
|
|
254
|
-
primaryColor = OZWELL_PRIMARY,
|
|
255
|
-
theme = "auto",
|
|
256
|
-
iconSrc = OZWELL_ICON_FALLBACK,
|
|
257
|
-
...rest
|
|
258
|
-
}) {
|
|
259
|
-
React.useEffect(() => {
|
|
260
|
-
return () => {
|
|
261
|
-
for (const id of [
|
|
262
|
-
"ozwell-chat-button",
|
|
263
|
-
"ozwell-chat-wrapper",
|
|
264
|
-
"ozwell-default-ui-styles"
|
|
265
|
-
]) {
|
|
266
|
-
document.getElementById(id)?.remove();
|
|
267
|
-
}
|
|
268
|
-
document.querySelector('script[src*="ozwell-loader.js"]')?.remove();
|
|
269
|
-
document.querySelector(
|
|
270
|
-
'iframe[title="Ozwell Chat"], iframe[title="Ozwell Assistant"]'
|
|
271
|
-
)?.remove();
|
|
272
|
-
delete window.OzwellChat;
|
|
273
|
-
delete window.OzwellChatConfig;
|
|
274
|
-
};
|
|
275
|
-
}, []);
|
|
276
|
-
React.useEffect(() => {
|
|
277
|
-
if (document.getElementById(THEME_OVERRIDES_ID)) return;
|
|
278
|
-
const style = document.createElement("style");
|
|
279
|
-
style.id = THEME_OVERRIDES_ID;
|
|
280
|
-
style.textContent = THEME_OVERRIDES_CSS;
|
|
281
|
-
document.head.appendChild(style);
|
|
282
|
-
}, []);
|
|
283
|
-
React.useEffect(() => {
|
|
284
|
-
const timer = setInterval(() => {
|
|
285
|
-
const img = document.querySelector(
|
|
286
|
-
"#ozwell-chat-button .ozwell-chat-icon"
|
|
287
|
-
);
|
|
288
|
-
if (!img || img.tagName !== "IMG") return;
|
|
289
|
-
clearInterval(timer);
|
|
290
|
-
clearTimeout(timeout);
|
|
291
|
-
img.onerror = () => {
|
|
292
|
-
img.src = iconSrc;
|
|
293
|
-
img.onerror = null;
|
|
294
|
-
};
|
|
295
|
-
if (img.complete && img.naturalWidth === 0) {
|
|
296
|
-
img.src = iconSrc;
|
|
297
|
-
}
|
|
298
|
-
}, 200);
|
|
299
|
-
const timeout = setTimeout(() => clearInterval(timer), 5e3);
|
|
300
|
-
return () => {
|
|
301
|
-
clearInterval(timer);
|
|
302
|
-
clearTimeout(timeout);
|
|
303
|
-
};
|
|
304
|
-
}, [iconSrc]);
|
|
305
|
-
React.useEffect(() => {
|
|
306
|
-
const IFRAME_STYLE_ID = "ozwell-mieweb-iframe-theme";
|
|
307
|
-
const findIframe = () => document.querySelector(
|
|
308
|
-
'iframe[title="Ozwell Chat"], iframe[title="Ozwell Assistant"]'
|
|
309
|
-
);
|
|
310
|
-
const injectTheme = () => {
|
|
311
|
-
const iframe = findIframe();
|
|
312
|
-
const doc = iframe?.contentDocument;
|
|
313
|
-
if (!doc) return;
|
|
314
|
-
let style = doc.getElementById(
|
|
315
|
-
IFRAME_STYLE_ID
|
|
316
|
-
);
|
|
317
|
-
if (!style) {
|
|
318
|
-
style = doc.createElement("style");
|
|
319
|
-
style.id = IFRAME_STYLE_ID;
|
|
320
|
-
doc.head.appendChild(style);
|
|
321
|
-
}
|
|
322
|
-
style.textContent = buildIframeThemeCSS();
|
|
323
|
-
};
|
|
324
|
-
let attempts = 0;
|
|
325
|
-
const poll = setInterval(() => {
|
|
326
|
-
attempts++;
|
|
327
|
-
const iframe = findIframe();
|
|
328
|
-
if (iframe?.contentDocument?.body) {
|
|
329
|
-
clearInterval(poll);
|
|
330
|
-
injectTheme();
|
|
331
|
-
}
|
|
332
|
-
if (attempts > 50) clearInterval(poll);
|
|
333
|
-
}, 200);
|
|
334
|
-
const observer = new MutationObserver(() => {
|
|
335
|
-
setTimeout(injectTheme, 50);
|
|
336
|
-
});
|
|
337
|
-
observer.observe(document.documentElement, {
|
|
338
|
-
attributes: true,
|
|
339
|
-
attributeFilter: ["class", "data-theme"]
|
|
340
|
-
});
|
|
341
|
-
return () => {
|
|
342
|
-
clearInterval(poll);
|
|
343
|
-
observer.disconnect();
|
|
344
|
-
};
|
|
345
|
-
}, []);
|
|
346
|
-
return /* @__PURE__ */ jsx(
|
|
347
|
-
OzwellChat,
|
|
348
|
-
{
|
|
349
|
-
endpoint,
|
|
350
|
-
widgetUrl,
|
|
351
|
-
primaryColor,
|
|
352
|
-
theme,
|
|
353
|
-
...rest
|
|
354
|
-
}
|
|
355
|
-
);
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
export { OzwellWidget };
|
|
359
|
-
//# sourceMappingURL=ozwell.js.map
|
|
360
|
-
//# sourceMappingURL=ozwell.js.map
|
package/dist/ozwell.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/AI/OzwellWidget.tsx"],"names":[],"mappings":"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","file":"ozwell.js","sourcesContent":["/**\n * OzwellWidget - MIE-branded wrapper around @ozwell/react's OzwellChat\n *\n * Provides the official Ozwell AI chat widget with MIE brand defaults.\n * This is a real, working AI chat — not a mock. It requires a valid\n * API endpoint and key to function.\n *\n * @example\n * ```tsx\n * // Agent key mode (recommended)\n * <OzwellWidget apiKey=\"agnt_key-your-agent-key\" />\n *\n * // Custom endpoint mode\n * <OzwellWidget\n * endpoint=\"https://ozwell-dev-refserver.opensource.mieweb.org/v1/chat/completions\"\n * apiKey=\"agnt_key-your-key\"\n * onToolCall={(tool, args, sendResult) => {\n * sendResult({ success: true });\n * }}\n * />\n * ```\n */\nimport * as React from 'react';\nimport { OzwellChat, useOzwell } from '@ozwell/react';\nimport type {\n OzwellChatProps,\n OzwellTool,\n OzwellToolFunction,\n OzwellToolParameter,\n OzwellError,\n UseOzwellReturn,\n} from '@ozwell/react';\n\n/** Default Ozwell dev reference server base */\nconst DEV_SERVER = 'https://ozwell-dev-refserver.opensource.mieweb.org';\n\n/** Default chat completions endpoint */\nconst DEFAULT_ENDPOINT = `${DEV_SERVER}/v1/chat/completions`;\n\n/** Default widget URL — the loader script is derived from this */\nconst DEFAULT_WIDGET_URL = `${DEV_SERVER}/embed/ozwell-chat.html`;\n\n/** Ozwell brand primary color */\nconst OZWELL_PRIMARY = '#27aae1';\n\n/**\n * Inline fallback icon — a lightweight Ozwell \"O\" circle in brand blue.\n * The full 900 KB mascot SVG cannot be inlined; this simple glyph is used\n * when the loader's default /favicon.ico 404s and no custom iconSrc is given.\n */\nconst OZWELL_ICON_FALLBACK =\n \"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Ccircle cx='32' cy='32' r='32' fill='%2327aae1'/%3E%3Ctext x='32' y='44' text-anchor='middle' font-size='36' font-family='system-ui,sans-serif' font-weight='700' fill='white'%3EO%3C/text%3E%3C/svg%3E\";\n\n/**\n * Theme-aware CSS overrides for the ozwell-loader's default UI.\n * The loader injects hardcoded colors (#0066ff). These overrides\n * bind to --mieweb-* CSS custom properties so the widget automatically\n * inherits the active brand theme and dark/light mode.\n */\nconst THEME_OVERRIDES_ID = 'ozwell-mieweb-theme-overrides';\nconst THEME_OVERRIDES_CSS = `\n /* ============================\n Ozwell Widget – MIE UI Theme Overrides\n Uses --mieweb-* design tokens for brand + dark mode support.\n ============================ */\n\n /* --- Floating chat button --- */\n @keyframes ozwellFloat {\n 0% { transform: translateY(0) rotate(0deg); }\n 10% { transform: translateY(-5px) rotate(-2deg); }\n 20% { transform: translateY(3px) rotate(3deg); }\n 30% { transform: translateY(-2px) rotate(-1deg); }\n 40% { transform: translateY(4px) rotate(2deg); }\n 50% { transform: translateY(0) rotate(0deg); }\n 60% { transform: translateY(-4px) rotate(2deg); }\n 70% { transform: translateY(2px) rotate(-3deg); }\n 80% { transform: translateY(5px) rotate(1deg); }\n 90% { transform: translateY(-3px) rotate(-2deg); }\n 100% { transform: translateY(0) rotate(0deg); }\n }\n .ozwell-chat-button {\n background: color-mix(in srgb, var(--mieweb-primary-500, #27aae1) 45%, transparent) !important;\n box-shadow: 0 4px 16px color-mix(in srgb, var(--mieweb-primary-500, #27aae1) 30%, transparent) !important;\n animation: ozwellFloat 15s ease-in-out infinite !important;\n }\n .ozwell-chat-button:hover {\n background: color-mix(in srgb, var(--mieweb-primary-500, #27aae1) 65%, transparent) !important;\n box-shadow: 0 6px 20px color-mix(in srgb, var(--mieweb-primary-500, #27aae1) 40%, transparent) !important;\n animation-play-state: paused !important;\n }\n\n /* --- Accessibility: respect reduced-motion preference --- */\n @media (prefers-reduced-motion: reduce) {\n .ozwell-chat-button {\n animation: none !important;\n }\n }\n\n /* --- Unread badge --- */\n .ozwell-unread-badge {\n background: var(--mieweb-destructive, #dc2626) !important;\n border-color: var(--mieweb-background, #ffffff) !important;\n }\n\n /* --- Chat window wrapper --- */\n .ozwell-chat-wrapper {\n background: var(--mieweb-card, #ffffff) !important;\n border-color: var(--mieweb-border, #e5e7eb) !important;\n box-shadow: var(--mieweb-shadow-modal, 0 10px 15px -3px rgb(0 0 0 / 0.1)) !important;\n }\n\n /* --- Header bar --- */\n .ozwell-chat-header {\n background: var(--mieweb-primary-500, #27aae1) !important;\n color: var(--mieweb-primary-foreground, #ffffff) !important;\n }\n\n /* --- Header title --- */\n .ozwell-chat-title {\n color: inherit !important;\n font-family: var(--mieweb-font-sans, inherit) !important;\n }\n\n /* --- Hide / minimize button --- */\n .ozwell-hide-btn {\n color: var(--mieweb-primary-foreground, #ffffff) !important;\n opacity: 0.85;\n }\n .ozwell-hide-btn:hover {\n opacity: 1;\n background: color-mix(in srgb, var(--mieweb-primary-foreground, #ffffff) 15%, transparent) !important;\n }\n\n /* --- Chat icon size --- */\n .ozwell-chat-icon {\n width: 56px !important;\n height: 56px !important;\n }\n`;\n\n/**\n * Reads the current --mieweb-* design-token values from the parent page\n * and returns CSS text that maps the widget's hardcoded colors to the\n * active brand + dark/light mode. Injected into the iframe's <head>.\n */\nfunction buildIframeThemeCSS(): string {\n const root = document.documentElement;\n const get = (v: string, fallback: string) =>\n getComputedStyle(root).getPropertyValue(v).trim() || fallback;\n\n const bg = get('--mieweb-background', '#ffffff');\n const fg = get('--mieweb-foreground', '#171717');\n const card = get('--mieweb-card', '#ffffff');\n const cardFg = get('--mieweb-card-foreground', '#171717');\n const muted = get('--mieweb-muted', '#f5f5f5');\n const mutedFg = get('--mieweb-muted-foreground', '#737373');\n const border = get('--mieweb-border', '#e5e7eb');\n const input = get('--mieweb-input', '#e5e7eb');\n const primary = get('--mieweb-primary-500', '#27aae1');\n const primaryFg = get('--mieweb-primary-foreground', '#ffffff');\n const ring = get('--mieweb-ring', '#27aae1');\n const fontSans = get(\n '--mieweb-font-sans',\n \"'Nunito', ui-sans-serif, system-ui, sans-serif\"\n );\n\n return `\n /* MIE UI iframe theme overrides — regenerated on theme change */\n\n /* --- Layout --- */\n body, .chat-container {\n background: ${bg} !important;\n color: ${fg} !important;\n font-family: ${fontSans} !important;\n }\n\n /* --- Status strip --- */\n .status-strip {\n background: ${muted} !important;\n border-color: ${border} !important;\n }\n .status { color: ${mutedFg} !important; }\n\n /* --- Reasoning controls --- */\n .reasoning-capsule {\n background: ${muted} !important;\n color: ${fg} !important;\n border-color: ${border} !important;\n }\n .reasoning-seg {\n background: ${card} !important;\n border-color: ${border} !important;\n }\n .reasoning-seg-btn {\n color: ${mutedFg} !important;\n }\n .reasoning-seg-btn.active {\n background: ${primary} !important;\n color: ${primaryFg} !important;\n }\n\n /* --- Messages --- */\n .messages { background: ${bg} !important; }\n\n .message.user {\n background: ${primary} !important;\n color: ${primaryFg} !important;\n }\n .message.assistant {\n background: ${card} !important;\n color: ${cardFg} !important;\n border: 1px solid ${border} !important;\n }\n .message.system {\n background: ${muted} !important;\n color: ${fg} !important;\n }\n .message.welcome {\n background: ${card} !important;\n color: ${mutedFg} !important;\n border-color: ${border} !important;\n }\n .message.queued {\n border-color: ${border} !important;\n color: ${mutedFg} !important;\n }\n\n /* --- Input area --- */\n .chat-form {\n background: ${bg} !important;\n border-top: 1px solid ${border} !important;\n }\n .chat-input {\n background: ${input} !important;\n color: ${fg} !important;\n border-color: ${border} !important;\n font-family: ${fontSans} !important;\n }\n .chat-input::placeholder { color: ${mutedFg} !important; }\n .chat-input:focus {\n border-color: ${ring} !important;\n box-shadow: 0 0 0 2px ${ring}33 !important;\n }\n\n /* --- Send button --- */\n .chat-submit {\n background: ${primary} !important;\n color: ${primaryFg} !important;\n }\n .chat-submit:hover {\n filter: brightness(1.1) !important;\n }\n .chat-submit:disabled {\n background: ${muted} !important;\n color: ${mutedFg} !important;\n filter: none !important;\n }\n\n /* --- Footer --- */\n .chat-footer {\n background: ${muted} !important;\n color: ${mutedFg} !important;\n border-color: ${border} !important;\n }\n\n /* --- Tool pills (debug mode) --- */\n .tool-pill {\n background: color-mix(in srgb, ${primary} 15%, ${bg}) !important;\n color: ${fg} !important;\n border-color: ${border} !important;\n }\n .tool-details {\n background: ${card} !important;\n border-color: ${border} !important;\n }\n .tool-details-header {\n background: ${muted} !important;\n color: ${fg} !important;\n }\n .tool-details-content {\n color: ${cardFg} !important;\n }\n\n /* --- Thinking bubble --- */\n .thinking-bubble { color: ${fg} !important; }\n .thinking-content {\n background: ${muted} !important;\n border-color: ${border} !important;\n color: ${mutedFg} !important;\n }\n\n /* --- Queued message actions --- */\n .queued-input {\n background: ${input} !important;\n color: ${fg} !important;\n border-color: ${border} !important;\n }\n\n /* --- Scrollbar (WebKit) --- */\n ::-webkit-scrollbar { width: 6px; }\n ::-webkit-scrollbar-track { background: ${bg}; }\n ::-webkit-scrollbar-thumb {\n background: ${border};\n border-radius: 3px;\n }\n `;\n}\n\nexport type OzwellWidgetProps = OzwellChatProps & {\n /**\n * Custom icon URL for the static (non-animated) chat launcher button.\n * Used as a fallback when the loader's default icon fails to load.\n * Defaults to a lightweight inline Ozwell \"O\" glyph.\n */\n iconSrc?: string;\n};\n\nexport function OzwellWidget({\n endpoint = DEFAULT_ENDPOINT,\n widgetUrl = DEFAULT_WIDGET_URL,\n primaryColor = OZWELL_PRIMARY,\n theme = 'auto',\n iconSrc = OZWELL_ICON_FALLBACK,\n ...rest\n}: OzwellWidgetProps) {\n // Clean up ozwell-loader DOM artifacts on unmount.\n // The vanilla loader injects a fixed-position button, chat wrapper, iframe,\n // and style tags directly into document.body — none of which get removed\n // when the React component unmounts. Without this, the button persists\n // across Storybook story navigation (or any SPA route change).\n React.useEffect(() => {\n return () => {\n // Remove loader-injected DOM elements\n for (const id of [\n 'ozwell-chat-button',\n 'ozwell-chat-wrapper',\n 'ozwell-default-ui-styles',\n ]) {\n document.getElementById(id)?.remove();\n }\n // Remove the loader script tag so it can be re-injected fresh\n document.querySelector('script[src*=\"ozwell-loader.js\"]')?.remove();\n // Remove the iframe (may not have an ID)\n document\n .querySelector(\n 'iframe[title=\"Ozwell Chat\"], iframe[title=\"Ozwell Assistant\"]'\n )\n ?.remove();\n // Clear global state so next mount starts fresh\n delete (window as unknown as Record<string, unknown>).OzwellChat;\n delete (window as unknown as Record<string, unknown>).OzwellChatConfig;\n };\n }, []);\n\n // Inject MIE UI theme overrides so the widget inherits brand tokens.\n // This <style> tag overrides the ozwell-loader's hardcoded colors\n // with --mieweb-* CSS custom properties, enabling brand + dark mode.\n // Not removed on unmount — idempotent CSS safe to leave in place,\n // prevents multi-instance bugs when one widget unmounts while another is live.\n React.useEffect(() => {\n if (document.getElementById(THEME_OVERRIDES_ID)) return;\n const style = document.createElement('style');\n style.id = THEME_OVERRIDES_ID;\n style.textContent = THEME_OVERRIDES_CSS;\n document.head.appendChild(style);\n }, []);\n\n // Fix broken launcher icon — the loader hardcodes src=\"/favicon.ico\" which\n // 404s when hosted on a different origin (e.g. Storybook). Replace with the\n // Ozwell brand icon from the design system.\n React.useEffect(() => {\n // The button is created asynchronously by the loader script, so poll briefly.\n // Once the icon element is found and handled, stop polling immediately.\n const timer = setInterval(() => {\n const img = document.querySelector(\n '#ozwell-chat-button .ozwell-chat-icon'\n ) as HTMLImageElement | null;\n if (!img || img.tagName !== 'IMG') return;\n\n // Found the icon — stop polling\n clearInterval(timer);\n clearTimeout(timeout);\n\n img.onerror = () => {\n img.src = iconSrc;\n img.onerror = null; // prevent infinite loop\n };\n // If already broken (naturalWidth 0), fix immediately\n if (img.complete && img.naturalWidth === 0) {\n img.src = iconSrc;\n }\n }, 200);\n const timeout = setTimeout(() => clearInterval(timer), 5000);\n return () => {\n clearInterval(timer);\n clearTimeout(timeout);\n };\n }, [iconSrc]);\n\n // Inject theme-aware CSS into the Ozwell iframe. The iframe content has\n // hardcoded colors (#0066ff, #ffffff, etc.) with no dark mode or theming.\n // Since it uses srcdoc it is same-origin, so we can access contentDocument.\n // We read --mieweb-* token values from the parent and inject them as\n // literal colors, then re-inject whenever the parent theme changes.\n React.useEffect(() => {\n const IFRAME_STYLE_ID = 'ozwell-mieweb-iframe-theme';\n\n /** Find the ozwell iframe in the parent DOM */\n const findIframe = () =>\n document.querySelector(\n 'iframe[title=\"Ozwell Chat\"], iframe[title=\"Ozwell Assistant\"]'\n ) as HTMLIFrameElement | null;\n\n /** Inject (or replace) the theme CSS inside the iframe */\n const injectTheme = () => {\n const iframe = findIframe();\n const doc = iframe?.contentDocument;\n if (!doc) return;\n let style = doc.getElementById(\n IFRAME_STYLE_ID\n ) as HTMLStyleElement | null;\n if (!style) {\n style = doc.createElement('style');\n style.id = IFRAME_STYLE_ID;\n doc.head.appendChild(style);\n }\n style.textContent = buildIframeThemeCSS();\n };\n\n // Poll until the iframe is ready, then inject\n let attempts = 0;\n const poll = setInterval(() => {\n attempts++;\n const iframe = findIframe();\n if (iframe?.contentDocument?.body) {\n clearInterval(poll);\n injectTheme();\n }\n if (attempts > 50) clearInterval(poll); // give up after 10s\n }, 200);\n\n // Watch for theme changes on <html> (class or data-theme attribute)\n const observer = new MutationObserver(() => {\n // Small delay so CSS variables have settled\n setTimeout(injectTheme, 50);\n });\n observer.observe(document.documentElement, {\n attributes: true,\n attributeFilter: ['class', 'data-theme'],\n });\n\n return () => {\n clearInterval(poll);\n observer.disconnect();\n };\n }, []);\n\n return (\n <OzwellChat\n endpoint={endpoint}\n widgetUrl={widgetUrl}\n primaryColor={primaryColor}\n theme={theme}\n {...rest}\n />\n );\n}\n\n// Re-export hook and types for convenience\nexport { useOzwell };\nexport type {\n OzwellChatProps,\n OzwellTool,\n OzwellToolFunction,\n OzwellToolParameter,\n OzwellError,\n UseOzwellReturn,\n};\n"]}
|