@ihoomanai/chat-widget 3.0.9 → 3.0.11

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/src/widget.ts CHANGED
@@ -17,7 +17,7 @@ import type {
17
17
  WidgetView,
18
18
  } from './types';
19
19
 
20
- const VERSION = '3.0.9';
20
+ const VERSION = '3.0.11';
21
21
  const STORAGE_PREFIX = 'ihooman_chat_';
22
22
  const DEFAULT_SERVER_URL = 'https://api.ihooman.ai';
23
23
 
@@ -231,9 +231,21 @@ function generateStyles(): string {
231
231
  const positionBottom = config.position?.includes('bottom') ?? true;
232
232
 
233
233
  return `
234
- .ihooman-widget * { box-sizing: border-box !important; margin: 0; padding: 0; }
234
+ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
235
+ :host { all: initial; }
235
236
  .ihooman-widget { font-family: ${fontFamily}; font-size: 14px; line-height: 1.5; color: ${textColor}; -webkit-font-smoothing: antialiased; }
236
- .ihooman-widget button { box-sizing: border-box !important; cursor: pointer !important; font-family: inherit !important; appearance: none !important; -webkit-appearance: none !important; outline: none !important; }
237
+ button {
238
+ font-family: inherit;
239
+ font-size: 100%;
240
+ line-height: inherit;
241
+ color: inherit;
242
+ margin: 0;
243
+ padding: 0;
244
+ background: transparent;
245
+ border: none;
246
+ cursor: pointer;
247
+ outline: none;
248
+ }
237
249
  .ihooman-toggle { position: fixed !important; ${positionRight ? 'right: 20px' : 'left: 20px'}; ${positionBottom ? 'bottom: 20px' : 'top: 20px'}; width: ${buttonSize}px !important; height: ${buttonSize}px !important; border-radius: 50% !important; background: linear-gradient(135deg, ${gradientFrom}, ${gradientTo}) !important; border: none !important; cursor: pointer; z-index: ${zIndex}; display: flex !important; align-items: center; justify-content: center; box-shadow: 0 4px 20px rgba(0, 174, 255, 0.35); transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); overflow: hidden; }
238
250
  .ihooman-toggle:hover { transform: scale(1.08); box-shadow: 0 6px 28px rgba(0, 174, 255, 0.45); }
239
251
  .ihooman-toggle:active { transform: scale(0.95); }
@@ -300,8 +312,7 @@ function generateStyles(): string {
300
312
  .ihooman-powered { text-align: center; padding: 8px; font-size: 11px; color: ${mutedColor}; background: ${bgColor}; }
301
313
  .ihooman-powered a { color: ${primaryColor}; text-decoration: none; }
302
314
  .ihooman-escalation-actions { display: flex; gap: 8px; margin-top: 10px; flex-wrap: wrap; }
303
- .ihooman-widget .ihooman-escalation-btn { cursor: pointer !important; font-family: inherit !important; transition: all 0.2s ease !important; }
304
- .ihooman-widget .ihooman-escalation-btn svg { width: 14px !important; height: 14px !important; flex-shrink: 0 !important; }
315
+ .ihooman-escalation-btn svg { width: 14px; height: 14px; flex-shrink: 0; }
305
316
  .ihooman-status-bar { padding: 10px 16px; text-align: center; font-size: 13px; display: none; }
306
317
  .ihooman-status-bar.show { display: block; }
307
318
  .ihooman-status-bar.waiting { background: #fef3c7; color: #92400e; }
@@ -337,8 +348,7 @@ function generateStyles(): string {
337
348
  .ihooman-history-empty { padding: 40px; text-align: center; color: ${mutedColor}; font-size: 14px; }
338
349
  .ihooman-preset-questions { padding: 10px 16px; display: flex; flex-wrap: wrap; gap: 6px; background: ${bgColor}; border-top: 1px solid ${borderColor}; }
339
350
  .ihooman-preset-questions:empty { display: none; }
340
- .ihooman-preset-questions.hidden { display: none !important; }
341
- .ihooman-widget .ihooman-preset-btn { cursor: pointer !important; font-family: inherit !important; transition: all 0.2s !important; }
351
+ .ihooman-preset-questions.hidden { display: none; }
342
352
  .ihooman-proactive-toast { position: fixed; ${positionRight ? 'right: 20px' : 'left: 20px'}; ${positionBottom ? 'bottom: 90px' : 'top: 90px'}; max-width: 300px; padding: 16px; background: ${bgColor}; border-radius: 12px; box-shadow: 0 10px 40px rgba(0,0,0,0.15); z-index: ${(zIndex ?? 9999) - 2}; opacity: 0; visibility: hidden; transform: translateY(10px); transition: all 0.3s ease; border: 1px solid ${borderColor}; }
343
353
  .ihooman-proactive-toast.show { opacity: 1; visibility: visible; transform: translateY(0); }
344
354
  .ihooman-proactive-toast-content { font-size: 14px; color: ${textColor}; margin-bottom: 12px; }
@@ -361,8 +371,7 @@ function generateStyles(): string {
361
371
  .ihooman-survey-skip { display: inline-flex; align-items: center; justify-content: center; padding: 8px 16px; background: transparent; color: ${mutedColor}; border: none; font-size: 12px; cursor: pointer; line-height: 1.4; }
362
372
  .ihooman-survey-skip:hover { color: ${textColor}; }
363
373
  .ihooman-feedback-btns { display: flex; gap: 6px; margin-top: 6px; }
364
- .ihooman-widget .ihooman-feedback-btn { cursor: pointer !important; transition: all 0.2s !important; }
365
- .ihooman-widget .ihooman-feedback-btn svg { width: 12px !important; height: 12px !important; }
374
+ .ihooman-feedback-btn svg { width: 12px; height: 12px; }
366
375
  .ihooman-carousel { display: flex; gap: 12px; overflow-x: auto; padding: 8px 0; scroll-snap-type: x mandatory; }
367
376
  .ihooman-carousel::-webkit-scrollbar { height: 4px; }
368
377
  .ihooman-carousel-card { min-width: 200px; max-width: 250px; border: 1px solid ${borderColor}; border-radius: 12px; overflow: hidden; scroll-snap-align: start; background: ${bgColor}; }
@@ -371,9 +380,7 @@ function generateStyles(): string {
371
380
  .ihooman-carousel-card-title { font-size: 14px; font-weight: 600; color: ${textColor}; margin-bottom: 4px; }
372
381
  .ihooman-carousel-card-desc { font-size: 12px; color: ${mutedColor}; margin-bottom: 8px; }
373
382
  .ihooman-carousel-card-btns { display: flex; flex-direction: column; gap: 6px; }
374
- .ihooman-widget .ihooman-carousel-card-btn { cursor: pointer !important; transition: all 0.2s !important; }
375
383
  .ihooman-quick-replies { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
376
- .ihooman-widget .ihooman-quick-reply { cursor: pointer !important; transition: all 0.2s !important; }
377
384
  @media (max-width: 480px) { .ihooman-window { width: calc(100vw - 20px); height: calc(100vh - 100px); min-height: 400px; max-height: calc(100vh - 100px); left: 10px; right: 10px; bottom: 80px; } .ihooman-toggle { ${positionRight ? 'right: 16px' : 'left: 16px'}; bottom: 16px; } .ihooman-proactive-toast { left: 10px; right: 10px; max-width: none; } }
378
385
  `;
379
386
  }
@@ -383,14 +390,27 @@ function generateStyles(): string {
383
390
  // DOM CREATION
384
391
  // ============================================================================
385
392
 
393
+ let shadowRoot: ShadowRoot | null = null;
394
+
386
395
  function createWidget(): void {
396
+ // Create host element
397
+ const host = document.createElement('div');
398
+ host.id = 'ihooman-chat-widget-host';
399
+ host.style.cssText = 'all: initial !important; position: fixed !important; z-index: 2147483647 !important; pointer-events: none !important;';
400
+ document.body.appendChild(host);
401
+
402
+ // Create Shadow DOM for style isolation
403
+ shadowRoot = host.attachShadow({ mode: 'open' });
404
+
405
+ // Add styles inside shadow DOM
387
406
  const styleEl = document.createElement('style');
388
407
  styleEl.id = 'ihooman-widget-styles';
389
408
  styleEl.textContent = generateStyles();
390
- document.head.appendChild(styleEl);
409
+ shadowRoot.appendChild(styleEl);
391
410
 
392
411
  const widget = document.createElement('div');
393
412
  widget.className = 'ihooman-widget';
413
+ widget.style.cssText = 'pointer-events: auto;';
394
414
  widget.innerHTML = `
395
415
  <button class="ihooman-toggle" aria-label="Open chat">
396
416
  <span class="ihooman-pulse"></span>
@@ -459,7 +479,7 @@ function createWidget(): void {
459
479
  </div>
460
480
  `;
461
481
 
462
- document.body.appendChild(widget);
482
+ shadowRoot.appendChild(widget);
463
483
 
464
484
  elements = {
465
485
  widget,
@@ -1789,16 +1809,41 @@ const DEFAULT_BUTTON_STYLES = {
1789
1809
  fontSize: 12,
1790
1810
  fontWeight: 'medium',
1791
1811
  },
1812
+ toggleButton: {
1813
+ backgroundColor: '#00aeff',
1814
+ textColor: '#ffffff',
1815
+ borderColor: 'transparent',
1816
+ borderWidth: 0,
1817
+ borderRadius: 30,
1818
+ paddingVertical: 0,
1819
+ paddingHorizontal: 0,
1820
+ fontSize: 14,
1821
+ fontWeight: 'medium',
1822
+ },
1823
+ attachButton: {
1824
+ backgroundColor: 'transparent',
1825
+ textColor: '#6b7280',
1826
+ borderColor: 'transparent',
1827
+ borderWidth: 0,
1828
+ borderRadius: 8,
1829
+ paddingVertical: 6,
1830
+ paddingHorizontal: 6,
1831
+ fontSize: 14,
1832
+ fontWeight: 'medium',
1833
+ },
1792
1834
  };
1793
1835
 
1794
1836
  function applyButtonStyling(buttonStyling?: Record<string, Record<string, unknown>>): void {
1795
1837
  const styleId = 'ihooman-button-styling';
1796
- let styleEl = document.getElementById(styleId) as HTMLStyleElement | null;
1838
+
1839
+ // Get the shadow root or fall back to document.head
1840
+ const styleContainer = shadowRoot || document.head;
1841
+ let styleEl = styleContainer.querySelector(`#${styleId}`) as HTMLStyleElement | null;
1797
1842
 
1798
1843
  if (!styleEl) {
1799
1844
  styleEl = document.createElement('style');
1800
1845
  styleEl.id = styleId;
1801
- document.head.appendChild(styleEl);
1846
+ styleContainer.appendChild(styleEl);
1802
1847
  }
1803
1848
 
1804
1849
  // Merge provided styles with defaults
@@ -1811,6 +1856,8 @@ function applyButtonStyling(buttonStyling?: Record<string, Record<string, unknow
1811
1856
  headerActions: { ...DEFAULT_BUTTON_STYLES.headerActions, ...(buttonStyling?.headerActions || {}) },
1812
1857
  escalation: { ...DEFAULT_BUTTON_STYLES.escalation, ...(buttonStyling?.escalation || {}) },
1813
1858
  cardActions: { ...DEFAULT_BUTTON_STYLES.cardActions, ...(buttonStyling?.cardActions || {}) },
1859
+ toggleButton: { ...DEFAULT_BUTTON_STYLES.toggleButton, ...(buttonStyling?.toggleButton || {}) },
1860
+ attachButton: { ...DEFAULT_BUTTON_STYLES.attachButton, ...(buttonStyling?.attachButton || {}) },
1814
1861
  };
1815
1862
 
1816
1863
  const generateButtonCSS = (selector: string, style: Record<string, unknown>): string => {
@@ -1824,37 +1871,37 @@ function applyButtonStyling(buttonStyling?: Record<string, Record<string, unknow
1824
1871
  const fontSize = style.fontSize as number;
1825
1872
  const fontWeight = getFontWeightValue(style.fontWeight as string);
1826
1873
 
1874
+ // Shadow DOM provides isolation, so we don't need !important or high specificity
1827
1875
  return `
1828
- .ihooman-widget ${selector},
1829
- html body .ihooman-widget ${selector} {
1830
- background: ${bg} !important;
1831
- color: ${color} !important;
1832
- border: ${borderWidth}px solid ${borderColor} !important;
1833
- border-radius: ${borderRadius}px !important;
1834
- padding: ${paddingV}px ${paddingH}px !important;
1835
- font-size: ${fontSize}px !important;
1836
- font-weight: ${fontWeight} !important;
1837
- min-width: auto !important;
1838
- min-height: auto !important;
1839
- width: auto !important;
1840
- height: auto !important;
1841
- max-width: none !important;
1842
- max-height: none !important;
1843
- display: inline-flex !important;
1844
- align-items: center !important;
1845
- justify-content: center !important;
1846
- gap: 6px !important;
1847
- line-height: 1.4 !important;
1848
- text-transform: none !important;
1849
- letter-spacing: normal !important;
1850
- box-shadow: none !important;
1851
- text-decoration: none !important;
1852
- white-space: nowrap !important;
1853
- flex-shrink: 0 !important;
1854
- flex-grow: 0 !important;
1855
- box-sizing: border-box !important;
1856
- appearance: none !important;
1857
- -webkit-appearance: none !important;
1876
+ ${selector} {
1877
+ background: ${bg};
1878
+ color: ${color};
1879
+ border: ${borderWidth}px solid ${borderColor};
1880
+ border-radius: ${borderRadius}px;
1881
+ padding: ${paddingV}px ${paddingH}px;
1882
+ margin: 0;
1883
+ font-family: inherit;
1884
+ font-size: ${fontSize}px;
1885
+ font-weight: ${fontWeight};
1886
+ min-width: unset;
1887
+ min-height: unset;
1888
+ width: auto;
1889
+ height: auto;
1890
+ max-width: none;
1891
+ max-height: none;
1892
+ display: inline-flex;
1893
+ align-items: center;
1894
+ justify-content: center;
1895
+ gap: 6px;
1896
+ line-height: 1.4;
1897
+ text-transform: none;
1898
+ letter-spacing: normal;
1899
+ box-shadow: none;
1900
+ text-decoration: none;
1901
+ white-space: nowrap;
1902
+ box-sizing: border-box;
1903
+ cursor: pointer;
1904
+ transition: all 0.2s ease;
1858
1905
  }
1859
1906
  `;
1860
1907
  };
@@ -1893,6 +1940,25 @@ function applyButtonStyling(buttonStyling?: Record<string, Record<string, unknow
1893
1940
  // Card action buttons
1894
1941
  css += generateButtonCSS('.ihooman-carousel-card-btn', mergedStyles.cardActions);
1895
1942
 
1943
+ // Toggle button (floating chat bubble) - special handling for circular button
1944
+ const toggleStyle = mergedStyles.toggleButton;
1945
+ const toggleBg = toggleStyle.backgroundColor as string;
1946
+ const toggleColor = toggleStyle.textColor as string;
1947
+ const toggleBorderColor = toggleStyle.borderColor as string;
1948
+ const toggleBorderWidth = toggleStyle.borderWidth as number;
1949
+ const toggleBorderRadius = toggleStyle.borderRadius as number;
1950
+ css += `
1951
+ .ihooman-toggle {
1952
+ background: linear-gradient(135deg, ${toggleBg}, ${toggleBg}) !important;
1953
+ color: ${toggleColor};
1954
+ border: ${toggleBorderWidth}px solid ${toggleBorderColor};
1955
+ border-radius: ${toggleBorderRadius}px;
1956
+ }
1957
+ `;
1958
+
1959
+ // Attach button (file attachment)
1960
+ css += generateButtonCSS('.ihooman-input-btn.attach', mergedStyles.attachButton);
1961
+
1896
1962
  console.debug('[IhoomanChat] Applied button styling CSS:', css.length, 'chars');
1897
1963
  styleEl.textContent = css;
1898
1964
  }