andy-widget-react 2.0.6 → 2.1.1

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 CHANGED
@@ -46,6 +46,8 @@ Widget as a short, language-aware retry message.
46
46
  | `description` | `string` | Override the configured description |
47
47
  | `welcomeMessage` | `string` | Override the configured first message |
48
48
  | `bubbleLabel` | `string` | Override the configured pill label |
49
+ | `lang` | `'en' \| 'es'` | Language for the Widget's own chrome (placeholder, starter-question title, error and handoff text). Overrides the Agent's `defaultLang`, so a Spanish Agent on an English page still renders English chrome |
50
+ | `predefinedQuestions` | `{ order: number, question: string }[]` | Override the configured starter questions |
49
51
  | `theme` | `'light' \| 'dark' \| 'auto'` | Override the configured theme |
50
52
  | `orientation` | `'left' \| 'right'` | Override the configured position |
51
53
  | `brandColor` | `string` | Override the configured six-digit hex color |
package/dist/index.cjs CHANGED
@@ -3437,6 +3437,48 @@ const SVG_ICONS = {
3437
3437
  <path d="M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6 1.41-1.41z" />
3438
3438
  </svg>`};
3439
3439
 
3440
+ // Localized UI Strings
3441
+ // Chrome the widget renders itself, as opposed to copy the Agent supplies.
3442
+ // Keyed by language so React and Vanilla render identical text for a visitor.
3443
+ const UI_STRINGS = {
3444
+ en: {
3445
+ openChat: 'Open chat',
3446
+ closeChat: 'Close chat',
3447
+ goBack: 'Go back',
3448
+ messageInput: 'Message input',
3449
+ sendMessage: 'Send message',
3450
+ welcomeMessage: 'Welcome message',
3451
+ closeWelcomeMessage: 'Close welcome message',
3452
+ inputPlaceholder: 'Type your message...',
3453
+ predefinedQuestionsTitle: 'What would you like to know?',
3454
+ sendFailure: 'Sorry, I could not answer. Please try again.',
3455
+ handoffWaiting: 'A team member will reply soon.',
3456
+ teamName: 'Team'
3457
+ },
3458
+ es: {
3459
+ openChat: 'Abrir chat',
3460
+ closeChat: 'Cerrar chat',
3461
+ goBack: 'Volver',
3462
+ messageInput: 'Entrada de mensaje',
3463
+ sendMessage: 'Enviar mensaje',
3464
+ welcomeMessage: 'Mensaje de bienvenida',
3465
+ closeWelcomeMessage: 'Cerrar mensaje de bienvenida',
3466
+ inputPlaceholder: 'Escribe tu mensaje...',
3467
+ predefinedQuestionsTitle: '¿Qué te gustaría saber?',
3468
+ sendFailure: 'Lo siento, no pude responder. Inténtalo de nuevo.',
3469
+ handoffWaiting: 'Un miembro del equipo te responderá pronto.',
3470
+ teamName: 'Equipo'
3471
+ }
3472
+ };
3473
+
3474
+ /**
3475
+ * Get the widget's own UI strings for a language.
3476
+ * Unknown languages fall back to English rather than rendering blanks.
3477
+ * @param {string} [lang] - Language code ('en' or 'es')
3478
+ * @returns {typeof UI_STRINGS.en} The localized string set
3479
+ */
3480
+ const getUiStrings = lang => UI_STRINGS[lang] || UI_STRINGS.en;
3481
+
3440
3482
  /**
3441
3483
  * Keyboard detection utility for handling mobile virtual keyboards
3442
3484
  * Provides cross-browser support for detecting keyboard open/close events
@@ -3855,8 +3897,13 @@ const createBrowserHandoff = (chatbotId, bootstrap, onProjection) => {
3855
3897
  }
3856
3898
  };
3857
3899
 
3858
- const AndyChat = ({ embedId, tooltip, name, headline, description, welcomeMessage, bubbleLabel, theme, orientation, brandColor, bubbleStyle, useBrandColor, logoUrl, previewMode = false, initialOpen = false }) => {
3900
+ const AndyChat = ({ embedId, tooltip, name, headline, description, welcomeMessage, bubbleLabel, lang, predefinedQuestions, theme, orientation, brandColor, bubbleStyle, useBrandColor, logoUrl, previewMode = false, initialOpen = false }) => {
3859
3901
  const [config, setConfig] = react.useState(null);
3902
+ // The visitor's language wins over the Agent's own default: a Spanish Agent
3903
+ // embedded on an English page must still render English chrome.
3904
+ const uiLang = lang || config?.defaultLang || 'en';
3905
+ const strings = getUiStrings(uiLang);
3906
+ const activeQuestions = predefinedQuestions?.length ? predefinedQuestions : config?.predefinedQuestions;
3860
3907
  const [isOpen, setIsOpen] = react.useState(initialOpen);
3861
3908
  const [messages, setMessages] = react.useState([]);
3862
3909
  const [isLoading, setIsLoading] = react.useState(false);
@@ -3886,8 +3933,11 @@ const AndyChat = ({ embedId, tooltip, name, headline, description, welcomeMessag
3886
3933
  setSessionId(projection.identity.sessionId);
3887
3934
  pendingHandoffIdsRef.current = projection.pendingProjectionIds || [];
3888
3935
  const projectedMessages = projection.messages.map(message => ({ id: message.id, content: message.content, sender: message.role === 'user' ? 'user' : 'bot', timestamp: new Date(message.createdAt).toISOString(), isHuman: message.sentByHuman }));
3936
+ // An empty agent projection does not mean the client-only greeting is gone.
3937
+ if (projection.control === 'agent' && projectedMessages.length === 0)
3938
+ return;
3889
3939
  setMessages(projection.control === 'requested' || projection.control === 'human'
3890
- ? [...projectedMessages, { id: 'handoff-waiting', content: config.defaultLang === 'es' ? 'Un miembro del equipo te responderá pronto.' : 'A team member will reply soon.', sender: 'bot', timestamp: new Date().toISOString(), isWaiting: true }]
3940
+ ? [...projectedMessages, { id: 'handoff-waiting', content: strings.handoffWaiting, sender: 'bot', timestamp: new Date().toISOString(), isWaiting: true }]
3891
3941
  : projectedMessages);
3892
3942
  });
3893
3943
  handoffRef.current = handoff;
@@ -4076,12 +4126,12 @@ const AndyChat = ({ embedId, tooltip, name, headline, description, welcomeMessag
4076
4126
  bubbleStyle: bubbleStyle || 'icon',
4077
4127
  bubbleLabel: bubbleLabel || null,
4078
4128
  useBrandColor: useBrandColor !== undefined ? useBrandColor : true,
4079
- defaultLang: 'en',
4129
+ defaultLang: uiLang,
4080
4130
  showBranding: true,
4081
4131
  showWelcomePopup: { enabled: false, seconds: 3, message: '' },
4082
4132
  collectUserInfo: { enabled: false, message: '' },
4083
4133
  welcomeMessage: welcomeMessage || 'Hi there! How can I help you today?',
4084
- predefinedQuestions: [],
4134
+ predefinedQuestions: predefinedQuestions || [],
4085
4135
  faqs: []
4086
4136
  };
4087
4137
  setConfig(previewConfig);
@@ -4234,7 +4284,7 @@ const AndyChat = ({ embedId, tooltip, name, headline, description, welcomeMessag
4234
4284
  setIsLoading(true);
4235
4285
  const response = await sendMessageForWidget(embedId, sessionId, messageText);
4236
4286
  if (response.status === 'waiting') {
4237
- setMessages(prev => prev.some(message => message.isWaiting) ? prev : [...prev, { id: 'handoff-waiting', content: config?.defaultLang === 'es' ? 'Un miembro del equipo te responderá pronto.' : 'A team member will reply soon.', sender: 'bot', timestamp: new Date().toISOString(), isWaiting: true }]);
4287
+ setMessages(prev => prev.some(message => message.isWaiting) ? prev : [...prev, { id: 'handoff-waiting', content: strings.handoffWaiting, sender: 'bot', timestamp: new Date().toISOString(), isWaiting: true }]);
4238
4288
  return;
4239
4289
  }
4240
4290
  const botMessage = {
@@ -4261,9 +4311,7 @@ const AndyChat = ({ embedId, tooltip, name, headline, description, welcomeMessag
4261
4311
  console.error('AndyChat: Message request failed.');
4262
4312
  const errorMessage = {
4263
4313
  id: timestamp + 3,
4264
- content: config?.defaultLang === 'es'
4265
- ? 'Lo siento, no pude responder. Inténtalo de nuevo.'
4266
- : 'Sorry, I could not answer. Please try again.',
4314
+ content: strings.sendFailure,
4267
4315
  sender: 'bot',
4268
4316
  timestamp: new Date().toISOString(),
4269
4317
  isError: true
@@ -4370,7 +4418,7 @@ const AndyChat = ({ embedId, tooltip, name, headline, description, welcomeMessag
4370
4418
  bubble = document.createElement('button');
4371
4419
  bubble.type = 'button';
4372
4420
  bubble.className = 'andy-chat-bubble';
4373
- bubble.setAttribute('aria-label', 'Open chat');
4421
+ bubble.setAttribute('aria-label', strings.openChat);
4374
4422
  const tooltipHTML = tooltip
4375
4423
  ? `<span class="andy-chat-bubble__tooltip" role="tooltip">${tooltip}</span>`
4376
4424
  : '';
@@ -4379,9 +4427,10 @@ const AndyChat = ({ embedId, tooltip, name, headline, description, welcomeMessag
4379
4427
  bubble.addEventListener('click', () => setIsOpen(prev => !prev));
4380
4428
  }
4381
4429
  const isPillStyle = config?.bubbleStyle === 'pill';
4382
- const displayLabel = bubbleLabel || config?.bubbleLabel || (isPillStyle ? getDefaultBubbleLabel(config?.defaultLang || 'en') : null);
4430
+ const displayLabel = bubbleLabel || config?.bubbleLabel || (isPillStyle ? getDefaultBubbleLabel(uiLang) : null);
4383
4431
  const bubbleLogoUrl = config?.logoUrl || CHAT_BUBBLE_DEFAULT_ICON_URL;
4384
4432
  if (bubble) {
4433
+ bubble.setAttribute('aria-label', isOpen ? strings.closeChat : strings.openChat);
4385
4434
  bubble.className = 'andy-chat-bubble';
4386
4435
  if (isPillStyle) {
4387
4436
  bubble.classList.add('andy-chat-bubble--pill');
@@ -4424,7 +4473,7 @@ const AndyChat = ({ embedId, tooltip, name, headline, description, welcomeMessag
4424
4473
  }
4425
4474
  }
4426
4475
  }, [shadowReady, config, isOpen, tooltip, bubbleLabel]);
4427
- return (jsxRuntime.jsx("div", { ref: containerRef, id: 'andy-chatbot-container', children: portalRef.current && shadowReady && config && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [ReactDOM.createPortal(jsxRuntime.jsxs("div", { className: `andy-chat-window ${isOpen ? 'andy-chat-window--open' : ''}`, children: [jsxRuntime.jsxs("header", { className: 'andy-header', children: [jsxRuntime.jsx("button", { type: 'button', className: 'andy-header__back', id: 'andy-back-button', "aria-label": 'Go back', onClick: () => setIsOpen(false), children: jsxRuntime.jsx("svg", { className: 'andy-header__back-icon', width: '20', height: '20', viewBox: '0 0 24 24', fill: 'none', children: jsxRuntime.jsx("path", { d: 'M15 18l-6-6 6-6', stroke: 'currentColor', strokeWidth: '2', strokeLinecap: 'round', strokeLinejoin: 'round' }) }) }), jsxRuntime.jsxs("div", { className: 'andy-header__bot-info', children: [jsxRuntime.jsx("div", { className: 'andy-header__avatar', children: config?.logoUrl ? (jsxRuntime.jsx("img", { src: config.logoUrl, alt: 'Bot Avatar', className: 'andy-header__avatar-image' })) : (jsxRuntime.jsx("img", { src: CHAT_BUBBLE_DEFAULT_ICON_URL, alt: 'Bot Avatar', className: 'andy-header__avatar-icon andy-header__avatar-icon--default' })) }), jsxRuntime.jsxs("div", { className: 'andy-header__text', children: [jsxRuntime.jsx("h1", { className: 'andy-header__name', children: config?.name || 'Andy bot' }), config?.headline && (jsxRuntime.jsx("p", { className: 'andy-header__subtitle', title: config.headline, children: config.headline }))] })] }), jsxRuntime.jsx("button", { type: 'button', className: 'andy-header__close', id: 'andy-close-button', "aria-label": 'Close chat', onClick: () => setIsOpen(false), children: jsxRuntime.jsx("svg", { className: 'andy-header__close-icon', width: '20', height: '20', viewBox: '0 0 24 24', fill: 'none', children: jsxRuntime.jsx("path", { d: 'M18 6L6 18M6 6l12 12', stroke: 'currentColor', strokeWidth: '2', strokeLinecap: 'round', strokeLinejoin: 'round' }) }) })] }), jsxRuntime.jsxs("div", { className: 'andy-chat-window__messages', id: 'andy-messages', ref: messagesContainerRef, children: [config?.description && (jsxRuntime.jsx("div", { className: 'andy-chat-subtitle', children: jsxRuntime.jsx("p", { className: 'andy-chat-subtitle__text', children: config.description }) })), messages.map(message => {
4476
+ return (jsxRuntime.jsx("div", { ref: containerRef, id: 'andy-chatbot-container', children: portalRef.current && shadowReady && config && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [ReactDOM.createPortal(jsxRuntime.jsxs("div", { className: `andy-chat-window ${isOpen ? 'andy-chat-window--open' : ''}`, children: [jsxRuntime.jsxs("header", { className: 'andy-header', children: [jsxRuntime.jsx("button", { type: 'button', className: 'andy-header__back', id: 'andy-back-button', "aria-label": strings.goBack, onClick: () => setIsOpen(false), children: jsxRuntime.jsx("svg", { className: 'andy-header__back-icon', width: '20', height: '20', viewBox: '0 0 24 24', fill: 'none', children: jsxRuntime.jsx("path", { d: 'M15 18l-6-6 6-6', stroke: 'currentColor', strokeWidth: '2', strokeLinecap: 'round', strokeLinejoin: 'round' }) }) }), jsxRuntime.jsxs("div", { className: 'andy-header__bot-info', children: [jsxRuntime.jsx("div", { className: 'andy-header__avatar', children: config?.logoUrl ? (jsxRuntime.jsx("img", { src: config.logoUrl, alt: 'Bot Avatar', className: 'andy-header__avatar-image' })) : (jsxRuntime.jsx("img", { src: CHAT_BUBBLE_DEFAULT_ICON_URL, alt: 'Bot Avatar', className: 'andy-header__avatar-icon andy-header__avatar-icon--default' })) }), jsxRuntime.jsxs("div", { className: 'andy-header__text', children: [jsxRuntime.jsx("h1", { className: 'andy-header__name', children: config?.name || 'Andy bot' }), config?.headline && (jsxRuntime.jsx("p", { className: 'andy-header__subtitle', title: config.headline, children: config.headline }))] })] }), jsxRuntime.jsx("button", { type: 'button', className: 'andy-header__close', id: 'andy-close-button', "aria-label": strings.closeChat, onClick: () => setIsOpen(false), children: jsxRuntime.jsx("svg", { className: 'andy-header__close-icon', width: '20', height: '20', viewBox: '0 0 24 24', fill: 'none', children: jsxRuntime.jsx("path", { d: 'M18 6L6 18M6 6l12 12', stroke: 'currentColor', strokeWidth: '2', strokeLinecap: 'round', strokeLinejoin: 'round' }) }) })] }), jsxRuntime.jsxs("div", { className: 'andy-chat-window__messages', id: 'andy-messages', ref: messagesContainerRef, children: [config?.description && (jsxRuntime.jsx("div", { className: 'andy-chat-subtitle', children: jsxRuntime.jsx("p", { className: 'andy-chat-subtitle__text', children: config.description }) })), messages.map(message => {
4428
4477
  if (message.isForm) {
4429
4478
  return (jsxRuntime.jsxs("div", { className: 'andy-message-container andy-message-container--form', children: [jsxRuntime.jsx("div", { className: 'andy-avatar', children: jsxRuntime.jsx("svg", { className: 'andy-avatar__icon', width: '24', height: '24', viewBox: '0 0 24 24', fill: 'none', xmlns: 'http://www.w3.org/2000/svg', children: jsxRuntime.jsx("path", { d: 'M20 2H4C2.9 2 2 2.9 2 4V22L6 18H20C21.1 18 22 17.1 22 16V4C22 2.9 21.1 2 20 2Z', fill: 'currentColor' }) }) }), jsxRuntime.jsx("div", { className: 'andy-message andy-message--bot andy-message--form', children: jsxRuntime.jsx("div", { className: 'andy-user-info-form', children: jsxRuntime.jsxs("div", { className: 'andy-user-info-form__content', children: [jsxRuntime.jsx("h3", { className: 'andy-user-info-form__title', children: config?.collectUserInfo?.message ||
4430
4479
  'Please provide your information to continue:' }), jsxRuntime.jsxs("form", { className: 'andy-user-info-form__form', id: 'andy-user-info-form', children: [jsxRuntime.jsxs("div", { className: 'andy-form-group', children: [jsxRuntime.jsx("label", { htmlFor: 'andy-user-name', className: 'andy-form-group__label', children: "Name" }), jsxRuntime.jsx("input", { type: 'text', id: 'andy-user-name', className: 'andy-form-group__input', placeholder: 'Your Name', required: true })] }), jsxRuntime.jsxs("div", { className: 'andy-form-group', children: [jsxRuntime.jsx("label", { htmlFor: 'andy-user-email', className: 'andy-form-group__label', children: "Email" }), jsxRuntime.jsx("input", { type: 'email', id: 'andy-user-email', className: 'andy-form-group__input', placeholder: 'Your Email', required: true })] }), jsxRuntime.jsx("button", { type: 'submit', className: 'andy-button andy-button--primary andy-user-info-form__submit', children: "Submit" })] })] }) }) })] }, message.id));
@@ -4432,15 +4481,15 @@ const AndyChat = ({ embedId, tooltip, name, headline, description, welcomeMessag
4432
4481
  if (message.isLoading) {
4433
4482
  return (jsxRuntime.jsx("div", { className: 'andy-message-container andy-message-container--bot andy-message-container--loading', children: jsxRuntime.jsx("div", { className: 'andy-message andy-message--bot', children: jsxRuntime.jsxs("div", { className: 'andy-typing-indicator', children: [jsxRuntime.jsx("div", { className: 'andy-typing-indicator__dot' }), jsxRuntime.jsx("div", { className: 'andy-typing-indicator__dot' }), jsxRuntime.jsx("div", { className: 'andy-typing-indicator__dot' })] }) }) }, message.id));
4434
4483
  }
4435
- return (jsxRuntime.jsxs("div", { className: `andy-message-container andy-message-container--${message.sender} ${message.isWaiting ? 'andy-message-container--waiting' : ''}`, children: [message.sender === 'bot' && (jsxRuntime.jsxs("div", { className: `andy-message andy-message--bot ${message.isHuman ? 'andy-message--operator' : ''} ${message.isWaiting ? 'andy-message--waiting' : ''} ${message.isError ? 'andy-message--error' : ''}`, children: [jsxRuntime.jsxs("div", { className: 'andy-bot-header', children: [jsxRuntime.jsx("div", { className: 'andy-bot-header__icon', children: config?.logoUrl ? (jsxRuntime.jsx("img", { src: config.logoUrl, alt: 'Bot Avatar', className: 'andy-bot-header__icon-image' })) : (jsxRuntime.jsx("img", { src: CHAT_BUBBLE_DEFAULT_ICON_URL, alt: 'Bot Avatar', className: 'andy-bot-header__icon-image andy-bot-header__icon-image--default' })) }), jsxRuntime.jsx("span", { className: 'andy-bot-header__name', children: message.isHuman ? (config?.defaultLang === 'es' ? 'Equipo' : 'Team') : config?.name || 'Andy bot' })] }), jsxRuntime.jsx("div", { className: 'andy-message__content', children: jsxRuntime.jsx("div", { dangerouslySetInnerHTML: { __html: parseMarkdown(message.content) } }) })] })), message.sender === 'user' && (jsxRuntime.jsx("div", { className: 'andy-message andy-message--user', children: jsxRuntime.jsx("div", { className: 'andy-message__content', children: jsxRuntime.jsx("p", { children: message.content }) }) }))] }, message.id));
4436
- }), isLoading && (jsxRuntime.jsx("div", { className: 'andy-message-container andy-message-container--bot andy-message-container--typing', children: jsxRuntime.jsx("div", { className: 'andy-message andy-message--bot andy-message--typing', children: jsxRuntime.jsxs("div", { className: 'andy-typing-indicator', children: [jsxRuntime.jsx("div", { className: 'andy-typing-indicator__dot' }), jsxRuntime.jsx("div", { className: 'andy-typing-indicator__dot' }), jsxRuntime.jsx("div", { className: 'andy-typing-indicator__dot' })] }) }) }))] }), jsxRuntime.jsxs("div", { className: 'andy-chat-window__bottom', children: [config?.predefinedQuestions &&
4437
- config.predefinedQuestions.length > 0 &&
4438
- showPredefinedQuestions && (jsxRuntime.jsxs("div", { className: 'andy-predefined-questions', id: 'andy-predefined-questions', children: [jsxRuntime.jsx("div", { className: 'andy-predefined-questions__header', children: jsxRuntime.jsx("p", { className: 'andy-predefined-questions__title', children: "What would you like to know?" }) }), jsxRuntime.jsx("div", { className: 'andy-predefined-questions__list', children: config.predefinedQuestions.map((q, index) => (jsxRuntime.jsxs("button", { type: 'button', className: 'andy-predefined-question', "data-question": q.question, disabled: isCollectingUserInfo || isLoading || !config, children: [jsxRuntime.jsx("span", { className: 'andy-predefined-question__icon', children: "\uD83D\uDCAC" }), jsxRuntime.jsx("span", { className: 'andy-predefined-question__text', children: q.question })] }, index))) })] })), jsxRuntime.jsx("div", { className: 'andy-chat-window__input', children: jsxRuntime.jsx("div", { className: 'andy-input-container', children: jsxRuntime.jsxs("div", { className: 'andy-input', children: [jsxRuntime.jsx("input", { type: 'text', className: 'andy-input__field', id: 'andy-message-input', placeholder: config ? 'Type your message...' : '...', "aria-label": 'Message input', onKeyDown: e => {
4484
+ return (jsxRuntime.jsxs("div", { className: `andy-message-container andy-message-container--${message.sender} ${message.isWaiting ? 'andy-message-container--waiting' : ''}`, children: [message.sender === 'bot' && (jsxRuntime.jsxs("div", { className: `andy-message andy-message--bot ${message.isHuman ? 'andy-message--operator' : ''} ${message.isWaiting ? 'andy-message--waiting' : ''} ${message.isError ? 'andy-message--error' : ''}`, children: [jsxRuntime.jsxs("div", { className: 'andy-bot-header', children: [jsxRuntime.jsx("div", { className: 'andy-bot-header__icon', children: config?.logoUrl ? (jsxRuntime.jsx("img", { src: config.logoUrl, alt: 'Bot Avatar', className: 'andy-bot-header__icon-image' })) : (jsxRuntime.jsx("img", { src: CHAT_BUBBLE_DEFAULT_ICON_URL, alt: 'Bot Avatar', className: 'andy-bot-header__icon-image andy-bot-header__icon-image--default' })) }), jsxRuntime.jsx("span", { className: 'andy-bot-header__name', children: message.isHuman ? strings.teamName : config?.name || 'Andy bot' })] }), jsxRuntime.jsx("div", { className: 'andy-message__content', children: jsxRuntime.jsx("div", { dangerouslySetInnerHTML: { __html: parseMarkdown(message.content) } }) })] })), message.sender === 'user' && (jsxRuntime.jsx("div", { className: 'andy-message andy-message--user', children: jsxRuntime.jsx("div", { className: 'andy-message__content', children: jsxRuntime.jsx("p", { children: message.content }) }) }))] }, message.id));
4485
+ }), isLoading && (jsxRuntime.jsx("div", { className: 'andy-message-container andy-message-container--bot andy-message-container--typing', children: jsxRuntime.jsx("div", { className: 'andy-message andy-message--bot andy-message--typing', children: jsxRuntime.jsxs("div", { className: 'andy-typing-indicator', children: [jsxRuntime.jsx("div", { className: 'andy-typing-indicator__dot' }), jsxRuntime.jsx("div", { className: 'andy-typing-indicator__dot' }), jsxRuntime.jsx("div", { className: 'andy-typing-indicator__dot' })] }) }) }))] }), jsxRuntime.jsxs("div", { className: 'andy-chat-window__bottom', children: [activeQuestions &&
4486
+ activeQuestions.length > 0 &&
4487
+ showPredefinedQuestions && (jsxRuntime.jsxs("div", { className: 'andy-predefined-questions', id: 'andy-predefined-questions', children: [jsxRuntime.jsx("div", { className: 'andy-predefined-questions__header', children: jsxRuntime.jsx("p", { className: 'andy-predefined-questions__title', children: strings.predefinedQuestionsTitle }) }), jsxRuntime.jsx("div", { className: 'andy-predefined-questions__list', children: activeQuestions.map((q, index) => (jsxRuntime.jsxs("button", { type: 'button', className: 'andy-predefined-question', "data-question": q.question, disabled: isCollectingUserInfo || isLoading || !config, children: [jsxRuntime.jsx("span", { className: 'andy-predefined-question__icon', children: "\uD83D\uDCAC" }), jsxRuntime.jsx("span", { className: 'andy-predefined-question__text', children: q.question })] }, index))) })] })), jsxRuntime.jsx("div", { className: 'andy-chat-window__input', children: jsxRuntime.jsx("div", { className: 'andy-input-container', children: jsxRuntime.jsxs("div", { className: 'andy-input', children: [jsxRuntime.jsx("input", { type: 'text', className: 'andy-input__field', id: 'andy-message-input', placeholder: config ? strings.inputPlaceholder : '...', "aria-label": strings.messageInput, onKeyDown: e => {
4439
4488
  if (e.key === 'Enter' && e.target.value.trim()) {
4440
4489
  handleSendMessage(e.target.value);
4441
4490
  e.target.value = '';
4442
4491
  }
4443
- }, disabled: isCollectingUserInfo || !config }), jsxRuntime.jsx("button", { type: 'button', className: 'andy-input__button', id: 'andy-send-button', "aria-label": 'Send message', onClick: () => {
4492
+ }, disabled: isCollectingUserInfo || !config }), jsxRuntime.jsx("button", { type: 'button', className: 'andy-input__button', id: 'andy-send-button', "aria-label": strings.sendMessage, onClick: () => {
4444
4493
  const input = shadowRef.current?.getElementById('andy-message-input');
4445
4494
  if (input && input.value.trim()) {
4446
4495
  handleSendMessage(input.value);
@@ -4448,9 +4497,9 @@ const AndyChat = ({ embedId, tooltip, name, headline, description, welcomeMessag
4448
4497
  }
4449
4498
  }, disabled: isCollectingUserInfo || !config, children: jsxRuntime.jsx("svg", { className: 'andy-input__button-icon', width: '18', height: '18', viewBox: '0 0 24 24', fill: 'currentColor', xmlns: 'http://www.w3.org/2000/svg', children: jsxRuntime.jsx("path", { d: 'M2.01 21L23 12 2.01 3 2 10l15 2-15 2z' }) }) })] }) }) }), config?.showBranding !== false && (jsxRuntime.jsx("footer", { className: 'andy-chat-window__footer', children: jsxRuntime.jsx("a", { href: getFooterUrl(), target: '_blank', rel: 'noopener noreferrer', className: 'andy-chat-window__footer-link', children: jsxRuntime.jsx("span", { className: 'andy-chat-window__footer-text', children: FOOTER_TEXT }) }) }))] })] }), portalRef.current), showWelcomePopup &&
4450
4499
  !isOpen &&
4451
- ReactDOM.createPortal(jsxRuntime.jsxs("div", { className: `andy-welcome-popup ${config?.orientation === 'left' ? 'andychat-popup-left' : ''}`, style: { display: 'block' }, role: 'dialog', "aria-label": 'Welcome message', children: [jsxRuntime.jsxs("div", { className: 'andy-welcome-popup__content', children: [jsxRuntime.jsx("div", { className: 'andy-welcome-popup__message', children: config?.showWelcomePopup?.message ||
4500
+ ReactDOM.createPortal(jsxRuntime.jsxs("div", { className: `andy-welcome-popup ${config?.orientation === 'left' ? 'andychat-popup-left' : ''}`, style: { display: 'block' }, role: 'dialog', "aria-label": strings.welcomeMessage, children: [jsxRuntime.jsxs("div", { className: 'andy-welcome-popup__content', children: [jsxRuntime.jsx("div", { className: 'andy-welcome-popup__message', children: config?.showWelcomePopup?.message ||
4452
4501
  config?.welcomeMessage ||
4453
- 'Welcome! How can I help you today?' }), jsxRuntime.jsx("button", { type: 'button', className: 'andy-welcome-popup__close', "aria-label": 'Close welcome message', onClick: () => setShowWelcomePopup(false), children: jsxRuntime.jsx("svg", { className: 'andy-welcome-popup__close-icon', width: '20', height: '20', viewBox: '0 0 24 24', fill: 'none', xmlns: 'http://www.w3.org/2000/svg', children: jsxRuntime.jsx("path", { d: 'M18 6L6 18M6 6l12 12', stroke: 'currentColor', strokeWidth: '2', strokeLinecap: 'round', strokeLinejoin: 'round' }) }) })] }), jsxRuntime.jsx("div", { className: 'andy-welcome-popup__arrow' })] }), portalRef.current)] })) }));
4502
+ 'Welcome! How can I help you today?' }), jsxRuntime.jsx("button", { type: 'button', className: 'andy-welcome-popup__close', "aria-label": strings.closeWelcomeMessage, onClick: () => setShowWelcomePopup(false), children: jsxRuntime.jsx("svg", { className: 'andy-welcome-popup__close-icon', width: '20', height: '20', viewBox: '0 0 24 24', fill: 'none', xmlns: 'http://www.w3.org/2000/svg', children: jsxRuntime.jsx("path", { d: 'M18 6L6 18M6 6l12 12', stroke: 'currentColor', strokeWidth: '2', strokeLinecap: 'round', strokeLinejoin: 'round' }) }) })] }), jsxRuntime.jsx("div", { className: 'andy-welcome-popup__arrow' })] }), portalRef.current)] })) }));
4454
4503
  };
4455
4504
 
4456
4505
  const { SESSION_STORAGE_KEY, FORM_DISPLAY_DELAY_MS, PERSIST_SESSION } = CONFIG;