@ourlu/assistant-sdk 0.2.5 → 0.2.6

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.
@@ -384,10 +384,25 @@ function installWidgetCssBuilder(ui) {
384
384
  };
385
385
  };
386
386
 
387
+ WidgetCssBuilder.prototype.darkenHex = function(hex, percent) {
388
+ var h = String(hex || "#000000").replace("#", "");
389
+ if (h.length !== 6) h = "000000";
390
+ var r = Math.max(0, Math.round(parseInt(h.slice(0, 2), 16) * (1 - percent / 100)));
391
+ var g = Math.max(0, Math.round(parseInt(h.slice(2, 4), 16) * (1 - percent / 100)));
392
+ var b = Math.max(0, Math.round(parseInt(h.slice(4, 6), 16) * (1 - percent / 100)));
393
+ return "#" + ("0" + r.toString(16)).slice(-2) + ("0" + g.toString(16)).slice(-2) + ("0" + b.toString(16)).slice(-2);
394
+ };
395
+
396
+ WidgetCssBuilder.prototype.resolveBackground = function(baseColor, gradientEnabled, autoMode, manualColor2, darkenPct) {
397
+ if (!gradientEnabled) return baseColor;
398
+ var color2 = autoMode ? this.darkenHex(baseColor, darkenPct) : (manualColor2 || this.darkenHex(baseColor, darkenPct));
399
+ return "linear-gradient(135deg," + baseColor + " 0%," + color2 + " 100%)";
400
+ };
401
+
387
402
  WidgetCssBuilder.prototype.build = function() {
388
403
  var cfg = this.config;
389
404
  var side = cfg.position === "bottom-left" ? "left" : "right";
390
- var gradient = "linear-gradient(135deg," + cfg.primaryColor + " 0%,#0047b3 100%)";
405
+ var headerBg = this.resolveBackground(cfg.primaryColor, cfg.headerGradientEnabled !== false, cfg.headerGradientColor2Auto !== false, cfg.headerGradientColor2, 25);
391
406
  var panelBg = ui.hexToRgba(cfg.panelBackgroundColor, cfg.panelBackgroundAlpha);
392
407
  var layout = this.resolveLayout();
393
408
  var pw = layout.panelWidth + "px";
@@ -395,14 +410,20 @@ function installWidgetCssBuilder(ui) {
395
410
  var mhVh = layout.panelMaxHeightVh + "vh";
396
411
  var br = layout.borderRadius + "px";
397
412
 
413
+ var userBubbleBase = cfg.userBubbleColor || cfg.primaryColor;
414
+ var userBubbleBg = this.resolveBackground(userBubbleBase, cfg.userBubbleGradientEnabled === true, cfg.userBubbleGradientColor2Auto !== false, cfg.userBubbleGradientColor2, 25);
415
+ var assistantBubbleBase = cfg.assistantBubbleColor || "#f0f4f8";
416
+ var assistantBubbleBg = this.resolveBackground(assistantBubbleBase, cfg.assistantBubbleGradientEnabled === true, cfg.assistantBubbleGradientColor2Auto !== false, cfg.assistantBubbleGradientColor2, 15);
417
+ var assistantBubbleTextColor = cfg.assistantBubbleTextColor || "#1a1a2e";
418
+
398
419
  return [
399
420
  this.buildResetAndBase(),
400
- this.buildBubble(side, gradient, cfg.primaryColor),
421
+ this.buildBubble(side, headerBg, cfg.primaryColor),
401
422
  this.buildPanel(side, pw, ph, mhVh, panelBg, br),
402
- this.buildHeader(gradient, br),
423
+ this.buildHeader(headerBg, br),
403
424
  this.buildNotes(),
404
425
  this.buildMessages(),
405
- this.buildMessageBubbles(cfg.primaryColor),
426
+ this.buildMessageBubbles(userBubbleBg, assistantBubbleBg, assistantBubbleTextColor),
406
427
  this.buildTypingAndError(),
407
428
  this.buildComposer(cfg.primaryColor, br),
408
429
  this.buildMobileOverrides()
@@ -471,11 +492,11 @@ function installWidgetCssBuilder(ui) {
471
492
  ].join("\n");
472
493
  };
473
494
 
474
- WidgetCssBuilder.prototype.buildMessageBubbles = function(primaryColor) {
495
+ WidgetCssBuilder.prototype.buildMessageBubbles = function(userBubbleBg, assistantBubbleBg, assistantTextColor) {
475
496
  return [
476
497
  ".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
498
  "@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}",
499
+ ".cm-msg.assistant{background:" + assistantBubbleBg + ";color:" + assistantTextColor + ";border-bottom-left-radius:4px;align-self:flex-start}",
479
500
  ".cm-msg.assistant p{margin:0 0 10px}",
480
501
  ".cm-msg.assistant p:last-child{margin-bottom:0}",
481
502
  ".cm-msg.assistant ul,.cm-msg.assistant ol{margin:0 0 10px 20px;padding:0}",
@@ -485,7 +506,7 @@ function installWidgetCssBuilder(ui) {
485
506
  ".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
507
  ".cm-msg.assistant pre code{background:transparent;color:inherit;padding:0;font-size:inherit}",
487
508
  ".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}"
509
+ ".cm-msg.user{background:" + userBubbleBg + ";color:#fff;border-bottom-right-radius:4px;align-self:flex-end}"
489
510
  ].join("\n");
490
511
  };
491
512
 
@@ -502,11 +523,14 @@ function installWidgetCssBuilder(ui) {
502
523
 
503
524
  WidgetCssBuilder.prototype.buildComposer = function(primaryColor, borderRadius) {
504
525
  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}",
526
+ "#cm-form{display:flex;flex-wrap:wrap;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}",
527
+ "#cm-form.cm-multiline #cm-input{order:-1;flex-basis:100%;width:100%}",
528
+ "#cm-form.cm-multiline #cm-mic{margin-right:auto}",
506
529
  "#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
530
  "#cm-input:focus{border-color:" + primaryColor + ";box-shadow:0 0 0 3px rgba(0,102,255,.15)}",
508
531
  "#cm-input::placeholder{color:#9ca3af}",
509
532
  "#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}",
533
+ "#cm-send svg,#cm-mic svg{width:24px !important;height:24px !important;min-width:24px !important;min-height:24px !important;display:block !important}",
510
534
  "#cm-send{background:" + primaryColor + ";color:#fff}",
511
535
  "#cm-send:hover:not(:disabled){transform:scale(1.08)}",
512
536
  "#cm-send:active:not(:disabled){transform:scale(0.94)}",
@@ -523,16 +547,17 @@ function installWidgetCssBuilder(ui) {
523
547
  "@media (max-width:600px){",
524
548
  "#cm-bubble{width:56px;height:56px;bottom:16px;right:16px !important;left:auto !important}",
525
549
  "#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}",
550
+ "#cm-panel{position:fixed !important;left:0 !important;right:0 !important;bottom:8px;top:16px;width:100% !important;max-width:none !important;height:auto;max-height:none !important;border-radius:12px !important;overflow:visible !important;transition:height .15s ease,top .15s ease}",
551
+ "#cm-header{padding:10px 12px 10px 76px;border-radius:12px 12px 0 0 !important;min-height:48px}",
552
+ "#cm-header-mascot{width:68px;height:68px;left:-4px;top:-12px}",
529
553
  "#cm-title{font-size:16px}",
530
554
  ".cm-header-btn-maximize{display:none !important}",
531
- "#cm-messages{flex:1;padding:12px 16px;gap:12px;overflow-y:auto}",
555
+ "#cm-messages{flex:1;min-height:0;padding:12px 16px;gap:12px;overflow-y:auto}",
532
556
  ".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}",
557
+ "#cm-form{padding:10px 12px;padding-bottom:calc(10px + env(safe-area-inset-bottom,0px));gap:8px;flex-shrink:0;border-radius:0 0 12px 12px !important}",
534
558
  "#cm-input{min-height:44px;font-size:16px;border-radius:14px;padding:10px 14px}",
535
559
  "#cm-send,#cm-mic{width:44px;height:44px}",
560
+ "#cm-send svg,#cm-mic svg{width:24px !important;height:24px !important;min-width:24px !important;min-height:24px !important;display:block !important}",
536
561
  "#cm-typing{padding:6px 16px;font-size:13px}",
537
562
  "#cm-disclaimer,#cm-transparency{font-size:12px;padding:8px 12px}",
538
563
  "#cm-welcome{font-size:15px;padding:24px 16px}",
@@ -609,20 +634,54 @@ function installWidgetUIManager(ui) {
609
634
  root.appendChild(this.themeOverrideStyle);
610
635
  this.bindMascotImageErrorHandlers();
611
636
  this.bindAutoGrowInput();
637
+ this.bindMobileViewportResize();
612
638
  this.applyThemeOverrides();
613
639
  this.applyMascotTheme();
614
640
  return true;
615
641
  };
616
642
 
643
+ WidgetUIManager.prototype.bindMobileViewportResize = function() {
644
+ var panelRef = this.panel;
645
+ if (!panelRef) return;
646
+ var mobileQuery = window.matchMedia("(max-width:600px)");
647
+ if (!window.visualViewport) return;
648
+ var rafId = 0;
649
+ function onViewportResize() {
650
+ if (!mobileQuery.matches) return;
651
+ if (rafId) return;
652
+ rafId = requestAnimationFrame(function() {
653
+ rafId = 0;
654
+ var vv = window.visualViewport;
655
+ if (!vv) return;
656
+ var topMargin = 16;
657
+ var bottomMargin = 8;
658
+ var adjustedTop = Math.round(vv.offsetTop) + topMargin;
659
+ var adjustedHeight = Math.round(vv.height) - topMargin - bottomMargin;
660
+ panelRef.style.height = Math.max(200, adjustedHeight) + "px";
661
+ panelRef.style.top = adjustedTop + "px";
662
+ });
663
+ }
664
+ window.visualViewport.addEventListener("resize", onViewportResize);
665
+ window.visualViewport.addEventListener("scroll", onViewportResize);
666
+ this._mobileQuery = mobileQuery;
667
+ };
668
+
617
669
  WidgetUIManager.prototype.bindAutoGrowInput = function() {
618
670
  var inputEl = this.input;
671
+ var formEl = this.root ? this.root.querySelector("#cm-form") : null;
619
672
  if (!inputEl) return;
673
+ var singleLineHeight = 0;
620
674
  function adjustHeight() {
621
675
  inputEl.style.height = "auto";
622
676
  var scrollH = inputEl.scrollHeight;
623
677
  var maxH = 200;
624
678
  inputEl.style.height = Math.min(scrollH, maxH) + "px";
625
679
  inputEl.style.overflowY = scrollH > maxH ? "auto" : "hidden";
680
+ if (formEl) {
681
+ if (!singleLineHeight && scrollH > 0) singleLineHeight = scrollH;
682
+ var isMultiline = singleLineHeight > 0 && scrollH > singleLineHeight + 4;
683
+ formEl.classList.toggle("cm-multiline", isMultiline);
684
+ }
626
685
  }
627
686
  inputEl.addEventListener("input", adjustHeight);
628
687
  inputEl.style.overflowY = "hidden";
@@ -770,6 +829,28 @@ function installWidgetUIManager(ui) {
770
829
  this.panel.classList.toggle("open", opened);
771
830
  this.bubble.style.display = opened ? "none" : "flex";
772
831
  if (opened && !("ontouchstart" in window)) this.input.focus();
832
+ this.lockBodyScroll(opened);
833
+ };
834
+
835
+ WidgetUIManager.prototype.lockBodyScroll = function(lock) {
836
+ if (!this._mobileQuery || !this._mobileQuery.matches) return;
837
+ if (lock) {
838
+ this._savedBodyOverflow = document.body.style.overflow;
839
+ this._savedBodyPosition = document.body.style.position;
840
+ this._savedBodyTop = document.body.style.top;
841
+ this._savedBodyWidth = document.body.style.width;
842
+ this._scrollY = window.scrollY;
843
+ document.body.style.overflow = "hidden";
844
+ document.body.style.position = "fixed";
845
+ document.body.style.top = "-" + this._scrollY + "px";
846
+ document.body.style.width = "100%";
847
+ } else {
848
+ document.body.style.overflow = this._savedBodyOverflow || "";
849
+ document.body.style.position = this._savedBodyPosition || "";
850
+ document.body.style.top = this._savedBodyTop || "";
851
+ document.body.style.width = this._savedBodyWidth || "";
852
+ window.scrollTo(0, this._scrollY || 0);
853
+ }
773
854
  };
774
855
 
775
856
  WidgetUIManager.prototype.pullInput = function() {
@@ -896,6 +977,17 @@ function installWidgetUIManager(ui) {
896
977
  return btn;
897
978
  };
898
979
 
980
+ WidgetUIManager.prototype.injectPluButton = function(messageNode, onOpen) {
981
+ if (!messageNode) return null;
982
+ var btn = document.createElement("button");
983
+ btn.className = "cm-plu-open-btn";
984
+ btn.type = "button";
985
+ btn.innerHTML = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M3 9l9-7 9 7v11a2 2 0 01-2 2H5a2 2 0 01-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>Urbanisme';
986
+ btn.addEventListener("click", function() { if (typeof onOpen === "function") onOpen(); });
987
+ messageNode.appendChild(btn);
988
+ return btn;
989
+ };
990
+
899
991
  ui.WidgetUIManager = WidgetUIManager;
900
992
  }
901
993
 
@@ -1,6 +1,7 @@
1
1
  {
2
- "ui.v1.js": "ui.v1.e007c7c4.js",
2
+ "ui.v1.js": "ui.v1.0caedc90.js",
3
3
  "audio.v1.js": "audio.v1.20858b08.js",
4
4
  "signalement.v1.js": "signalement.v1.d321dfde.js",
5
- "engine.v1.js": "engine.v1.c127656e.js"
5
+ "plu.v1.js": "plu.v1.cc853a2d.js",
6
+ "engine.v1.js": "engine.v1.19c589a2.js"
6
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ourlu/assistant-sdk",
3
- "version": "0.2.5",
3
+ "version": "0.2.6",
4
4
  "description": "SDK JavaScript pour l'assistant conversationnel Ourlu — widget intégrable pour les mairies.",
5
5
  "type": "module",
6
6
  "private": false,
@@ -11,6 +11,7 @@
11
11
  "./ui.v1.js": "./dist/iife/ui.v1.js",
12
12
  "./audio.v1.js": "./dist/iife/audio.v1.js",
13
13
  "./signalement.v1.js": "./dist/iife/signalement.v1.js",
14
+ "./plu.v1.js": "./dist/iife/plu.v1.js",
14
15
  "./engine.v1.js": "./dist/iife/engine.v1.js"
15
16
  },
16
17
  "files": [