@ourlu/assistant-sdk 0.2.4 → 0.2.5

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.
Files changed (44) hide show
  1. package/dist/iife/audio.v1.028c93fe.js +160 -0
  2. package/dist/iife/audio.v1.051ececf.js +183 -0
  3. package/dist/iife/audio.v1.200db1a6.js +208 -0
  4. package/dist/iife/audio.v1.20858b08.js +191 -0
  5. package/dist/iife/audio.v1.2690e445.js +179 -0
  6. package/dist/iife/audio.v1.2742ff12.js +188 -0
  7. package/dist/iife/audio.v1.70af81b3.js +191 -0
  8. package/dist/iife/audio.v1.95146620.js +1 -1
  9. package/dist/iife/audio.v1.b330baaf.js +166 -0
  10. package/dist/iife/audio.v1.bb9c2d88.js +181 -0
  11. package/dist/iife/audio.v1.ea7571b2.js +182 -0
  12. package/dist/iife/audio.v1.fc0aa8af.js +191 -0
  13. package/dist/iife/audio.v1.js +107 -95
  14. package/dist/iife/engine.v1.2b5bb43b.js +3 -3
  15. package/dist/iife/engine.v1.3b09dc20.js +3 -3
  16. package/dist/iife/engine.v1.56074e5a.js +769 -0
  17. package/dist/iife/engine.v1.61c10e6c.js +770 -0
  18. package/dist/iife/engine.v1.773fc15d.js +2 -2
  19. package/dist/iife/engine.v1.80d2230f.js +3 -3
  20. package/dist/iife/engine.v1.940ba9ea.js +764 -0
  21. package/dist/iife/engine.v1.99a33ee2.js +767 -0
  22. package/dist/iife/engine.v1.9ca6b7ec.js +3 -3
  23. package/dist/iife/engine.v1.a1f7dea2.js +764 -0
  24. package/dist/iife/engine.v1.c0c00bd0.js +3 -3
  25. package/dist/iife/engine.v1.c127656e.js +820 -0
  26. package/dist/iife/engine.v1.c54c9a1a.js +3 -3
  27. package/dist/iife/engine.v1.d1052e81.js +3 -3
  28. package/dist/iife/engine.v1.f6d23a0f.js +770 -0
  29. package/dist/iife/engine.v1.js +75 -25
  30. package/dist/iife/loader.v1.js +5 -1
  31. package/dist/iife/signalement.v1.d321dfde.js +518 -0
  32. package/dist/iife/signalement.v1.js +518 -0
  33. package/dist/iife/ui.v1.00abf020.js +895 -0
  34. package/dist/iife/ui.v1.6becaa84.js +895 -0
  35. package/dist/iife/ui.v1.6c9e4995.js +895 -0
  36. package/dist/iife/ui.v1.88bf5494.js +898 -0
  37. package/dist/iife/ui.v1.a8cfe724.js +900 -0
  38. package/dist/iife/ui.v1.e007c7c4.js +926 -0
  39. package/dist/iife/ui.v1.e24ba2bd.js +903 -0
  40. package/dist/iife/ui.v1.f1d8e998.js +903 -0
  41. package/dist/iife/ui.v1.fc52b520.js +895 -0
  42. package/dist/iife/ui.v1.js +44 -77
  43. package/dist/iife/widget-manifest.json +4 -3
  44. package/package.json +2 -1
@@ -0,0 +1,895 @@
1
+ (function() {
2
+ function installColorUtils(ui) {
3
+ ui.clampAlpha = function clampAlpha(rawValue) {
4
+ var parsed = Number(rawValue);
5
+ if (!Number.isFinite(parsed)) return 1;
6
+ if (parsed < 0) return 0;
7
+ if (parsed > 1) return 1;
8
+ return parsed;
9
+ };
10
+
11
+ ui.normalizeHexColor = function normalizeHexColor(rawValue, fallbackColor) {
12
+ var color = String(rawValue || "").trim().toLowerCase();
13
+ if (!/^#[0-9a-f]{6}$/.test(color)) return fallbackColor;
14
+ return color;
15
+ };
16
+
17
+ ui.hexToRgba = function hexToRgba(hexColor, alphaValue) {
18
+ var normalized = ui.normalizeHexColor(hexColor, "#ffffff");
19
+ var alpha = ui.clampAlpha(alphaValue);
20
+ var r = parseInt(normalized.slice(1, 3), 16);
21
+ var g = parseInt(normalized.slice(3, 5), 16);
22
+ var b = parseInt(normalized.slice(5, 7), 16);
23
+ return "rgba(" + r + "," + g + "," + b + "," + alpha + ")";
24
+ };
25
+
26
+ ui.clampColorChannel = function clampColorChannel(channelValue) {
27
+ return Math.max(0, Math.min(255, channelValue));
28
+ };
29
+
30
+ ui.adjustHexBrightness = function adjustHexBrightness(hexColor, percentage) {
31
+ var normalizedColor = ui.normalizeHexColor(hexColor, "#000000");
32
+ var adjustment = Math.round((Number(percentage) / 100) * 255);
33
+ var red = ui.clampColorChannel(parseInt(normalizedColor.slice(1, 3), 16) + adjustment);
34
+ var green = ui.clampColorChannel(parseInt(normalizedColor.slice(3, 5), 16) + adjustment);
35
+ var blue = ui.clampColorChannel(parseInt(normalizedColor.slice(5, 7), 16) + adjustment);
36
+ return "#" + red.toString(16).padStart(2, "0") + green.toString(16).padStart(2, "0") + blue.toString(16).padStart(2, "0");
37
+ };
38
+ }
39
+
40
+ function installMascotTheme(ui) {
41
+ ui.mascotSvgSourceCache = {};
42
+
43
+ ui.escapeRegExp = function escapeRegExp(rawValue) {
44
+ return String(rawValue || "").replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
45
+ };
46
+
47
+ ui.replaceSvgColorTokens = function replaceSvgColorTokens(rawSvgMarkup, colorMap) {
48
+ var themedMarkup = String(rawSvgMarkup || "");
49
+ Object.keys(colorMap).forEach(function(token) {
50
+ var resolvedColor = String(colorMap[token] || "").trim();
51
+ if (!resolvedColor) return;
52
+ themedMarkup = themedMarkup.replace(new RegExp(ui.escapeRegExp(token), "gi"), resolvedColor);
53
+ });
54
+ return themedMarkup;
55
+ };
56
+
57
+ ui.assignMascotTokenGroup = function assignMascotTokenGroup(replacementMap, tokens, replacementColor) {
58
+ tokens.forEach(function(token) {
59
+ replacementMap[token] = replacementColor;
60
+ });
61
+ };
62
+
63
+ ui.buildMascotDerivedPalette = function buildMascotDerivedPalette(config) {
64
+ var blue500 = ui.normalizeHexColor(config.mascotSecondaryColor, "#68b1d6");
65
+ var blue700 = ui.normalizeHexColor(config.mascotSecondaryDarkColor, "#1472a8");
66
+ var gold500 = ui.normalizeHexColor(config.mascotGoldColor, "#ffd22e");
67
+ var eye500 = ui.normalizeHexColor(config.mascotEyeColor, "#040402");
68
+ var beak300 = ui.normalizeHexColor(config.mascotBeakColor, "#ab5f30");
69
+ var claw300 = ui.normalizeHexColor(config.mascotClawColor, "#ab5f30");
70
+ var neutral200 = ui.normalizeHexColor(config.mascotNeutralColor, "#e6e6e6");
71
+ var brow500 = ui.normalizeHexColor(config.mascotBrowColor, "#3e3e3e");
72
+ return {
73
+ blue400: ui.adjustHexBrightness(blue500, 8),
74
+ blue500: blue500,
75
+ blue550: ui.adjustHexBrightness(blue500, -6),
76
+ blue580: ui.adjustHexBrightness(blue500, -24),
77
+ blue600: ui.adjustHexBrightness(blue700, 12),
78
+ blue700: blue700,
79
+ blue800: ui.adjustHexBrightness(blue700, -10),
80
+ gold500: gold500,
81
+ gold450: ui.adjustHexBrightness(gold500, -6),
82
+ gold700: ui.adjustHexBrightness(gold500, -24),
83
+ gold900: ui.adjustHexBrightness(gold500, -42),
84
+ eye500: eye500,
85
+ eye900: ui.adjustHexBrightness(eye500, -26),
86
+ beak300: beak300,
87
+ beak400: ui.adjustHexBrightness(beak300, 14),
88
+ beak500: ui.adjustHexBrightness(beak300, 8),
89
+ beak700: ui.adjustHexBrightness(beak300, -24),
90
+ claw300: claw300,
91
+ claw400: ui.adjustHexBrightness(claw300, 18),
92
+ claw700: ui.adjustHexBrightness(claw300, -30),
93
+ brow500: brow500,
94
+ brow400: ui.adjustHexBrightness(brow500, 4),
95
+ neutral200: neutral200,
96
+ neutral300: ui.adjustHexBrightness(neutral200, -18),
97
+ black: ui.adjustHexBrightness(eye500, -40),
98
+ white: "#ffffff"
99
+ };
100
+ };
101
+
102
+ ui.buildMascotColorReplacementMap = function buildMascotColorReplacementMap(config) {
103
+ var palette = ui.buildMascotDerivedPalette(config || {});
104
+ var replacementMap = {};
105
+ ui.assignMascotTokenGroup(replacementMap, ["#70c1ea"], palette.blue400);
106
+ ui.assignMascotTokenGroup(replacementMap, ["#68b1d6"], palette.blue500);
107
+ ui.assignMascotTokenGroup(replacementMap, ["#44aade"], palette.blue550);
108
+ ui.assignMascotTokenGroup(replacementMap, ["#4a9ac3"], palette.blue580);
109
+ ui.assignMascotTokenGroup(replacementMap, ["#2f97cc"], palette.blue600);
110
+ ui.assignMascotTokenGroup(replacementMap, ["#1472a8"], palette.blue700);
111
+ ui.assignMascotTokenGroup(replacementMap, ["#156696"], palette.blue800);
112
+ ui.assignMascotTokenGroup(replacementMap, ["#ffd22e"], palette.gold500);
113
+ ui.assignMascotTokenGroup(replacementMap, ["#f0c31f"], palette.gold450);
114
+ ui.assignMascotTokenGroup(replacementMap, ["#c29500"], palette.gold700);
115
+ ui.assignMascotTokenGroup(replacementMap, ["#946700"], palette.gold900);
116
+ ui.assignMascotTokenGroup(replacementMap, ["#040402", "#00193b"], palette.eye900);
117
+ ui.assignMascotTokenGroup(replacementMap, ["#ab5f30"], palette.beak300);
118
+ ui.assignMascotTokenGroup(replacementMap, ["#dd8e5d", "#dd9060", "#ca7e4f"], palette.beak400);
119
+ ui.assignMascotTokenGroup(replacementMap, ["#d98d5e"], palette.beak500);
120
+ ui.assignMascotTokenGroup(replacementMap, ["#6e2200"], palette.beak700);
121
+ ui.assignMascotTokenGroup(replacementMap, ["#6f2301"], palette.claw700);
122
+ ui.assignMascotTokenGroup(replacementMap, ["#da8e5f"], palette.claw400);
123
+ ui.assignMascotTokenGroup(replacementMap, ["#3e3e3e"], palette.brow500);
124
+ ui.assignMascotTokenGroup(replacementMap, ["#434343"], palette.brow400);
125
+ ui.assignMascotTokenGroup(replacementMap, ["#e6e6e6"], palette.neutral200);
126
+ replacementMap.white = palette.white;
127
+ replacementMap.black = palette.black;
128
+ return replacementMap;
129
+ };
130
+
131
+ ui.isLikelySvgAsset = function isLikelySvgAsset(rawUrl) {
132
+ return /\.svg(?:[?#].*)?$/i.test(String(rawUrl || "").trim());
133
+ };
134
+
135
+ ui.resolveAbsoluteMascotUrl = function resolveAbsoluteMascotUrl(mascotUrl, apiBaseUrl) {
136
+ var normalized = String(mascotUrl || "").trim();
137
+ if (!normalized) return "";
138
+ if (/^https?:\/\//i.test(normalized)) return normalized;
139
+ var base = String(apiBaseUrl || "").trim().replace(/\/$/, "");
140
+ if (!base) {
141
+ throw new Error("[OurluMairie] mascot URL relative sans apiBaseUrl: " + normalized);
142
+ }
143
+ return normalized.startsWith("/") ? base + normalized : base + "/" + normalized;
144
+ };
145
+
146
+ ui.encodeSvgToDataUrl = function encodeSvgToDataUrl(svgMarkup) {
147
+ return "data:image/svg+xml;charset=utf-8," + encodeURIComponent(String(svgMarkup || ""));
148
+ };
149
+
150
+ ui.resolveMascotUrlWithTheme = function resolveMascotUrlWithTheme(mascotUrl, config) {
151
+ var normalizedMascotUrl = ui.resolveAbsoluteMascotUrl(mascotUrl, (config || {}).apiBaseUrl);
152
+ if (!normalizedMascotUrl || typeof fetch !== "function" || !ui.isLikelySvgAsset(normalizedMascotUrl)) {
153
+ return Promise.resolve(normalizedMascotUrl);
154
+ }
155
+ var replacementMap = ui.buildMascotColorReplacementMap(config || {});
156
+ var cacheKey = normalizedMascotUrl + "::" + [
157
+ ui.normalizeHexColor((config || {}).mascotSecondaryColor, "#68b1d6"),
158
+ ui.normalizeHexColor((config || {}).mascotSecondaryDarkColor, "#1472a8"),
159
+ ui.normalizeHexColor((config || {}).mascotGoldColor, "#ffd22e"),
160
+ ui.normalizeHexColor((config || {}).mascotEyeColor, "#040402"),
161
+ ui.normalizeHexColor((config || {}).mascotBeakColor, "#ab5f30"),
162
+ ui.normalizeHexColor((config || {}).mascotNeutralColor, "#e6e6e6"),
163
+ ui.normalizeHexColor((config || {}).mascotBrowColor, "#3e3e3e"),
164
+ ui.normalizeHexColor((config || {}).mascotClawColor, "#ab5f30")
165
+ ].join("::");
166
+ if (ui.mascotSvgSourceCache[cacheKey]) {
167
+ return Promise.resolve(ui.mascotSvgSourceCache[cacheKey]);
168
+ }
169
+ return fetch(normalizedMascotUrl, { method: "GET", credentials: "omit" })
170
+ .then(function(response) {
171
+ if (!response.ok) {
172
+ throw new Error("mascot fetch failed");
173
+ }
174
+ return response.text();
175
+ })
176
+ .then(function(rawSvgMarkup) {
177
+ if (!rawSvgMarkup || rawSvgMarkup.indexOf("<svg") === -1) {
178
+ throw new Error("mascot SVG invalide ou reponse non-SVG pour " + normalizedMascotUrl);
179
+ }
180
+ var themedSvgMarkup = ui.replaceSvgColorTokens(rawSvgMarkup, replacementMap);
181
+ var themedDataUrl = ui.encodeSvgToDataUrl(themedSvgMarkup);
182
+ ui.mascotSvgSourceCache[cacheKey] = themedDataUrl;
183
+ return themedDataUrl;
184
+ });
185
+ };
186
+ }
187
+
188
+ function installMarkdownRender(ui) {
189
+ ui.escapeHtml = function escapeHtml(rawValue) {
190
+ return String(rawValue || "")
191
+ .replace(/&/g, "&amp;")
192
+ .replace(/</g, "&lt;")
193
+ .replace(/>/g, "&gt;")
194
+ .replace(/"/g, "&quot;")
195
+ .replace(/'/g, "&#39;");
196
+ };
197
+
198
+ ui.escapeHtmlAttribute = function escapeHtmlAttribute(rawValue) {
199
+ return ui.escapeHtml(rawValue).replace(/`/g, "&#96;");
200
+ };
201
+
202
+ ui.renderInlineMarkdown = function renderInlineMarkdown(rawText) {
203
+ var escaped = ui.escapeHtml(rawText);
204
+ escaped = escaped.replace(/\[([^\]\n]+)\]\((https?:\/\/[^\s)]+)\)/g, function(_match, label, url) {
205
+ return '<a href="' + ui.escapeHtmlAttribute(url) + '" target="_blank" rel="noopener noreferrer">' + label + "</a>";
206
+ });
207
+ escaped = escaped.replace(/`([^`\n]+)`/g, "<code>$1</code>");
208
+ escaped = escaped.replace(/\*\*([^*\n]+)\*\*/g, "<strong>$1</strong>");
209
+ escaped = escaped.replace(/\*([^*\n]+)\*/g, "<em>$1</em>");
210
+ return escaped;
211
+ };
212
+
213
+ ui.renderAssistantMarkdown = function renderAssistantMarkdown(rawText) {
214
+ var normalized = String(rawText || "").replace(/\r\n?/g, "\n").trim();
215
+ if (!normalized) {
216
+ return "";
217
+ }
218
+
219
+ var codeBlocks = [];
220
+ normalized = normalized.replace(/```([\s\S]*?)```/g, function(_match, codeContent) {
221
+ var placeholder = "@@CM_CODE_BLOCK_" + codeBlocks.length + "@@";
222
+ codeBlocks.push(
223
+ '<pre><code>' + ui.escapeHtml(String(codeContent || "").replace(/^\n+|\n+$/g, "")) + "</code></pre>"
224
+ );
225
+ return placeholder;
226
+ });
227
+
228
+ var htmlParts = [];
229
+ var listType = "";
230
+ var listItems = [];
231
+ var lines = normalized.split("\n");
232
+
233
+ function flushList() {
234
+ if (!listType || listItems.length === 0) {
235
+ listType = "";
236
+ listItems = [];
237
+ return;
238
+ }
239
+ htmlParts.push("<" + listType + ">" + listItems.join("") + "</" + listType + ">");
240
+ listType = "";
241
+ listItems = [];
242
+ }
243
+
244
+ for (var index = 0; index < lines.length; index += 1) {
245
+ var rawLine = lines[index];
246
+ var trimmedLine = rawLine.trim();
247
+ if (!trimmedLine) {
248
+ flushList();
249
+ continue;
250
+ }
251
+
252
+ var unorderedMatch = trimmedLine.match(/^[-*]\s+(.+)$/);
253
+ if (unorderedMatch) {
254
+ if (listType && listType !== "ul") {
255
+ flushList();
256
+ }
257
+ listType = "ul";
258
+ listItems.push("<li>" + ui.renderInlineMarkdown(unorderedMatch[1]) + "</li>");
259
+ continue;
260
+ }
261
+
262
+ var orderedMatch = trimmedLine.match(/^\d+\.\s+(.+)$/);
263
+ if (orderedMatch) {
264
+ if (listType && listType !== "ol") {
265
+ flushList();
266
+ }
267
+ listType = "ol";
268
+ listItems.push("<li>" + ui.renderInlineMarkdown(orderedMatch[1]) + "</li>");
269
+ continue;
270
+ }
271
+
272
+ flushList();
273
+
274
+ var headingMatch = trimmedLine.match(/^(#{1,3})\s+(.+)$/);
275
+ if (headingMatch) {
276
+ var level = Math.min(4, headingMatch[1].length + 2);
277
+ htmlParts.push("<h" + level + ">" + ui.renderInlineMarkdown(headingMatch[2]) + "</h" + level + ">");
278
+ continue;
279
+ }
280
+
281
+ htmlParts.push("<p>" + ui.renderInlineMarkdown(trimmedLine) + "</p>");
282
+ }
283
+
284
+ flushList();
285
+
286
+ var rendered = htmlParts.join("");
287
+ rendered = rendered.replace(/@@CM_CODE_BLOCK_(\d+)@@/g, function(_match, rawIndex) {
288
+ var blockIndex = Number(rawIndex);
289
+ if (!Number.isInteger(blockIndex) || blockIndex < 0 || blockIndex >= codeBlocks.length) {
290
+ return "";
291
+ }
292
+ return codeBlocks[blockIndex];
293
+ });
294
+ return rendered || "<p>" + ui.renderInlineMarkdown(normalized) + "</p>";
295
+ };
296
+ }
297
+
298
+ function installMediaUtils(ui) {
299
+ ui.trimTrailingSlash = function trimTrailingSlash(value) {
300
+ return String(value || "").replace(/\/$/, "");
301
+ };
302
+
303
+ ui.mergeTranscript = function mergeTranscript(currentText, delta) {
304
+ var base = String(currentText || "");
305
+ var incoming = String(delta || "").replace(/^\s+/, "");
306
+ if (!incoming) return base;
307
+ if (!base) return incoming;
308
+ var lastChar = base[base.length - 1];
309
+ var firstChar = incoming[0];
310
+ var noSpaceAfter = [" ", "\n", "'", "\"", "(", "[", "{", "/", "-"];
311
+ var noSpaceBefore = [".", ",", ";", ":", "!", "?", ")", "]", "}", "/", "-"];
312
+ var needsSpace = noSpaceAfter.indexOf(lastChar) === -1 && noSpaceBefore.indexOf(firstChar) === -1;
313
+ return needsSpace ? base + " " + incoming : base + incoming;
314
+ };
315
+
316
+ ui.resolveRecorderMimeType = function resolveRecorderMimeType() {
317
+ if (typeof MediaRecorder === "undefined") return "";
318
+ var preferred = ["audio/webm;codecs=opus", "audio/webm", "audio/ogg;codecs=opus", "audio/ogg", "audio/mp4"];
319
+ for (var i = 0; i < preferred.length; i += 1) {
320
+ if (MediaRecorder.isTypeSupported(preferred[i])) return preferred[i];
321
+ }
322
+ return "";
323
+ };
324
+
325
+ ui.encodeArrayBufferToBase64 = function encodeArrayBufferToBase64(arrayBuffer) {
326
+ var bytes = new Uint8Array(arrayBuffer);
327
+ var chunkSize = 0x8000;
328
+ var chunks = [];
329
+ for (var offset = 0; offset < bytes.length; offset += chunkSize) {
330
+ var part = bytes.subarray(offset, offset + chunkSize);
331
+ chunks.push(String.fromCharCode.apply(null, part));
332
+ }
333
+ return btoa(chunks.join(""));
334
+ };
335
+ }
336
+
337
+ function installEventBus(ui) {
338
+ function EventBus() {
339
+ this.events = {};
340
+ }
341
+
342
+ EventBus.prototype.on = function(eventName, handler) {
343
+ if (!this.events[eventName]) this.events[eventName] = [];
344
+ this.events[eventName].push(handler);
345
+ };
346
+
347
+ EventBus.prototype.emit = function(eventName, payload) {
348
+ var handlers = this.events[eventName] || [];
349
+ handlers.forEach(function(handler) {
350
+ try { handler(payload); } catch (_) {}
351
+ });
352
+ };
353
+
354
+ ui.EventBus = EventBus;
355
+ }
356
+
357
+ function installWidgetCssBuilder(ui) {
358
+ function WidgetCssBuilder(config) {
359
+ this.config = config;
360
+ }
361
+
362
+ WidgetCssBuilder.prototype.resolveLayout = function() {
363
+ var panelWidth = Number(this.config.panelWidth);
364
+ if (!Number.isFinite(panelWidth)) panelWidth = 420;
365
+ panelWidth = Math.max(360, Math.min(960, Math.round(panelWidth)));
366
+
367
+ var panelHeight = Number(this.config.panelHeight);
368
+ if (!Number.isFinite(panelHeight)) panelHeight = 640;
369
+ panelHeight = Math.max(480, Math.min(1400, Math.round(panelHeight)));
370
+
371
+ var panelMaxHeightVh = Number(this.config.panelMaxHeightVh);
372
+ if (!Number.isFinite(panelMaxHeightVh)) panelMaxHeightVh = 85;
373
+ panelMaxHeightVh = Math.max(60, Math.min(98, Math.round(panelMaxHeightVh)));
374
+
375
+ var borderRadius = Number(this.config.panelBorderRadius);
376
+ if (!Number.isFinite(borderRadius)) borderRadius = 16;
377
+ borderRadius = Math.max(0, Math.min(32, Math.round(borderRadius)));
378
+
379
+ return {
380
+ panelWidth: panelWidth,
381
+ panelHeight: panelHeight,
382
+ panelMaxHeightVh: panelMaxHeightVh,
383
+ borderRadius: borderRadius
384
+ };
385
+ };
386
+
387
+ WidgetCssBuilder.prototype.build = function() {
388
+ var cfg = this.config;
389
+ var side = cfg.position === "bottom-left" ? "left" : "right";
390
+ var gradient = "linear-gradient(135deg," + cfg.primaryColor + " 0%,#0047b3 100%)";
391
+ var panelBg = ui.hexToRgba(cfg.panelBackgroundColor, cfg.panelBackgroundAlpha);
392
+ var layout = this.resolveLayout();
393
+ var pw = layout.panelWidth + "px";
394
+ var ph = layout.panelHeight + "px";
395
+ var mhVh = layout.panelMaxHeightVh + "vh";
396
+ var br = layout.borderRadius + "px";
397
+
398
+ return [
399
+ this.buildResetAndBase(),
400
+ this.buildBubble(side, gradient, cfg.primaryColor),
401
+ this.buildPanel(side, pw, ph, mhVh, panelBg, br),
402
+ this.buildHeader(gradient, br),
403
+ this.buildNotes(),
404
+ this.buildMessages(),
405
+ this.buildMessageBubbles(cfg.primaryColor),
406
+ this.buildTypingAndError(),
407
+ this.buildComposer(cfg.primaryColor, br),
408
+ this.buildMobileOverrides()
409
+ ].join("\n");
410
+ };
411
+
412
+ WidgetCssBuilder.prototype.buildResetAndBase = function() {
413
+ return [
414
+ ":host *{box-sizing:border-box;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,system-ui,sans-serif;-webkit-font-smoothing:antialiased}",
415
+ ":host button{outline:none;-webkit-tap-highlight-color:transparent}",
416
+ ":host button:focus{outline:none}",
417
+ ":host button:focus-visible{outline:2px solid rgba(0,102,255,.4);outline-offset:2px}"
418
+ ].join("\n");
419
+ };
420
+
421
+ WidgetCssBuilder.prototype.buildBubble = function(side, gradient, primaryColor) {
422
+ return [
423
+ "#cm-bubble{position:fixed;" + side + ":20px;bottom:20px;width:64px;height:64px;border-radius:50%;background:" + gradient + ";border:none;cursor:pointer;display:flex;align-items:center;justify-content:center;z-index:2147483000;box-shadow:0 8px 24px rgba(0,0,0,.28),0 2px 8px rgba(0,0,0,.12);transition:transform .2s cubic-bezier(.4,0,.2,1)}",
424
+ "#cm-bubble:hover{transform:scale(1.1)}",
425
+ "#cm-bubble:active{transform:scale(0.95)}",
426
+ "#cm-bubble:focus-visible{outline:3px solid " + primaryColor + ";outline-offset:3px}",
427
+ "#cm-bubble img{width:84px;height:84px;object-fit:contain;position:absolute;top:-14px;filter:drop-shadow(0 2px 4px rgba(0,0,0,.15))}"
428
+ ].join("\n");
429
+ };
430
+
431
+ WidgetCssBuilder.prototype.buildPanel = function(side, width, height, maxHeightVh, background, borderRadius) {
432
+ return [
433
+ "#cm-panel{position:fixed;" + side + ":24px;bottom:100px;width:" + width + ";max-width:calc(100vw - 32px);height:" + height + ";max-height:" + maxHeightVh + ";background:" + background + ";border-radius:" + borderRadius + ";box-shadow:0 16px 48px rgba(0,0,0,.22),0 4px 16px rgba(0,0,0,.1);display:none;flex-direction:column;overflow:visible;z-index:2147483000;transition:box-shadow .2s,bottom .25s cubic-bezier(.4,0,.2,1)}",
434
+ "#cm-panel.open{display:flex;bottom:24px}",
435
+ "#cm-panel.maximized{width:840px !important;height:calc(100vh - 48px) !important;max-width:calc(100vw - 48px) !important;max-height:none !important}"
436
+ ].join("\n");
437
+ };
438
+
439
+ WidgetCssBuilder.prototype.buildHeader = function(gradient, borderRadius) {
440
+ return [
441
+ "#cm-header{display:flex;align-items:center;justify-content:space-between;padding:10px 12px 10px 80px;background:" + gradient + ";color:#fff;position:relative;border-radius:" + borderRadius + " " + borderRadius + " 0 0;min-height:44px;flex-shrink:0}",
442
+ "#cm-header-mascot{width:83px;height:83px;position:absolute;left:-6px;top:-16px;filter:drop-shadow(0 2px 3px rgba(0,0,0,.12));pointer-events:none}",
443
+ "#cm-title{margin:0;font-size:16px;font-weight:600;letter-spacing:-0.01em}",
444
+ "#cm-header-actions{display:flex;align-items:center;gap:4px}",
445
+ ".cm-header-btn{background:none;border:none;color:#fff;cursor:pointer;padding:6px;border-radius:8px;transition:background .15s;display:flex;align-items:center;justify-content:center;-webkit-user-select:none;user-select:none}",
446
+ ".cm-header-btn:hover{background:rgba(255,255,255,.18)}",
447
+ ".cm-header-btn:active{transform:scale(0.92)}",
448
+ ".cm-header-btn svg{width:22px;height:22px}"
449
+ ].join("\n");
450
+ };
451
+
452
+ WidgetCssBuilder.prototype.buildNotes = function() {
453
+ return [
454
+ "#cm-disclaimer,#cm-transparency{font-size:13px;display:flex;align-items:center;gap:8px;padding:8px 14px;flex-shrink:0}",
455
+ "#cm-disclaimer{background:#e8f4fd;color:#1a5276;border-bottom:1px solid #b3d9f2}",
456
+ "#cm-transparency{color:#555;border-top:1px solid #eee;background:#fff}",
457
+ ".cm-close-note{background:none;border:none;cursor:pointer;border-radius:6px;padding:4px 8px;min-width:32px;min-height:32px;width:32px;opacity:.6;transition:opacity .15s,background .15s;flex-shrink:0;display:flex;align-items:center;justify-content:center;margin-left:auto}",
458
+ ".cm-close-note:hover{opacity:1;background:rgba(0,0,0,.08)}",
459
+ ".cm-close-note svg{width:16px;height:16px}"
460
+ ].join("\n");
461
+ };
462
+
463
+ WidgetCssBuilder.prototype.buildMessages = function() {
464
+ return [
465
+ "#cm-messages{flex:1;overflow-y:auto;padding:16px;display:flex;flex-direction:column;gap:12px;scroll-behavior:smooth;overscroll-behavior:contain}",
466
+ "#cm-messages::-webkit-scrollbar{width:6px}",
467
+ "#cm-messages::-webkit-scrollbar-track{background:transparent}",
468
+ "#cm-messages::-webkit-scrollbar-thumb{background:rgba(0,0,0,.12);border-radius:3px}",
469
+ "#cm-messages::-webkit-scrollbar-thumb:hover{background:rgba(0,0,0,.2)}",
470
+ "#cm-welcome{color:#555;font-size:15px;line-height:1.6;text-align:center;padding:24px 16px}"
471
+ ].join("\n");
472
+ };
473
+
474
+ WidgetCssBuilder.prototype.buildMessageBubbles = function(primaryColor) {
475
+ return [
476
+ ".cm-msg{max-width:88%;padding:12px 16px;border-radius:16px;font-size:15px;line-height:1.55;word-break:break-word;animation:cm-msg-in .25s cubic-bezier(.4,0,.2,1)}",
477
+ "@keyframes cm-msg-in{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}",
478
+ ".cm-msg.assistant{background:#f0f4f8;color:#1a1a2e;border-bottom-left-radius:4px;align-self:flex-start}",
479
+ ".cm-msg.assistant p{margin:0 0 10px}",
480
+ ".cm-msg.assistant p:last-child{margin-bottom:0}",
481
+ ".cm-msg.assistant ul,.cm-msg.assistant ol{margin:0 0 10px 20px;padding:0}",
482
+ ".cm-msg.assistant li{margin:0 0 4px}",
483
+ ".cm-msg.assistant a{color:#0b57d0;text-decoration:underline;word-break:break-all}",
484
+ ".cm-msg.assistant code{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;background:#e2e8f0;padding:2px 6px;border-radius:4px;font-size:13px}",
485
+ ".cm-msg.assistant pre{margin:0 0 10px;padding:10px 12px;background:#1f2937;color:#f9fafb;border-radius:10px;overflow-x:auto;font-size:13px}",
486
+ ".cm-msg.assistant pre code{background:transparent;color:inherit;padding:0;font-size:inherit}",
487
+ ".cm-msg.assistant h3,.cm-msg.assistant h4{margin:0 0 8px;font-size:15px;line-height:1.35;font-weight:600}",
488
+ ".cm-msg.user{background:" + primaryColor + ";color:#fff;border-bottom-right-radius:4px;align-self:flex-end}"
489
+ ].join("\n");
490
+ };
491
+
492
+ WidgetCssBuilder.prototype.buildTypingAndError = function() {
493
+ return [
494
+ "#cm-typing{padding:8px 16px;font-size:13px;color:#666;display:none}",
495
+ "#cm-typing.visible{display:flex;align-items:center;gap:8px}",
496
+ "#cm-typing::before{content:'';display:inline-block;width:6px;height:6px;background:#666;border-radius:50%;animation:cm-dot-pulse 1.2s infinite}",
497
+ "@keyframes cm-dot-pulse{0%,100%{opacity:.3;transform:scale(.8)}50%{opacity:1;transform:scale(1.1)}}",
498
+ "#cm-error{display:none;background:#f8d7da;color:#58151c;font-size:13px;padding:10px 14px}",
499
+ "#cm-error.visible{display:block}"
500
+ ].join("\n");
501
+ };
502
+
503
+ WidgetCssBuilder.prototype.buildComposer = function(primaryColor, borderRadius) {
504
+ return [
505
+ "#cm-form{display:flex;align-items:flex-end;gap:8px;padding:12px 16px;border-top:1px solid #eee;background:#fff;border-radius:0 0 " + borderRadius + " " + borderRadius + ";flex-shrink:0}",
506
+ "#cm-input{flex:1;border:1.5px solid #d1d5db;border-radius:14px;padding:12px 16px;min-height:48px;max-height:200px;resize:none;outline:none;line-height:1.5;font-size:15px;transition:border-color .2s,box-shadow .2s;overflow-y:auto}",
507
+ "#cm-input:focus{border-color:" + primaryColor + ";box-shadow:0 0 0 3px rgba(0,102,255,.15)}",
508
+ "#cm-input::placeholder{color:#9ca3af}",
509
+ "#cm-send,#cm-mic{width:48px;height:48px;border-radius:50%;display:flex;align-items:center;justify-content:center;border:none;cursor:pointer;flex-shrink:0;transition:transform .15s,opacity .15s;font-size:18px;-webkit-user-select:none;user-select:none;-webkit-user-drag:none}",
510
+ "#cm-send{background:" + primaryColor + ";color:#fff}",
511
+ "#cm-send:hover:not(:disabled){transform:scale(1.08)}",
512
+ "#cm-send:active:not(:disabled){transform:scale(0.94)}",
513
+ "#cm-send:disabled,#cm-mic:disabled{opacity:.4;cursor:not-allowed}",
514
+ "#cm-mic{background:#f3f4f6;color:#667085;border:none}",
515
+ "#cm-mic:hover:not(:disabled){background:#e5e7eb}",
516
+ "#cm-mic.listening{background:#ef4444;color:#fff;border-color:#ef4444;animation:cm-mic-pulse 1.5s infinite}",
517
+ "@keyframes cm-mic-pulse{0%,100%{box-shadow:0 0 0 0 rgba(239,68,68,.35)}50%{box-shadow:0 0 0 8px rgba(239,68,68,0)}}"
518
+ ].join("\n");
519
+ };
520
+
521
+ WidgetCssBuilder.prototype.buildMobileOverrides = function() {
522
+ return [
523
+ "@media (max-width:600px){",
524
+ "#cm-bubble{width:56px;height:56px;bottom:16px;right:16px !important;left:auto !important}",
525
+ "#cm-bubble img{width:72px;height:72px;top:-12px}",
526
+ "#cm-panel{left:8px !important;right:8px !important;bottom:8px !important;top:8px !important;width:auto !important;max-width:none !important;height:auto !important;max-height:none !important}",
527
+ "#cm-header{padding:10px 12px 10px 76px}",
528
+ "#cm-header-mascot{width:68px;height:68px;left:-4px;top:-6px}",
529
+ "#cm-title{font-size:16px}",
530
+ ".cm-header-btn-maximize{display:none !important}",
531
+ "#cm-messages{flex:1;padding:12px 16px;gap:12px;overflow-y:auto}",
532
+ ".cm-msg{max-width:92%;padding:12px 14px;font-size:15px;border-radius:16px}",
533
+ "#cm-form{padding:10px 12px;padding-bottom:calc(10px + env(safe-area-inset-bottom,0px));gap:8px}",
534
+ "#cm-input{min-height:44px;font-size:16px;border-radius:14px;padding:10px 14px}",
535
+ "#cm-send,#cm-mic{width:44px;height:44px}",
536
+ "#cm-typing{padding:6px 16px;font-size:13px}",
537
+ "#cm-disclaimer,#cm-transparency{font-size:12px;padding:8px 12px}",
538
+ "#cm-welcome{font-size:15px;padding:24px 16px}",
539
+ "}"
540
+ ].join("\n");
541
+ };
542
+
543
+ ui.WidgetCssBuilder = WidgetCssBuilder;
544
+ }
545
+
546
+ function installWidgetUIManager(ui) {
547
+ function WidgetUIManager(config) {
548
+ this.config = config;
549
+ this.root = null;
550
+ this.bubble = null;
551
+ this.bubbleMascot = null;
552
+ this.panel = null;
553
+ this.headerMascot = null;
554
+ this.messages = null;
555
+ this.input = null;
556
+ this.sendButton = null;
557
+ this.micButton = null;
558
+ this.typing = null;
559
+ this.error = null;
560
+ this.welcome = null;
561
+ this.streamingAssistantElement = null;
562
+ this.streamingAssistantBuffer = "";
563
+ this.themeOverrideStyle = null;
564
+ }
565
+
566
+ WidgetUIManager.prototype.mount = function() {
567
+ if (document.getElementById(ui.CONTAINER_ID)) return false;
568
+ var cssBuilder = new ui.WidgetCssBuilder(this.config);
569
+ var css = cssBuilder.build();
570
+ var esc = ui.escapeHtml;
571
+ var escAttr = ui.escapeHtmlAttribute;
572
+
573
+ var host = document.createElement("div");
574
+ host.id = ui.CONTAINER_ID;
575
+ document.body.appendChild(host);
576
+ var shadow = host.attachShadow({ mode: "open" });
577
+ var root = document.createElement("div");
578
+ root.innerHTML = [
579
+ "<style>" + css + "</style>",
580
+ '<button id="cm-bubble" type="button" aria-label="Ouvrir l\'assistant">',
581
+ '<img id="cm-bubble-mascot" src="' + escAttr(this.config.mascotUrl) + '" alt="Mascotte assistant" />',
582
+ "</button>",
583
+ '<div id="cm-panel" role="dialog" aria-modal="true" aria-label="Chat ' + escAttr(this.config.assistantName) + '">',
584
+ '<div id="cm-header"><img id="cm-header-mascot" src="' + escAttr(this.config.mascotUrl) + '" alt="" /><h3 id="cm-title">' + esc(this.config.assistantName) + '</h3><div id="cm-header-actions"><button class="cm-header-btn cm-header-btn-maximize" id="cm-maximize" type="button" aria-label="Agrandir"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 3h6v6"/><path d="M9 21H3v-6"/><path d="M21 3l-7 7"/><path d="M3 21l7-7"/></svg></button><button class="cm-header-btn" id="cm-close" type="button" aria-label="Fermer l\'assistant"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg></button></div></div>',
585
+ this.config.disclaimer ? '<div id="cm-disclaimer"><span>' + esc(this.config.disclaimerText) + '</span><button class="cm-close-note" id="cm-disclaimer-close" type="button" aria-label="Fermer l\'avertissement"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg></button></div>' : "",
586
+ '<div id="cm-messages" aria-live="polite" aria-relevant="additions"><p id="cm-welcome">' + esc(this.config.welcomeMessage) + "</p></div>",
587
+ '<div id="cm-typing">L\'assistant r\u00e9fl\u00e9chit\u2026</div>',
588
+ '<div id="cm-error"></div>',
589
+ '<div id="cm-transparency"><span>' + esc(this.config.transparencyText) + '</span><button class="cm-close-note" id="cm-transparency-close" type="button" aria-label="Fermer le message de transparence"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg></button></div>',
590
+ '<form id="cm-form"><button id="cm-mic" type="button" aria-label="Dicter un message"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z"/><path d="M19 10v2a7 7 0 0 1-14 0v-2"/><line x1="12" y1="19" x2="12" y2="23"/><line x1="8" y1="23" x2="16" y2="23"/></svg></button><textarea id="cm-input" rows="1" aria-label="Votre message" placeholder="Posez votre question\u2026"></textarea><button id="cm-send" type="submit" aria-label="Envoyer"><svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/></svg></button></form>',
591
+ "</div>"
592
+ ].join("");
593
+ shadow.appendChild(root);
594
+ this.host = host;
595
+ this.root = root;
596
+ this.bubble = root.querySelector("#cm-bubble");
597
+ this.bubbleMascot = root.querySelector("#cm-bubble-mascot");
598
+ this.panel = root.querySelector("#cm-panel");
599
+ this.headerMascot = root.querySelector("#cm-header-mascot");
600
+ this.messages = root.querySelector("#cm-messages");
601
+ this.input = root.querySelector("#cm-input");
602
+ this.sendButton = root.querySelector("#cm-send");
603
+ this.micButton = root.querySelector("#cm-mic");
604
+ this.typing = root.querySelector("#cm-typing");
605
+ this.error = root.querySelector("#cm-error");
606
+ this.welcome = root.querySelector("#cm-welcome");
607
+ this.themeOverrideStyle = document.createElement("style");
608
+ this.themeOverrideStyle.id = "cm-theme-overrides";
609
+ root.appendChild(this.themeOverrideStyle);
610
+ this.bindMascotImageErrorHandlers();
611
+ this.bindAutoGrowInput();
612
+ this.applyThemeOverrides();
613
+ this.applyMascotTheme();
614
+ return true;
615
+ };
616
+
617
+ WidgetUIManager.prototype.bindAutoGrowInput = function() {
618
+ var inputEl = this.input;
619
+ if (!inputEl) return;
620
+ function adjustHeight() {
621
+ inputEl.style.height = "auto";
622
+ var scrollH = inputEl.scrollHeight;
623
+ var maxH = 200;
624
+ inputEl.style.height = Math.min(scrollH, maxH) + "px";
625
+ inputEl.style.overflowY = scrollH > maxH ? "auto" : "hidden";
626
+ }
627
+ inputEl.addEventListener("input", adjustHeight);
628
+ inputEl.style.overflowY = "hidden";
629
+ };
630
+
631
+ WidgetUIManager.prototype.bindMascotImageErrorHandlers = function() {
632
+ var self = this;
633
+ [this.bubbleMascot, this.headerMascot].forEach(function(mascotNode) {
634
+ if (!mascotNode) return;
635
+ mascotNode.addEventListener("error", function() {
636
+ var failedUrl = mascotNode.getAttribute("src") || "";
637
+ var errorMessage = failedUrl ? "chargement échoué pour " + failedUrl : "chargement échoué";
638
+ console.error("[OurluMairie] mascot image error:", errorMessage);
639
+ self.showMascotLoadError(errorMessage);
640
+ });
641
+ });
642
+ };
643
+
644
+ WidgetUIManager.prototype.showMascotLoadError = function(message) {
645
+ var resolvedMessage = String(message || "Mascotte indisponible.").trim() || "Mascotte indisponible.";
646
+ this.showError("Mascotte indisponible: " + resolvedMessage);
647
+ if (this.bubbleMascot) {
648
+ this.bubbleMascot.style.display = "none";
649
+ this.bubbleMascot.alt = resolvedMessage;
650
+ }
651
+ if (this.headerMascot) {
652
+ this.headerMascot.style.display = "none";
653
+ }
654
+ };
655
+
656
+ WidgetUIManager.prototype.bind = function(callbacks) {
657
+ this.bubble.addEventListener("click", callbacks.onToggle);
658
+ this.root.querySelector("#cm-close").addEventListener("click", callbacks.onToggle);
659
+ this.root.querySelector("#cm-form").addEventListener("submit", callbacks.onSend);
660
+ this.micButton.addEventListener("click", callbacks.onMicToggle);
661
+ document.addEventListener("keydown", callbacks.onEscape);
662
+ var disclaimerClose = this.root.querySelector("#cm-disclaimer-close");
663
+ var transparencyClose = this.root.querySelector("#cm-transparency-close");
664
+ var rootRef = this.root;
665
+ if (disclaimerClose) disclaimerClose.addEventListener("click", function() { var p = rootRef.querySelector("#cm-disclaimer"); if (p) p.style.display = "none"; });
666
+ if (transparencyClose) transparencyClose.addEventListener("click", function() { var p = rootRef.querySelector("#cm-transparency"); if (p) p.style.display = "none"; });
667
+ var maximizeBtn = this.root.querySelector("#cm-maximize");
668
+ var panelRef = this.panel;
669
+ if (maximizeBtn && panelRef) maximizeBtn.addEventListener("click", function() { panelRef.classList.toggle("maximized"); });
670
+ };
671
+
672
+ WidgetUIManager.prototype.setMascotSource = function(sourceUrl) {
673
+ var normalizedSourceUrl = String(sourceUrl || "").trim();
674
+ if (!normalizedSourceUrl) return;
675
+ if (this.bubbleMascot) {
676
+ this.bubbleMascot.src = normalizedSourceUrl;
677
+ this.bubbleMascot.style.display = "block";
678
+ }
679
+ if (this.headerMascot) {
680
+ this.headerMascot.src = normalizedSourceUrl;
681
+ this.headerMascot.style.display = "block";
682
+ }
683
+ };
684
+
685
+ WidgetUIManager.prototype.applyMascotTheme = function() {
686
+ var self = this;
687
+ ui.resolveMascotUrlWithTheme(this.config.mascotUrl, this.config).then(function(themedMascotUrl) {
688
+ self.setMascotSource(themedMascotUrl);
689
+ }).catch(function(error) {
690
+ var message = (error && error.message) ? error.message : "Mascotte indisponible.";
691
+ console.error("[OurluMairie]", message, error);
692
+ self.showMascotLoadError(message);
693
+ });
694
+ };
695
+
696
+ WidgetUIManager.prototype.applyThemeOverrides = function() {
697
+ if (!this.root || !this.themeOverrideStyle) return;
698
+ var isDarkTheme = String(this.config.effectiveThemeScheme || "light").toLowerCase() === "dark";
699
+ var primaryColor = ui.normalizeHexColor(this.config.primaryColor, "#0066ff");
700
+ var panelBackgroundBaseColor = isDarkTheme ? "#111827" : this.config.panelBackgroundColor;
701
+ var panelBackgroundAlpha = isDarkTheme ? "0.96" : this.config.panelBackgroundAlpha;
702
+ var panelBackground = ui.hexToRgba(panelBackgroundBaseColor, panelBackgroundAlpha);
703
+ var borderRadius = Number(this.config.panelBorderRadius);
704
+ if (!Number.isFinite(borderRadius)) borderRadius = 16;
705
+ borderRadius = Math.max(0, Math.min(32, Math.round(borderRadius)));
706
+ var borderRadiusPx = borderRadius + "px";
707
+ var gradient = "linear-gradient(135deg," + primaryColor + " 0%,#0047b3 100%)";
708
+ var darkThemeRules = isDarkTheme ? [
709
+ "#cm-panel{color:#f3f4f6 !important}",
710
+ "#cm-messages{background:rgba(2,6,23,0.28) !important}",
711
+ ".cm-msg.assistant{background:rgba(30,41,59,0.94) !important;color:#f8fafc !important}",
712
+ ".cm-msg.assistant code{background:#334155 !important;color:#f8fafc !important}",
713
+ "#cm-form{background:#0f172a !important;border-top:1px solid #1f2937 !important}",
714
+ "#cm-input{background:#111827 !important;color:#f8fafc !important;border-color:#334155 !important}",
715
+ "#cm-input::placeholder{color:#94a3b8 !important}",
716
+ "#cm-error{background:#7f1d1d !important;color:#fee2e2 !important}",
717
+ "#cm-resize-handle{color:#94a3b8 !important}"
718
+ ] : [
719
+ "#cm-messages{background:transparent !important}",
720
+ ".cm-msg.assistant{background:#f0f4f8 !important;color:#1a1a2e !important}",
721
+ "#cm-form{background:#ffffff !important;border-top:1px solid #eee !important}",
722
+ "#cm-input{background:#ffffff !important;color:#0f172a !important;border-color:#d1d5db !important}",
723
+ "#cm-error{background:#f8d7da !important;color:#58151c !important}"
724
+ ];
725
+ this.themeOverrideStyle.textContent = [
726
+ "#cm-bubble{background:" + gradient + " !important}",
727
+ "#cm-bubble:focus-visible{outline-color:" + primaryColor + " !important}",
728
+ "#cm-panel{background:" + panelBackground + " !important;border-radius:" + borderRadiusPx + " !important}",
729
+ "#cm-header{background:" + gradient + " !important;border-radius:" + borderRadiusPx + " " + borderRadiusPx + " 0 0 !important}",
730
+ "#cm-form{border-radius:0 0 " + borderRadiusPx + " " + borderRadiusPx + " !important}",
731
+ "#cm-send{background:" + primaryColor + " !important}",
732
+ ".cm-msg.user{background:" + primaryColor + " !important}",
733
+ "#cm-input:focus{border-color:" + primaryColor + " !important;box-shadow:0 0 0 3px rgba(0,102,255,.15) !important}"
734
+ ].concat(darkThemeRules).join("\n");
735
+ };
736
+
737
+ WidgetUIManager.prototype.updateTheme = function(updatedConfig) {
738
+ this.config = Object.assign({}, this.config, updatedConfig || {});
739
+ if (this.root) {
740
+ var titleNode = this.root.querySelector("#cm-title");
741
+ if (titleNode) {
742
+ titleNode.textContent = this.config.assistantName || "Assistant mairie";
743
+ }
744
+ if (this.panel) {
745
+ this.panel.setAttribute("aria-label", "Chat " + (this.config.assistantName || "Assistant mairie"));
746
+ }
747
+ var userMessages = this.root.querySelectorAll(".cm-msg.user");
748
+ var userBubbleColor = ui.normalizeHexColor(this.config.primaryColor, "#0066ff");
749
+ userMessages.forEach(function(node) {
750
+ node.style.background = userBubbleColor;
751
+ });
752
+ if (this.welcome && this.config.welcomeMessage) {
753
+ this.welcome.textContent = this.config.welcomeMessage;
754
+ }
755
+ var disclaimerSpan = this.root.querySelector("#cm-disclaimer > span");
756
+ if (disclaimerSpan && this.config.disclaimerText) {
757
+ disclaimerSpan.textContent = this.config.disclaimerText;
758
+ }
759
+ var headerMascot = this.root.querySelector("#cm-header-mascot");
760
+ if (headerMascot && this.config.mascotUrl) {
761
+ headerMascot.setAttribute("src", this.config.mascotUrl);
762
+ headerMascot.style.display = "";
763
+ }
764
+ }
765
+ this.applyThemeOverrides();
766
+ this.applyMascotTheme();
767
+ };
768
+
769
+ WidgetUIManager.prototype.setOpen = function(opened) {
770
+ this.panel.classList.toggle("open", opened);
771
+ this.bubble.style.display = opened ? "none" : "flex";
772
+ if (opened && !("ontouchstart" in window)) this.input.focus();
773
+ };
774
+
775
+ WidgetUIManager.prototype.pullInput = function() {
776
+ var value = this.input.value.trim();
777
+ this.input.value = "";
778
+ this.input.style.height = "auto";
779
+ return value;
780
+ };
781
+
782
+ WidgetUIManager.prototype.setInput = function(value) { this.input.value = String(value || ""); };
783
+ WidgetUIManager.prototype.inputValue = function() { return this.input.value; };
784
+ WidgetUIManager.prototype.showTyping = function(visible) { this.typing.classList.toggle("visible", Boolean(visible)); };
785
+
786
+ WidgetUIManager.prototype.setComposerDisabled = function(disabled) {
787
+ this.input.disabled = disabled;
788
+ this.sendButton.disabled = disabled;
789
+ this.micButton.disabled = disabled;
790
+ };
791
+
792
+ WidgetUIManager.prototype.showError = function(message) {
793
+ this.error.textContent = message;
794
+ this.error.classList.toggle("visible", Boolean(message));
795
+ this._retryHandler = null;
796
+ };
797
+
798
+ WidgetUIManager.prototype.showRetryableError = function(message, onRetry) {
799
+ this.error.innerHTML = "";
800
+ var textNode = document.createTextNode(message + " ");
801
+ this.error.appendChild(textNode);
802
+ var retryButton = document.createElement("button");
803
+ retryButton.textContent = "Réessayer";
804
+ retryButton.style.cssText = "background:none;border:1px solid #58151c;border-radius:6px;color:#58151c;cursor:pointer;padding:4px 12px;font-size:13px;margin-left:8px;";
805
+ var self = this;
806
+ retryButton.addEventListener("click", function() {
807
+ self.showError("");
808
+ if (typeof onRetry === "function") onRetry();
809
+ });
810
+ this.error.appendChild(retryButton);
811
+ this.error.classList.add("visible");
812
+ this._retryHandler = onRetry;
813
+ };
814
+
815
+ WidgetUIManager.prototype.setAssistantDraftText = function(node, text) {
816
+ if (!node) return;
817
+ node.textContent = String(text || "");
818
+ };
819
+
820
+ WidgetUIManager.prototype.setAssistantFinalText = function(node, text) {
821
+ if (!node) return;
822
+ node.innerHTML = ui.renderAssistantMarkdown(String(text || ""));
823
+ };
824
+
825
+ WidgetUIManager.prototype.addMessage = function(role, text) {
826
+ if (this.welcome) { this.welcome.remove(); this.welcome = null; }
827
+ var node = document.createElement("div");
828
+ node.className = "cm-msg " + role;
829
+ if (role === "assistant") {
830
+ this.setAssistantDraftText(node, text);
831
+ } else {
832
+ node.textContent = text;
833
+ }
834
+ this.messages.appendChild(node);
835
+ this.messages.scrollTop = this.messages.scrollHeight;
836
+ return node;
837
+ };
838
+
839
+ WidgetUIManager.prototype.startAssistantStream = function() {
840
+ this.streamingAssistantElement = this.addMessage("assistant", "");
841
+ this.streamingAssistantBuffer = "";
842
+ };
843
+
844
+ WidgetUIManager.prototype.appendAssistantToken = function(token) {
845
+ if (!this.streamingAssistantElement) this.startAssistantStream();
846
+ var resolvedToken = String(token || "");
847
+ if (!resolvedToken) return;
848
+ this.streamingAssistantBuffer += resolvedToken;
849
+ this.streamingAssistantElement.textContent += resolvedToken;
850
+ this.messages.scrollTop = this.messages.scrollHeight;
851
+ };
852
+
853
+ WidgetUIManager.prototype.finalizeAssistantMessage = function(content) {
854
+ if (!this.streamingAssistantElement) this.startAssistantStream();
855
+ var resolvedContent = content || this.streamingAssistantBuffer || this.streamingAssistantElement.textContent || "";
856
+ this.setAssistantFinalText(this.streamingAssistantElement, resolvedContent);
857
+ this.streamingAssistantElement = null;
858
+ this.streamingAssistantBuffer = "";
859
+ };
860
+
861
+ WidgetUIManager.prototype.setMicListening = function(isListening) {
862
+ this.micButton.classList.toggle("listening", isListening);
863
+ this.micButton.textContent = isListening ? "\u23f9" : "\ud83c\udfa4";
864
+ this.micButton.setAttribute("aria-label", isListening ? "Arrêter la dictée vocale" : "Dicter un message");
865
+ this.input.placeholder = isListening ? "Transcription en cours\u2026" : "Posez votre question\u2026";
866
+ };
867
+
868
+ ui.WidgetUIManager = WidgetUIManager;
869
+ }
870
+
871
+ "use strict";
872
+ var runtime = window.__OurluWidgetRuntimeV1 || (window.__OurluWidgetRuntimeV1 = {});
873
+ var ui = {};
874
+
875
+ ui.CONTAINER_ID = "ourlu-widget-root";
876
+
877
+ installColorUtils(ui);
878
+ installMascotTheme(ui);
879
+ installMarkdownRender(ui);
880
+ installMediaUtils(ui);
881
+ installEventBus(ui);
882
+ installWidgetCssBuilder(ui);
883
+ installWidgetUIManager(ui);
884
+
885
+ runtime.constants = { CONTAINER_ID: ui.CONTAINER_ID };
886
+ runtime.EventBus = ui.EventBus;
887
+ runtime.WidgetUIManager = ui.WidgetUIManager;
888
+ runtime.utils = {
889
+ trimTrailingSlash: ui.trimTrailingSlash,
890
+ mergeTranscript: ui.mergeTranscript,
891
+ resolveRecorderMimeType: ui.resolveRecorderMimeType,
892
+ encodeArrayBufferToBase64: ui.encodeArrayBufferToBase64,
893
+ resolveAbsoluteMascotUrl: ui.resolveAbsoluteMascotUrl
894
+ };
895
+ })();