@topconsultnpm/sdkui-react 6.22.0-dev3.9 → 6.22.0-dev4.10

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 (186) hide show
  1. package/lib/components/NewComponents/ContextMenu/styles.d.ts +43 -45
  2. package/lib/components/NewComponents/FloatingMenuBar/styles.d.ts +60 -67
  3. package/lib/components/base/Styled.d.ts +77 -93
  4. package/lib/components/base/TMAlert.js +6 -8
  5. package/lib/components/base/TMAreaManager.js +53 -55
  6. package/lib/components/base/TMButton.js +4 -2
  7. package/lib/components/base/TMCounterBar.d.ts +2 -2
  8. package/lib/components/base/TMCounterContainer.d.ts +4 -3
  9. package/lib/components/base/TMCounterContainer.js +16 -1
  10. package/lib/components/base/TMCustomButton.d.ts +1 -1
  11. package/lib/components/base/TMCustomButton.js +40 -48
  12. package/lib/components/base/TMDataGrid.js +243 -223
  13. package/lib/components/base/TMDataGridExportForm.d.ts +1 -2
  14. package/lib/components/base/TMFileManager.d.ts +1 -2
  15. package/lib/components/base/TMFileManagerDataGridView.d.ts +1 -2
  16. package/lib/components/base/TMFileManagerThumbnailItems.d.ts +1 -1
  17. package/lib/components/base/TMFileManagerThumbnailsView.d.ts +1 -1
  18. package/lib/components/base/TMFileManagerUtils.d.ts +6 -4
  19. package/lib/components/base/TMLayout.d.ts +4 -4
  20. package/lib/components/base/TMList.d.ts +1 -2
  21. package/lib/components/base/TMListView.d.ts +1 -1
  22. package/lib/components/base/TMPanel.js +173 -170
  23. package/lib/components/base/TMSpinner.d.ts +3 -3
  24. package/lib/components/base/TMSpinner.js +9 -7
  25. package/lib/components/base/TMTab.d.ts +3 -4
  26. package/lib/components/base/TMTabControl.d.ts +5 -0
  27. package/lib/components/base/TMTabControl.js +219 -208
  28. package/lib/components/base/TMTooltip.d.ts +1 -1
  29. package/lib/components/base/TMTreeView.d.ts +8 -14
  30. package/lib/components/base/TMTreeView.js +20 -0
  31. package/lib/components/base/TMUserAvatar.d.ts +1 -2
  32. package/lib/components/base/TMVilViewer.d.ts +1 -2
  33. package/lib/components/base/TMWaitPanel.d.ts +2 -3
  34. package/lib/components/base/TMWaitPanel.js +1 -1
  35. package/lib/components/base/waitPanel/TMWaitPanelConfirm.d.ts +12 -0
  36. package/lib/components/base/waitPanel/TMWaitPanelConfirm.js +185 -0
  37. package/lib/components/base/waitPanel/TMWaitPanelManager.d.ts +179 -0
  38. package/lib/components/base/waitPanel/TMWaitPanelManager.js +373 -0
  39. package/lib/components/base/waitPanel/TMWaitPanelView.d.ts +57 -0
  40. package/lib/components/base/waitPanel/TMWaitPanelView.js +346 -0
  41. package/lib/components/base/waitPanel/index.d.ts +1 -0
  42. package/lib/components/base/waitPanel/index.js +1 -0
  43. package/lib/components/choosers/TMDistinctValues.js +3 -3
  44. package/lib/components/choosers/TMDynDataListItemChooser.d.ts +1 -1
  45. package/lib/components/choosers/TMInvoiceRetrieveFormats.d.ts +1 -2
  46. package/lib/components/choosers/TMOrderRetrieveFormats.d.ts +1 -2
  47. package/lib/components/choosers/TMPathChooser.js +17 -34
  48. package/lib/components/choosers/TMQuickSearchInfo.d.ts +1 -2
  49. package/lib/components/choosers/TMRelationChooser.d.ts +3 -3
  50. package/lib/components/choosers/TMUserChooser.d.ts +2 -2
  51. package/lib/components/editors/TMEditorStyled.d.ts +42 -20
  52. package/lib/components/editors/TMFormulaEditor.d.ts +1 -1
  53. package/lib/components/editors/TMHtmlContentDisplay.d.ts +1 -2
  54. package/lib/components/editors/TMHtmlEditor.d.ts +1 -2
  55. package/lib/components/editors/TMTextBox.d.ts +4 -0
  56. package/lib/components/editors/TMTextBox.js +99 -11
  57. package/lib/components/editors/TMTreeDropDown.d.ts +1 -1
  58. package/lib/components/features/archive/TMArchive.js +7 -2
  59. package/lib/components/features/assistant/TMHelpOnLineChat.d.ts +28 -0
  60. package/lib/components/features/assistant/TMHelpOnLineChat.js +1231 -0
  61. package/lib/components/features/assistant/TMToppyDraggableHelpCenter.d.ts +1 -1
  62. package/lib/components/features/assistant/TMToppyDraggableHelpCenter.js +2 -2
  63. package/lib/components/features/blog/TMBlogCommentForm.d.ts +1 -2
  64. package/lib/components/features/documents/TMBatchUpdateForm.js +3 -4
  65. package/lib/components/features/documents/TMCopyToFolderForm.js +53 -84
  66. package/lib/components/features/documents/TMDcmtForm.js +50 -61
  67. package/lib/components/features/documents/TMDcmtFormActionButtons.d.ts +1 -1
  68. package/lib/components/features/documents/TMDcmtIcon.d.ts +1 -4
  69. package/lib/components/features/documents/TMDcmtIcon.js +3 -5
  70. package/lib/components/features/documents/TMDcmtPreview.d.ts +6 -8
  71. package/lib/components/features/documents/TMDcmtPreview.js +5 -3
  72. package/lib/components/features/documents/TMDcmtTasks.d.ts +1 -2
  73. package/lib/components/features/documents/TMDcmtTasks.js +2 -9
  74. package/lib/components/features/documents/TMDragDropOverlay.d.ts +1 -1
  75. package/lib/components/features/documents/TMFileUploader.js +5 -5
  76. package/lib/components/features/documents/TMMasterDetailDcmts.d.ts +2 -0
  77. package/lib/components/features/documents/TMMasterDetailDcmts.js +53 -148
  78. package/lib/components/features/documents/TMMasterInfoFields.d.ts +1 -2
  79. package/lib/components/features/documents/TMMasterInfoFields.js +3 -2
  80. package/lib/components/features/documents/TMMergeToPdfForm.d.ts +1 -2
  81. package/lib/components/features/documents/TMMergeToPdfForm.js +52 -56
  82. package/lib/components/features/documents/TMMultiMasterDetailDcmtsForm.d.ts +1 -2
  83. package/lib/components/features/documents/TMMultiMasterDetailDcmtsForm.js +14 -15
  84. package/lib/components/features/documents/TMMultiMasterDetailDcmtsUtils.d.ts +5 -5
  85. package/lib/components/features/documents/TMMultiMasterDetailDcmtsUtils.js +3 -3
  86. package/lib/components/features/documents/TMRelationViewer.d.ts +13 -14
  87. package/lib/components/features/documents/TMRelationViewer.js +206 -143
  88. package/lib/components/features/documents/relationTreeState.d.ts +32 -0
  89. package/lib/components/features/documents/relationTreeState.js +89 -0
  90. package/lib/components/features/search/TMDcmtCheckoutInfoForm.d.ts +1 -2
  91. package/lib/components/features/search/TMMetadataOutputForm.d.ts +1 -2
  92. package/lib/components/features/search/TMMetadataSorterForm.d.ts +1 -2
  93. package/lib/components/features/search/TMSavedQuerySelector.d.ts +2 -2
  94. package/lib/components/features/search/TMSearch.d.ts +1 -2
  95. package/lib/components/features/search/TMSearch.js +3 -4
  96. package/lib/components/features/search/TMSearchQueryPanel.d.ts +3 -9
  97. package/lib/components/features/search/TMSearchQueryPanel.js +0 -4
  98. package/lib/components/features/search/TMSearchResult.d.ts +5 -0
  99. package/lib/components/features/search/TMSearchResult.js +129 -102
  100. package/lib/components/features/search/TMSearchResultFloatingActionButton.d.ts +1 -1
  101. package/lib/components/features/search/TMSignatureInfoContent.d.ts +1 -2
  102. package/lib/components/features/search/TMTreeSelector.js +23 -27
  103. package/lib/components/features/search/TMViewHistoryDcmt.d.ts +1 -2
  104. package/lib/components/features/search/TMViewHistoryDcmt.js +15 -26
  105. package/lib/components/features/tasks/TMTaskForm.d.ts +1 -1
  106. package/lib/components/features/tasks/TMTaskFormUtils.d.ts +10 -10
  107. package/lib/components/features/tasks/TMTasksAgenda.d.ts +1 -1
  108. package/lib/components/features/tasks/TMTasksCalendar.d.ts +1 -1
  109. package/lib/components/features/tasks/TMTasksHeader.d.ts +1 -1
  110. package/lib/components/features/tasks/TMTasksPanelContent.d.ts +1 -1
  111. package/lib/components/features/tasks/TMTasksUtilsView.d.ts +5 -5
  112. package/lib/components/features/tasks/TMTasksView.d.ts +1 -1
  113. package/lib/components/features/tasks/TMTasksView.js +97 -90
  114. package/lib/components/features/wg/TMWGsCopyMoveForm.d.ts +2 -3
  115. package/lib/components/features/wg/TMWGsCopyMoveForm.js +95 -91
  116. package/lib/components/features/workflow/TMWorkflowPopup.d.ts +7 -8
  117. package/lib/components/features/workflow/diagram/WorkitemRecipientsEditor.d.ts +1 -3
  118. package/lib/components/forms/Login/ChangePasswordInputs.d.ts +1 -3
  119. package/lib/components/forms/Login/Chooser.d.ts +2 -2
  120. package/lib/components/forms/TMChooserForm.d.ts +1 -2
  121. package/lib/components/forms/TMResultDialog.js +1 -1
  122. package/lib/components/forms/TMSaveForm.d.ts +4 -4
  123. package/lib/components/grids/TMBlogAttachments.d.ts +1 -2
  124. package/lib/components/grids/TMBlogHeader.d.ts +1 -1
  125. package/lib/components/grids/TMBlogsPost.d.ts +1 -1
  126. package/lib/components/grids/TMBlogsPost.js +93 -97
  127. package/lib/components/grids/TMBlogsPostUtils.d.ts +9 -9
  128. package/lib/components/grids/TMValidationItemsList.d.ts +1 -2
  129. package/lib/components/index.d.ts +5 -1
  130. package/lib/components/index.js +4 -1
  131. package/lib/components/layout/panelManager/TMPanelManagerContainer.d.ts +1 -2
  132. package/lib/components/layout/panelManager/TMPanelManagerContainer.js +4 -3
  133. package/lib/components/layout/panelManager/TMPanelManagerContext.d.ts +3 -2
  134. package/lib/components/layout/panelManager/TMPanelManagerContext.js +5 -1
  135. package/lib/components/layout/panelManager/TMPanelManagerLoader.d.ts +5 -0
  136. package/lib/components/layout/panelManager/TMPanelManagerLoader.js +18 -0
  137. package/lib/components/layout/panelManager/TMPanelManagerToolbar.d.ts +6 -5
  138. package/lib/components/layout/panelManager/TMPanelManagerToolbar.js +4 -8
  139. package/lib/components/layout/panelManager/TMPanelManagerWithPersistenceProvider.d.ts +2 -2
  140. package/lib/components/layout/panelManager/TMPanelManagerWithPersistenceProvider.js +2 -1
  141. package/lib/components/layout/panelManager/TMPanelWrapper.d.ts +2 -2
  142. package/lib/components/pages/TMPage.d.ts +1 -1
  143. package/lib/components/pages/TMPage.js +32 -31
  144. package/lib/components/query/TMQueryEditor.d.ts +13 -14
  145. package/lib/components/query/TMQueryEditor.js +2 -1
  146. package/lib/components/settings/SettingsAppearance.d.ts +1 -2
  147. package/lib/components/sidebar/TMAboutApp.d.ts +1 -2
  148. package/lib/components/sidebar/TMCommandsPanel.d.ts +4 -4
  149. package/lib/components/sidebar/TMHeader.d.ts +4 -3
  150. package/lib/components/sidebar/TMHeader.js +2 -2
  151. package/lib/components/viewers/TMDataListItemViewer.d.ts +2 -3
  152. package/lib/components/viewers/TMDataUserIdItemViewer.d.ts +2 -3
  153. package/lib/components/viewers/TMMidViewer.d.ts +2 -2
  154. package/lib/components/viewers/TMTidViewer.d.ts +2 -2
  155. package/lib/helper/Enum_Localizator.js +1 -0
  156. package/lib/helper/SDKUI_Globals.d.ts +7 -2
  157. package/lib/helper/SDKUI_Globals.js +7 -2
  158. package/lib/helper/SDKUI_Localizator.d.ts +31 -6
  159. package/lib/helper/SDKUI_Localizator.js +301 -51
  160. package/lib/helper/TMAppUpdatedModal.d.ts +1 -2
  161. package/lib/helper/TMAppUpdatedModal.js +93 -93
  162. package/lib/helper/TMCommandsContextMenu.d.ts +1 -1
  163. package/lib/helper/TMIcons.d.ts +280 -280
  164. package/lib/helper/TMPdfViewer.d.ts +1 -2
  165. package/lib/helper/TMToppyMessage.d.ts +2 -2
  166. package/lib/helper/TMUtils.d.ts +4 -10
  167. package/lib/helper/ZipManager.d.ts +1 -1
  168. package/lib/helper/ZipManager.js +2 -1
  169. package/lib/helper/dcmtsHelper.d.ts +2 -0
  170. package/lib/helper/dcmtsHelper.js +3 -1
  171. package/lib/helper/helpers.d.ts +1 -1
  172. package/lib/hooks/useCheckInOutOperations.d.ts +0 -6
  173. package/lib/hooks/useCheckInOutOperations.js +14 -34
  174. package/lib/hooks/useDcmtOperations.d.ts +3 -19
  175. package/lib/hooks/useDcmtOperations.js +174 -227
  176. package/lib/hooks/useDocumentOperations.d.ts +1 -0
  177. package/lib/hooks/useDocumentOperations.js +14 -25
  178. package/lib/hooks/useInputDialog.d.ts +1 -2
  179. package/lib/hooks/useMultiMasterDetailDcmts.d.ts +0 -15
  180. package/lib/hooks/useMultiMasterDetailDcmts.js +70 -68
  181. package/lib/hooks/usePreventFileDrop.js +9 -0
  182. package/lib/hooks/useWorkflowApprove.js +33 -17
  183. package/lib/services/caseflow/CaseFlowService.d.ts +69 -9
  184. package/lib/services/caseflow/CaseFlowService.js +126 -58
  185. package/lib/services/platform_services.d.ts +2 -3
  186. package/package.json +2 -2
@@ -0,0 +1,1231 @@
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useCallback, useEffect, useRef, useState } from 'react';
3
+ import styled, { keyframes } from 'styled-components';
4
+ import { locale as dxLocale } from 'devextreme/localization';
5
+ import { CultureIDs, HolAskDescriptor, SDK_Globals, TopMediaServer } from '@topconsultnpm/sdk-ts';
6
+ import TMTooltip from '../../base/TMTooltip';
7
+ import { TMColors } from '../../../utils/theme';
8
+ import { SDKUI_Localizator } from '../../../helper';
9
+ import ToppyImage from '../../../assets/Toppy-help-center.png';
10
+ const generateGUID = () => {
11
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replaceAll(/[xy]/g, (c) => {
12
+ const r = Math.trunc(Math.random() * 16);
13
+ const v = c === 'x' ? r : (r & 0x3 | 0x8);
14
+ return v.toString(16);
15
+ });
16
+ };
17
+ const PANEL_DEFAULT_WIDTH = 600;
18
+ const PANEL_MIN_WIDTH = 340;
19
+ const PANEL_MAX_WIDTH = 900;
20
+ const FEEDBACK_MAX_LENGTH = 200;
21
+ const NO_ANSWER_TEXT = 'Nessuna risposta ricevuta.';
22
+ const ERROR_TEXT = 'Si è verificato un errore, riprova più tardi.';
23
+ const FEEDBACK_TAGS = {
24
+ like: ['Aggiornata', 'Accurata', 'Utile', 'Pertinente', 'Fonti affidabili', 'Altro'],
25
+ dislike: ['Non aggiornata', 'Imprecisa', 'Troppo lunga', 'Troppo corta', 'Fonti non affidabili', 'Inappropriata', 'Altro'],
26
+ };
27
+ const FEEDBACK_TITLES = {
28
+ like: 'Cosa ti è piaciuto di questa risposta?',
29
+ dislike: 'Cosa non ha funzionato in questa risposta?',
30
+ };
31
+ const copyToClipboard = async (text) => {
32
+ try {
33
+ if (globalThis.isSecureContext && navigator.clipboard?.writeText) {
34
+ await navigator.clipboard.writeText(text);
35
+ return true;
36
+ }
37
+ const textarea = document.createElement('textarea');
38
+ textarea.value = text;
39
+ textarea.setAttribute('readonly', '');
40
+ textarea.style.position = 'fixed';
41
+ textarea.style.opacity = '0';
42
+ document.body.appendChild(textarea);
43
+ textarea.select();
44
+ const copied = document.execCommand('copy');
45
+ document.body.removeChild(textarea);
46
+ return copied;
47
+ }
48
+ catch {
49
+ return false;
50
+ }
51
+ };
52
+ const getSafeSession = () => {
53
+ try {
54
+ return SDK_Globals.tmSession;
55
+ }
56
+ catch {
57
+ return undefined;
58
+ }
59
+ };
60
+ const DX_LOCALE_TO_CULTURE_ID = {
61
+ de: CultureIDs.De_DE,
62
+ en: CultureIDs.En_US,
63
+ es: CultureIDs.Es_ES,
64
+ fr: CultureIDs.Fr_FR,
65
+ it: CultureIDs.It_IT,
66
+ pt: CultureIDs.Pt_PT,
67
+ };
68
+ const getCurrentCultureId = () => DX_LOCALE_TO_CULTURE_ID[dxLocale().split('-')[0]] ?? getSafeSession()?.SessionDescr?.cultureID;
69
+ let preLoginSession;
70
+ let preLoginSessionUrl;
71
+ const getPreLoginSession = (endpointUrl) => {
72
+ if (!endpointUrl) {
73
+ return undefined;
74
+ }
75
+ if (!preLoginSession || preLoginSessionUrl !== endpointUrl) {
76
+ const tmServer = new TopMediaServer(endpointUrl);
77
+ preLoginSession = tmServer.NewSession();
78
+ preLoginSessionUrl = endpointUrl;
79
+ }
80
+ return preLoginSession;
81
+ };
82
+ const TMHelpOnLineChat = ({ isOpen, showChatButton, isLogged, messages, conversationId, isThinking, endpointUrl, onClose, onToggle, onNewConversation, onAddMessage, onSetThinking, onSetConversationId }) => {
83
+ const [width, setWidth] = useState(PANEL_DEFAULT_WIDTH);
84
+ const showFab = !isLogged && showChatButton && !isOpen;
85
+ const [submittedRatings, setSubmittedRatings] = useState({});
86
+ const onFeedbackSubmitted = useCallback((messageId, rating) => {
87
+ setSubmittedRatings(prev => ({ ...prev, [messageId]: rating }));
88
+ }, []);
89
+ return (_jsxs(_Fragment, { children: [isOpen && (_jsxs(_Fragment, { children: [_jsx(Overlay, { onClick: onClose }), _jsx(ChatPanel, { width: width, onWidthChange: setWidth, messages: messages, conversationId: conversationId, isThinking: isThinking, endpointUrl: endpointUrl, onClose: onClose, onNewConversation: onNewConversation, onAddMessage: onAddMessage, onSetThinking: onSetThinking, onSetConversationId: onSetConversationId, isLogged: isLogged, submittedRatings: submittedRatings, onFeedbackSubmitted: onFeedbackSubmitted })] })), showFab && (_jsx(Fab, { onClick: onToggle, title: "Chiedi a Toppy", "aria-label": "Chiedi a Toppy", children: _jsx(FabAvatar, { src: ToppyImage, alt: "Toppy" }) }))] }));
90
+ };
91
+ export default TMHelpOnLineChat;
92
+ //#region Header button
93
+ export const TMToppyHeaderButton = ({ showChatButton, onToggle }) => {
94
+ if (!showChatButton)
95
+ return null;
96
+ return (_jsx(TMTooltip, { content: "Chiedi a Toppy", children: _jsxs(ToppyHeaderButton, { onClick: onToggle, title: "Chiedi a Toppy", children: [_jsx(ToppyHeaderAvatar, { src: ToppyImage, alt: "Toppy" }), _jsx(ToppyHeaderText, { children: "Chiedi a Toppy" })] }) }));
97
+ };
98
+ const ChatPanel = ({ width, onWidthChange, messages, conversationId, isThinking, endpointUrl, onClose, onNewConversation, onAddMessage, onSetThinking, onSetConversationId, isLogged, submittedRatings, onFeedbackSubmitted }) => {
99
+ const [chatInput, setChatInput] = useState('');
100
+ const inputRef = useRef(null);
101
+ const messagesEndRef = useRef(null);
102
+ const onCloseRef = useRef(onClose);
103
+ onCloseRef.current = onClose;
104
+ const userName = getSafeSession()?.SessionDescr?.userName ?? '';
105
+ useEffect(() => {
106
+ messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
107
+ }, [messages, isThinking]);
108
+ useEffect(() => {
109
+ inputRef.current?.focus();
110
+ }, []);
111
+ useEffect(() => {
112
+ const onKeyDown = (e) => {
113
+ if (e.key === 'Escape')
114
+ onCloseRef.current();
115
+ };
116
+ window.addEventListener('keydown', onKeyDown);
117
+ return () => window.removeEventListener('keydown', onKeyDown);
118
+ }, []);
119
+ const onResizeStart = useCallback((e) => {
120
+ e.preventDefault();
121
+ const startX = e.clientX;
122
+ const startWidth = width;
123
+ const onMove = (ev) => {
124
+ const next = startWidth + (startX - ev.clientX);
125
+ const max = Math.min(PANEL_MAX_WIDTH, globalThis.innerWidth - 40);
126
+ onWidthChange(Math.min(Math.max(next, PANEL_MIN_WIDTH), max));
127
+ };
128
+ const onUp = () => {
129
+ document.body.style.userSelect = '';
130
+ document.body.style.cursor = '';
131
+ globalThis.removeEventListener('mousemove', onMove);
132
+ globalThis.removeEventListener('mouseup', onUp);
133
+ };
134
+ document.body.style.userSelect = 'none';
135
+ document.body.style.cursor = 'col-resize';
136
+ globalThis.addEventListener('mousemove', onMove);
137
+ globalThis.addEventListener('mouseup', onUp);
138
+ }, [width, onWidthChange]);
139
+ const askHandler = useCallback(async () => {
140
+ const question = chatInput.trim();
141
+ if (question.length < 2 || isThinking) {
142
+ return;
143
+ }
144
+ onAddMessage({ id: generateGUID(), text: question, isUser: true });
145
+ setChatInput('');
146
+ onSetThinking(true);
147
+ let convId = conversationId;
148
+ if (!convId) {
149
+ convId = generateGUID();
150
+ onSetConversationId(convId);
151
+ }
152
+ try {
153
+ const globalSession = getSafeSession();
154
+ const preSession = globalSession ? undefined : getPreLoginSession(endpointUrl);
155
+ const session = globalSession ?? preSession;
156
+ let answer = '';
157
+ if (session) {
158
+ const hol_d = new HolAskDescriptor();
159
+ hol_d.question = question;
160
+ hol_d.conversationId = convId;
161
+ const raw = await session.HelpOnLineAskAsync(hol_d);
162
+ const parsed = typeof raw === 'string' ? safeJsonParse(raw) : raw;
163
+ if (parsed && typeof parsed === 'object') {
164
+ answer = parsed.answer ?? '';
165
+ }
166
+ else if (typeof raw === 'string') {
167
+ answer = raw;
168
+ }
169
+ }
170
+ else {
171
+ console.error('[HOL] NO SESSION -> nothing called. endpointUrl =', endpointUrl);
172
+ }
173
+ onAddMessage({ id: generateGUID(), text: answer || NO_ANSWER_TEXT, isUser: false });
174
+ }
175
+ catch (error) {
176
+ onAddMessage({ id: generateGUID(), text: ERROR_TEXT, isUser: false });
177
+ console.error('[HOL]', error);
178
+ }
179
+ finally {
180
+ onSetThinking(false);
181
+ }
182
+ }, [chatInput, conversationId, isThinking, endpointUrl, onAddMessage, onSetThinking, onSetConversationId]);
183
+ const onFeedbackSubmit = (index, rating, tags, feedback) => {
184
+ const answer = messages[index];
185
+ const question = messages.slice(0, index).reverse().find(m => m.isUser)?.text ?? '';
186
+ const session = getSafeSession();
187
+ console.log('[HOL] feedback', {
188
+ userName: session?.SessionDescr?.userName ?? '',
189
+ app: isLogged ? SDK_Globals.appModule : 'LOGIN',
190
+ cultureId: getCurrentCultureId(),
191
+ question,
192
+ answer: answer.text,
193
+ rating,
194
+ tags,
195
+ feedback,
196
+ conversationId,
197
+ timestamp: new Date().toISOString(),
198
+ });
199
+ onFeedbackSubmitted(answer.id, rating);
200
+ };
201
+ return (_jsxs(PanelContainer, { $width: width, children: [_jsx(ResizeHandle, { onMouseDown: onResizeStart }), _jsxs(ChatHeader, { children: [_jsxs(HeaderLeft, { children: [_jsx(ToppyAvatar, { src: ToppyImage, alt: "Toppy" }), _jsxs(HeaderText, { children: [_jsxs(HeaderGreeting, { children: ["Ciao ", userName] }), _jsx(HeaderQuestion, { children: "Come posso aiutarti?" })] })] }), _jsxs(HeaderRight, { children: [_jsx(TMTooltip, { content: "Nuova conversazione", children: _jsx(HeaderButton, { onClick: onNewConversation, disabled: !conversationId && messages.length === 0, title: "Nuova conversazione", children: _jsx(IconNewChat, { color: "white", fontSize: 18 }) }) }), _jsx(TMTooltip, { content: "Chiudi", children: _jsx(HeaderButton, { onClick: onClose, title: "Chiudi", children: _jsx(IconClose, { fontSize: 18 }) }) })] })] }), _jsxs(ChatBody, { children: [messages.length === 0 ? (_jsxs(WelcomeMessage, { children: [_jsx(WelcomeIcon, { children: "\uD83D\uDCA1" }), _jsxs(WelcomeText, { children: ["Ciao! Sono ", _jsx("strong", { children: "Toppy" }), ", il tuo assistente.", _jsx("br", {}), "Fai una domanda e ti aiuter\u00F2 a trovare la risposta."] })] })) : (messages.map((msg, index) => (_jsxs(MessageBubble, { $isUser: msg.isUser, children: [!msg.isUser && _jsx(BotAvatar, { src: ToppyImage, alt: "Toppy" }), msg.isUser ? (_jsxs(_Fragment, { children: [_jsx(QuestionCopy, { children: _jsx(CopyButton, { text: msg.text }) }), _jsx(MessageContent, { $isUser: true, children: msg.text })] })) : (_jsxs(BotMessageColumn, { children: [_jsx(BotMessageContent, { $isUser: false, children: _jsx(MarkdownContent, { children: renderMarkdown(msg.text) }) }), msg.text !== NO_ANSWER_TEXT && msg.text !== ERROR_TEXT && (_jsx(MessageFeedback, { answer: msg.text, submittedRating: submittedRatings[msg.id], onSubmit: (rating, tags, feedback) => onFeedbackSubmit(index, rating, tags, feedback) }))] }))] }, msg.id)))), isThinking && (_jsxs(MessageBubble, { $isUser: false, children: [_jsx(BotAvatar, { src: ToppyImage, alt: "Toppy" }), _jsx(ThinkingStatus, {}, messages.length)] })), _jsx("div", { ref: messagesEndRef })] }), _jsxs(ChatFooter, { children: [_jsx(TMChatInput, { inputRef: inputRef, value: chatInput, onChange: setChatInput, onSend: askHandler, placeholder: "Scrivi la tua domanda...", tooltip: "Invia", disabled: isThinking }), _jsx(FooterHint, { children: SDKUI_Localizator.HelpOnLineShiftEnterHint })] })] }));
202
+ };
203
+ const TMChatInput = ({ value, onChange, onSend, placeholder = 'Scrivi la tua domanda...', disabled = false, inputRef, tooltip = 'Ricerca AI' }) => {
204
+ const isDisabled = disabled || value.length < 2;
205
+ return (_jsxs(ChatInputWrapper, { children: [_jsx(ChatInputTextarea, { ref: inputRef, placeholder: placeholder, value: value, onChange: (e) => onChange(e.target.value), onKeyDown: (e) => {
206
+ if (e.key !== 'Enter')
207
+ return;
208
+ e.stopPropagation();
209
+ if (!e.shiftKey && !e.nativeEvent.isComposing) {
210
+ e.preventDefault();
211
+ if (!isDisabled)
212
+ onSend();
213
+ }
214
+ } }), _jsx(TMTooltip, { content: tooltip, children: _jsx(InlineSendButton, { $disabled: isDisabled, disabled: isDisabled, onClick: onSend, title: tooltip, children: _jsx(IconSendFilled, { fontSize: 20 }) }) })] }));
215
+ };
216
+ const CopyButton = ({ text }) => {
217
+ const [copied, setCopied] = useState(false);
218
+ const copiedTimerRef = useRef();
219
+ useEffect(() => () => clearTimeout(copiedTimerRef.current), []);
220
+ const onCopyClick = async () => {
221
+ if (!(await copyToClipboard(text)))
222
+ return;
223
+ setCopied(true);
224
+ clearTimeout(copiedTimerRef.current);
225
+ copiedTimerRef.current = setTimeout(() => setCopied(false), 2000);
226
+ };
227
+ return (_jsx(TMTooltip, { content: copied ? 'Copiato' : 'Copia', children: _jsx(FeedbackActionButton, { type: "button", $active: false, $locked: false, $success: copied, "aria-label": "Copia", onClick: onCopyClick, children: copied ? _jsx(IconCheck, { fontSize: 16 }) : _jsx(IconCopy, { fontSize: 16 }) }) }));
228
+ };
229
+ const MessageFeedback = ({ answer, submittedRating, onSubmit }) => {
230
+ const [draftRating, setDraftRating] = useState(undefined);
231
+ const [selectedTags, setSelectedTags] = useState([]);
232
+ const [feedback, setFeedback] = useState('');
233
+ const panelRef = useRef(null);
234
+ useEffect(() => {
235
+ if (draftRating)
236
+ panelRef.current?.scrollIntoView({ block: 'nearest', behavior: 'smooth' });
237
+ }, [draftRating]);
238
+ const isSubmitted = submittedRating !== undefined;
239
+ const activeRating = submittedRating ?? draftRating;
240
+ const canSubmit = draftRating === 'like' || selectedTags.length > 0 || feedback.trim().length > 0;
241
+ const resetDraft = () => {
242
+ setDraftRating(undefined);
243
+ setSelectedTags([]);
244
+ setFeedback('');
245
+ };
246
+ const onRatingClick = (rating) => {
247
+ if (isSubmitted)
248
+ return;
249
+ if (draftRating === rating) {
250
+ resetDraft();
251
+ return;
252
+ }
253
+ setDraftRating(rating);
254
+ setSelectedTags([]);
255
+ };
256
+ const onTagClick = (tag) => {
257
+ setSelectedTags(prev => prev.includes(tag) ? prev.filter(t => t !== tag) : [...prev, tag]);
258
+ };
259
+ const onSubmitClick = () => {
260
+ if (!draftRating || !canSubmit)
261
+ return;
262
+ onSubmit(draftRating, selectedTags, feedback.trim());
263
+ resetDraft();
264
+ };
265
+ return (_jsxs(FeedbackContainer, { children: [_jsxs(FeedbackActions, { children: [_jsx(CopyButton, { text: answer }), isSubmitted && (_jsxs(SentBadge, { role: "status", children: [_jsx(IconCheck, { fontSize: 12 }), "Inviato"] }))] }), !isSubmitted && draftRating && (_jsxs(FeedbackPanel, { ref: panelRef, children: [_jsxs(FeedbackPanelHeader, { children: [_jsx(FeedbackPanelTitle, { children: FEEDBACK_TITLES[draftRating] }), _jsx(FeedbackCloseButton, { type: "button", "aria-label": "Chiudi", title: "Chiudi", onClick: resetDraft, children: _jsx(IconClose, { fontSize: 16 }) })] }), _jsx(FeedbackLabel, { children: "Era..." }), _jsx(FeedbackTags, { children: FEEDBACK_TAGS[draftRating].map(tag => (_jsx(FeedbackTag, { type: "button", $selected: selectedTags.includes(tag), "aria-pressed": selectedTags.includes(tag), onClick: () => onTagClick(tag), children: tag }, tag))) }), _jsx(FeedbackLabel, { children: "Feedback aggiuntivo" }), _jsx(FeedbackTextarea, { value: feedback, maxLength: FEEDBACK_MAX_LENGTH, placeholder: "Raccontaci di pi\u00F9", onChange: (e) => setFeedback(e.target.value.slice(0, FEEDBACK_MAX_LENGTH)), onKeyDown: (e) => { if (e.key === 'Enter')
266
+ e.stopPropagation(); } }), _jsxs(FeedbackPanelFooter, { children: [_jsxs(FeedbackCounter, { $full: feedback.length >= FEEDBACK_MAX_LENGTH, children: [feedback.length, "/", FEEDBACK_MAX_LENGTH] }), _jsx(FeedbackSubmitButton, { type: "button", disabled: !canSubmit, onClick: onSubmitClick, children: "Invia" })] })] }, draftRating))] }));
267
+ };
268
+ //#endregion
269
+ //#region Thinking status (phrases + elapsed seconds)
270
+ const getThinkingPhrases = () => [
271
+ { at: 0, text: SDKUI_Localizator.HelpOnLineThinking01 },
272
+ { at: 3, text: SDKUI_Localizator.HelpOnLineThinking02 },
273
+ { at: 7, text: SDKUI_Localizator.HelpOnLineThinking03 },
274
+ { at: 12, text: SDKUI_Localizator.HelpOnLineThinking04 },
275
+ { at: 18, text: SDKUI_Localizator.HelpOnLineThinking05 },
276
+ { at: 25, text: SDKUI_Localizator.HelpOnLineThinking06 },
277
+ { at: 33, text: SDKUI_Localizator.HelpOnLineThinking07 },
278
+ { at: 42, text: SDKUI_Localizator.HelpOnLineThinking08 },
279
+ { at: 55, text: SDKUI_Localizator.HelpOnLineThinking09 },
280
+ { at: 70, text: SDKUI_Localizator.HelpOnLineThinking10 },
281
+ ];
282
+ const COUNTER_VISIBLE_FROM = 2;
283
+ const getPhraseIndex = (seconds, phrases) => {
284
+ let index = 0;
285
+ for (let i = 1; i < phrases.length; i++) {
286
+ if (seconds < phrases[i].at)
287
+ break;
288
+ index = i;
289
+ }
290
+ return index;
291
+ };
292
+ const formatElapsed = (seconds) => seconds < 60 ? `${seconds}s` : `${Math.floor(seconds / 60)}:${String(seconds % 60).padStart(2, '0')}`;
293
+ const ThinkingStatus = () => {
294
+ const [seconds, setSeconds] = useState(0);
295
+ useEffect(() => {
296
+ const startedAt = performance.now();
297
+ const intervalId = globalThis.setInterval(() => {
298
+ setSeconds(Math.floor((performance.now() - startedAt) / 1000));
299
+ }, 1000);
300
+ return () => globalThis.clearInterval(intervalId);
301
+ }, []);
302
+ const phrases = getThinkingPhrases();
303
+ const phraseIndex = getPhraseIndex(seconds, phrases);
304
+ return (_jsx(ThinkingIndicator, { children: _jsxs(ThinkingCaption, { children: [_jsxs(ThinkingPhrase, { role: "status", "aria-live": "polite", children: [phrases[phraseIndex].text, _jsxs(ThinkingDots, { "aria-hidden": "true", children: [_jsx(ThinkingDot, { $delay: 0, children: "." }), _jsx(ThinkingDot, { $delay: 0.2, children: "." }), _jsx(ThinkingDot, { $delay: 0.4, children: "." })] })] }, phraseIndex), _jsx(ThinkingCounter, { $visible: seconds >= COUNTER_VISIBLE_FROM, "aria-hidden": "true", children: formatElapsed(seconds) })] }) }));
305
+ };
306
+ //#endregion
307
+ //#region Markdown rendering (no third-party library)
308
+ const safeJsonParse = (value) => {
309
+ try {
310
+ return JSON.parse(value);
311
+ }
312
+ catch {
313
+ return value;
314
+ }
315
+ };
316
+ const renderInline = (text, keyPrefix) => {
317
+ const nodes = [];
318
+ const pattern = /(\*\*([^*]+)\*\*)|(~~([^~]+)~~)|(`([^`]+)`)|(\[([^\]]+)\]\(([^)]+)\))|(\*([^*\n]+)\*)|(_([^_\n]+)_)/g;
319
+ let lastIndex = 0;
320
+ let match;
321
+ let i = 0;
322
+ while ((match = pattern.exec(text)) !== null) {
323
+ if (match.index > lastIndex)
324
+ nodes.push(text.slice(lastIndex, match.index));
325
+ const key = `${keyPrefix}-${i}`;
326
+ if (match[2] !== undefined) {
327
+ nodes.push(_jsx("strong", { children: renderInline(match[2], key) }, key));
328
+ }
329
+ else if (match[4] !== undefined) {
330
+ nodes.push(_jsx("s", { children: renderInline(match[4], key) }, key));
331
+ }
332
+ else if (match[6] !== undefined) {
333
+ nodes.push(_jsx(MdCode, { children: match[6] }, key));
334
+ }
335
+ else if (match[8] !== undefined) {
336
+ nodes.push(_jsx("a", { href: match[9], target: "_blank", rel: "noopener noreferrer", children: match[8] }, key));
337
+ }
338
+ else if (match[11] !== undefined) {
339
+ nodes.push(_jsx("em", { children: match[11] }, key));
340
+ }
341
+ else if (match[13] !== undefined) {
342
+ nodes.push(_jsx("em", { children: match[13] }, key));
343
+ }
344
+ lastIndex = pattern.lastIndex;
345
+ i++;
346
+ }
347
+ if (lastIndex < text.length)
348
+ nodes.push(text.slice(lastIndex));
349
+ return nodes;
350
+ };
351
+ const splitTableCells = (row) => {
352
+ let s = row.trim();
353
+ if (s.startsWith('|'))
354
+ s = s.slice(1);
355
+ if (s.endsWith('|') && !s.endsWith('\\|'))
356
+ s = s.slice(0, -1);
357
+ const cells = [];
358
+ let cur = '';
359
+ for (let i = 0; i < s.length; i++) {
360
+ if (s[i] === '\\' && s[i + 1] === '|') {
361
+ cur += '|';
362
+ i++;
363
+ continue;
364
+ }
365
+ if (s[i] === '|') {
366
+ cells.push(cur.trim());
367
+ cur = '';
368
+ continue;
369
+ }
370
+ cur += s[i];
371
+ }
372
+ cells.push(cur.trim());
373
+ return cells;
374
+ };
375
+ const isTableSeparator = (line) => {
376
+ if (!line?.includes('-'))
377
+ return false;
378
+ const cells = splitTableCells(line);
379
+ return cells.length > 0 && cells.every(c => /^:?-+:?$/.test(c));
380
+ };
381
+ const getCellAlign = (sep) => {
382
+ const left = sep.startsWith(':');
383
+ const right = sep.endsWith(':');
384
+ if (left && right)
385
+ return 'center';
386
+ if (right)
387
+ return 'right';
388
+ if (left)
389
+ return 'left';
390
+ return undefined;
391
+ };
392
+ //#endregion
393
+ const startsBlock = (lines, idx) => {
394
+ const line = lines[idx];
395
+ if (line.trim() === '')
396
+ return true;
397
+ if (line.trim().startsWith('```'))
398
+ return true;
399
+ if (/^#{1,6}\s+/.test(line))
400
+ return true;
401
+ if (/^\s*[-*+]\s+/.test(line))
402
+ return true;
403
+ if (/^\s*\d+\.\s+/.test(line))
404
+ return true;
405
+ if (/^\s*>\s?/.test(line))
406
+ return true;
407
+ if (/^\s*(-{3,}|\*{3,}|_{3,})\s*$/.test(line))
408
+ return true;
409
+ if (line.includes('|') && isTableSeparator(lines[idx + 1]))
410
+ return true;
411
+ return false;
412
+ };
413
+ const renderMarkdown = (raw) => {
414
+ const lines = raw.replace(/\r\n/g, '\n').split('\n');
415
+ const blocks = [];
416
+ let i = 0;
417
+ let key = 0;
418
+ while (i < lines.length) {
419
+ const line = lines[i];
420
+ if (line.trim().startsWith('```')) {
421
+ const codeLines = [];
422
+ i++;
423
+ while (i < lines.length && !lines[i].trim().startsWith('```')) {
424
+ codeLines.push(lines[i]);
425
+ i++;
426
+ }
427
+ i++;
428
+ blocks.push(_jsx(MdPre, { children: codeLines.join('\n') }, `b-${key++}`));
429
+ continue;
430
+ }
431
+ if (line.includes('|') && isTableSeparator(lines[i + 1])) {
432
+ const headers = splitTableCells(line);
433
+ const aligns = splitTableCells(lines[i + 1]).map(getCellAlign);
434
+ i += 2;
435
+ const rows = [];
436
+ while (i < lines.length && lines[i].trim() !== '' && lines[i].includes('|')) {
437
+ rows.push(splitTableCells(lines[i]));
438
+ i++;
439
+ }
440
+ const tKey = key++;
441
+ blocks.push(_jsx(MdTableWrapper, { children: _jsxs(MdTable, { children: [_jsx("thead", { children: _jsx("tr", { children: headers.map((cell, ci) => (_jsx(MdTh, { $align: aligns[ci], children: renderInline(cell, `th-${tKey}-${ci}`) }, `th-${tKey}-${ci}`))) }) }), _jsx("tbody", { children: rows.map((row, ri) => (_jsx("tr", { children: headers.map((_, ci) => (_jsx(MdTd, { $align: aligns[ci], children: renderInline(row[ci] ?? '', `td-${tKey}-${ri}-${ci}`) }, `td-${tKey}-${ri}-${ci}`))) }, `tr-${tKey}-${ri}`))) })] }) }, `b-${tKey}`));
442
+ continue;
443
+ }
444
+ if (/^\s*(-{3,}|\*{3,}|_{3,})\s*$/.test(line)) {
445
+ blocks.push(_jsx(MdHr, {}, `b-${key++}`));
446
+ i++;
447
+ continue;
448
+ }
449
+ if (/^\s*>\s?/.test(line)) {
450
+ const quoteLines = [];
451
+ while (i < lines.length && /^\s*>\s?/.test(lines[i])) {
452
+ quoteLines.push(lines[i].replace(/^\s*>\s?/, ''));
453
+ i++;
454
+ }
455
+ blocks.push(_jsx(MdBlockquote, { children: renderMarkdown(quoteLines.join('\n')) }, `b-${key++}`));
456
+ continue;
457
+ }
458
+ const heading = line.match(/^(#{1,6})\s+(.*)$/);
459
+ if (heading) {
460
+ const level = heading[1].length;
461
+ blocks.push(_jsx(MdHeading, { $level: level, children: renderInline(heading[2], `h-${key}`) }, `b-${key}`));
462
+ key++;
463
+ i++;
464
+ continue;
465
+ }
466
+ if (/^\s*[-*+]\s+/.test(line)) {
467
+ const items = [];
468
+ while (i < lines.length && /^\s*[-*+]\s+/.test(lines[i])) {
469
+ const content = lines[i].replace(/^\s*[-*+]\s+/, '');
470
+ items.push(_jsx("li", { children: renderInline(content, `li-${key}-${items.length}`) }, `li-${key}-${items.length}`));
471
+ i++;
472
+ }
473
+ blocks.push(_jsx(MdUl, { children: items }, `b-${key++}`));
474
+ continue;
475
+ }
476
+ if (/^\s*\d+\.\s+/.test(line)) {
477
+ const items = [];
478
+ while (i < lines.length && /^\s*\d+\.\s+/.test(lines[i])) {
479
+ const content = lines[i].replace(/^\s*\d+\.\s+/, '');
480
+ items.push(_jsx("li", { children: renderInline(content, `oi-${key}-${items.length}`) }, `oi-${key}-${items.length}`));
481
+ i++;
482
+ }
483
+ blocks.push(_jsx(MdOl, { children: items }, `b-${key++}`));
484
+ continue;
485
+ }
486
+ if (line.trim() === '') {
487
+ i++;
488
+ continue;
489
+ }
490
+ const paraLines = [];
491
+ while (i < lines.length && !startsBlock(lines, i)) {
492
+ paraLines.push(lines[i]);
493
+ i++;
494
+ }
495
+ const paraNodes = paraLines.flatMap((pl, idx) => {
496
+ const inline = renderInline(pl, `p-${key}-${idx}`);
497
+ return idx === 0 ? inline : [_jsx("br", {}, `br-${key}-${idx}`), ...inline];
498
+ });
499
+ blocks.push(_jsx(MdParagraph, { children: paraNodes }, `b-${key++}`));
500
+ }
501
+ return blocks;
502
+ };
503
+ //#endregion
504
+ //#region Icons
505
+ function IconClose(props) {
506
+ return (_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", width: "1em", height: "1em", fill: "currentColor", ...props, children: _jsx("path", { d: "M18.3 5.71 12 12.01l-6.3-6.3-1.41 1.41 6.3 6.3-6.3 6.3 1.41 1.41 6.3-6.3 6.3 6.3 1.41-1.41-6.3-6.3 6.3-6.3z" }) }));
507
+ }
508
+ function IconSendFilled(props) {
509
+ return (_jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 16 16", width: "1em", height: "1em", ...props, children: [_jsx("defs", { children: _jsx("path", { id: "lsiconSendFilled0", d: "M12.97 2.67a.5.5 0 0 0-.64-.64l-11 4a.5.5 0 0 0-.016.934l4.433 1.773l2.9-3.09l.707.707l-2.98 3.176l1.662 4.156a.5.5 0 0 0 .934-.015z" }) }), _jsxs("g", { fill: "currentColor", fillRule: "evenodd", clipRule: "evenodd", children: [_jsx("use", { href: "#lsiconSendFilled0" }), _jsx("use", { href: "#lsiconSendFilled0" })] })] }));
510
+ }
511
+ function IconNewChat(props) {
512
+ return (_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", width: "1em", height: "1em", fill: props.color || "currentColor", ...props, children: _jsx("path", { d: "M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H6l-2 2V4h16v12z" }) }));
513
+ }
514
+ function IconThumbUp(props) {
515
+ return (_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", width: "1em", height: "1em", fill: "currentColor", ...props, children: _jsx("path", { d: "M9 21h9c.83 0 1.54-.5 1.84-1.22l3.02-7.05c.09-.23.14-.47.14-.73v-2c0-1.1-.9-2-2-2h-6.31l.95-4.57.03-.32c0-.41-.17-.79-.44-1.06L14.17 1 7.58 7.59C7.22 7.95 7 8.45 7 9v10c0 1.1.9 2 2 2zM9 9l4.34-4.34L12 10h9v2l-3 7H9V9zM1 9h4v12H1z" }) }));
516
+ }
517
+ function IconCopy(props) {
518
+ return (_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", width: "1em", height: "1em", fill: "currentColor", ...props, children: _jsx("path", { d: "M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z" }) }));
519
+ }
520
+ function IconCheck(props) {
521
+ return (_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", width: "1em", height: "1em", fill: "currentColor", ...props, children: _jsx("path", { d: "M9 16.17 4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z" }) }));
522
+ }
523
+ //#endregion
524
+ //#region Styled Components
525
+ const fadeIn = keyframes `
526
+ from { opacity: 0; }
527
+ to { opacity: 1; }
528
+ `;
529
+ const slideInRight = keyframes `
530
+ from { transform: translateX(100%); }
531
+ to { transform: translateX(0); }
532
+ `;
533
+ const phraseIn = keyframes `
534
+ from { opacity: 0; transform: translateY(4px); }
535
+ to { opacity: 1; transform: translateY(0); }
536
+ `;
537
+ const feedbackIn = keyframes `
538
+ from { opacity: 0; transform: translateY(-4px); }
539
+ to { opacity: 1; transform: translateY(0); }
540
+ `;
541
+ const badgeIn = keyframes `
542
+ 0% { opacity: 0; transform: scale(0.85); }
543
+ 60% { opacity: 1; transform: scale(1.05); }
544
+ 100% { opacity: 1; transform: scale(1); }
545
+ `;
546
+ const dotCycle = keyframes `
547
+ 0% { opacity: 0; }
548
+ 25%, 75% { opacity: 1; }
549
+ 100% { opacity: 0; }
550
+ `;
551
+ const ToppyHeaderButton = styled.button `
552
+ display: flex;
553
+ align-items: center;
554
+ gap: 8px;
555
+ height: 36px;
556
+ padding: 0 14px 0 5px;
557
+ border-radius: 18px;
558
+ border: 1px solid ${TMColors.primary}35;
559
+ background: ${TMColors.primary}0d;
560
+ color: ${TMColors.primary};
561
+ font-size: 13px;
562
+ font-weight: 600;
563
+ white-space: nowrap;
564
+ cursor: pointer;
565
+ flex-shrink: 0;
566
+ transition: all 0.2s ease;
567
+
568
+ &:hover {
569
+ background: ${TMColors.primary}1a;
570
+ border-color: ${TMColors.primary}66;
571
+ transform: translateY(-1px);
572
+ box-shadow: 0 4px 12px ${TMColors.primary}25;
573
+ }
574
+ &:active { transform: translateY(0); }
575
+ `;
576
+ const ToppyHeaderAvatar = styled.img `
577
+ width: 28px;
578
+ height: 28px;
579
+ border-radius: 50%;
580
+ object-fit: contain;
581
+ pointer-events: none;
582
+ `;
583
+ const ToppyHeaderText = styled.span `
584
+ line-height: 1;
585
+ `;
586
+ const Fab = styled.button `
587
+ position: fixed;
588
+ bottom: 24px;
589
+ right: 24px;
590
+ width: 60px;
591
+ height: 60px;
592
+ border-radius: 50%;
593
+ border: none;
594
+ padding: 0;
595
+ cursor: pointer;
596
+ display: flex;
597
+ align-items: center;
598
+ justify-content: center;
599
+ background: white;
600
+ box-shadow: 0 6px 20px rgba(0, 0, 0, 0.25);
601
+ z-index: 100000;
602
+ transition: transform 0.2s ease, box-shadow 0.2s ease;
603
+ animation: ${fadeIn} 0.3s ease-out;
604
+
605
+ &:hover { transform: scale(1.08); box-shadow: 0 8px 26px rgba(0, 0, 0, 0.3); }
606
+ &:active { transform: scale(0.96); }
607
+ `;
608
+ const FabAvatar = styled.img `
609
+ width: 52px;
610
+ height: 52px;
611
+ border-radius: 50%;
612
+ object-fit: contain;
613
+ pointer-events: none;
614
+ `;
615
+ const Overlay = styled.div `
616
+ position: fixed;
617
+ inset: 0;
618
+ background: rgba(0, 0, 0, 0.45);
619
+ z-index: 100000;
620
+ animation: ${fadeIn} 0.2s ease-out;
621
+ `;
622
+ const PanelContainer = styled.div `
623
+ position: fixed;
624
+ top: 0;
625
+ right: 0;
626
+ height: 100vh;
627
+ width: ${props => props.$width}px;
628
+ max-width: 100vw;
629
+ background: white;
630
+ display: flex;
631
+ flex-direction: column;
632
+ box-shadow: -8px 0 32px rgba(0, 0, 0, 0.28);
633
+ z-index: 100001;
634
+ animation: ${slideInRight} 0.25s ease-out;
635
+ `;
636
+ const ResizeHandle = styled.div `
637
+ position: absolute;
638
+ left: 0;
639
+ top: 0;
640
+ bottom: 0;
641
+ width: 6px;
642
+ cursor: col-resize;
643
+ background: transparent;
644
+ z-index: 2;
645
+ transition: background 0.2s ease;
646
+
647
+ &:hover { background: ${TMColors.primary}55; }
648
+ `;
649
+ const ChatHeader = styled.div `
650
+ display: flex;
651
+ align-items: center;
652
+ justify-content: space-between;
653
+ padding: 16px 20px;
654
+ background: linear-gradient(135deg, ${TMColors.primary} 0%, ${TMColors.primary}dd 100%);
655
+ color: white;
656
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
657
+ `;
658
+ const HeaderLeft = styled.div `
659
+ display: flex;
660
+ align-items: center;
661
+ gap: 12px;
662
+ flex: 1;
663
+ min-width: 0;
664
+ `;
665
+ const HeaderRight = styled.div `
666
+ display: flex;
667
+ align-items: center;
668
+ gap: 8px;
669
+ margin-left: 12px;
670
+ flex-shrink: 0;
671
+ `;
672
+ const ToppyAvatar = styled.img `
673
+ width: 44px;
674
+ height: 44px;
675
+ border-radius: 50%;
676
+ background: white;
677
+ padding: 4px;
678
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
679
+ flex-shrink: 0;
680
+ object-fit: contain;
681
+ `;
682
+ const HeaderText = styled.div `
683
+ display: flex;
684
+ flex-direction: column;
685
+ gap: 2px;
686
+ min-width: 0;
687
+ `;
688
+ const HeaderGreeting = styled.h2 `
689
+ margin: 0;
690
+ font-size: 17px;
691
+ font-weight: 600;
692
+ color: white;
693
+ white-space: nowrap;
694
+ overflow: hidden;
695
+ text-overflow: ellipsis;
696
+ `;
697
+ const HeaderQuestion = styled.p `
698
+ margin: 0;
699
+ font-size: 13px;
700
+ color: rgba(255, 255, 255, 0.9);
701
+ `;
702
+ const HeaderButton = styled.button `
703
+ width: 32px;
704
+ height: 32px;
705
+ border-radius: 50%;
706
+ background: rgba(255, 255, 255, 0.2);
707
+ border: 1px solid rgba(255, 255, 255, 0.3);
708
+ color: white;
709
+ cursor: pointer;
710
+ display: flex;
711
+ align-items: center;
712
+ justify-content: center;
713
+ flex-shrink: 0;
714
+ transition: all 0.2s ease;
715
+
716
+ &:hover:not(:disabled) { background: rgba(255, 255, 255, 0.3); transform: scale(1.05); }
717
+ &:active:not(:disabled) { transform: scale(0.95); }
718
+ &:disabled { opacity: 0.45; cursor: default; }
719
+ `;
720
+ const ChatBody = styled.div `
721
+ flex: 1;
722
+ padding: 20px;
723
+ overflow-y: auto;
724
+ background: linear-gradient(to bottom, #f8f9fa 0%, #ffffff 100%);
725
+ `;
726
+ const WelcomeMessage = styled.div `
727
+ display: flex;
728
+ gap: 16px;
729
+ padding: 18px;
730
+ background: white;
731
+ border-radius: 12px;
732
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
733
+ border-left: 4px solid ${TMColors.primary};
734
+ animation: ${fadeIn} 0.5s ease-out;
735
+ `;
736
+ const WelcomeIcon = styled.div `
737
+ font-size: 30px;
738
+ flex-shrink: 0;
739
+ `;
740
+ const WelcomeText = styled.p `
741
+ margin: 0;
742
+ font-size: 14px;
743
+ line-height: 1.6;
744
+ color: #242424;
745
+
746
+ strong { color: ${TMColors.primary}; font-weight: 600; }
747
+ `;
748
+ const MessageBubble = styled.div `
749
+ display: flex;
750
+ gap: 10px;
751
+ margin-bottom: 16px;
752
+ align-items: flex-start;
753
+ justify-content: ${props => (props.$isUser ? 'flex-end' : 'flex-start')};
754
+ animation: ${fadeIn} 0.3s ease-out;
755
+ `;
756
+ const BotAvatar = styled.img `
757
+ width: 32px;
758
+ height: 32px;
759
+ border-radius: 50%;
760
+ background: white;
761
+ padding: 2px;
762
+ box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
763
+ flex-shrink: 0;
764
+ object-fit: contain;
765
+ `;
766
+ const MessageContent = styled.div `
767
+ max-width: 80%;
768
+ padding: 10px 14px;
769
+ border-radius: 12px;
770
+ font-size: 14px;
771
+ line-height: 1.5;
772
+ background: ${props => (props.$isUser ? TMColors.primary : '#f0f2f5')};
773
+ color: ${props => (props.$isUser ? 'white' : '#242424')};
774
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
775
+ word-wrap: break-word;
776
+ overflow-wrap: anywhere;
777
+ white-space: ${props => (props.$isUser ? 'pre-wrap' : 'normal')};
778
+ border-bottom-${props => (props.$isUser ? 'right' : 'left')}-radius: 4px;
779
+ `;
780
+ const BotMessageColumn = styled.div `
781
+ display: flex;
782
+ flex-direction: column;
783
+ align-items: flex-start;
784
+ width: 80%;
785
+ min-width: 0;
786
+ `;
787
+ const BotMessageContent = styled(MessageContent) `
788
+ max-width: 100%;
789
+ `;
790
+ const QuestionCopy = styled.div `
791
+ align-self: center;
792
+ flex-shrink: 0;
793
+ opacity: 0.55;
794
+ transition: opacity 0.2s ease;
795
+
796
+ ${MessageBubble}:hover &, &:focus-within {
797
+ opacity: 1;
798
+ }
799
+ `;
800
+ const FeedbackContainer = styled.div `
801
+ width: 100%;
802
+ margin-top: 4px;
803
+ `;
804
+ const FeedbackActions = styled.div `
805
+ display: flex;
806
+ align-items: center;
807
+ gap: 2px;
808
+ `;
809
+ const FeedbackActionButton = styled.button `
810
+ display: flex;
811
+ align-items: center;
812
+ justify-content: center;
813
+ width: 28px;
814
+ height: 28px;
815
+ padding: 0;
816
+ border-radius: 8px;
817
+ border: 1px solid ${props => (props.$active ? `${TMColors.primary}55` : 'transparent')};
818
+ background: ${props => (props.$active ? `${TMColors.primary}12` : 'transparent')};
819
+ color: ${props => (props.$success ? '#2e7d32' : props.$active ? TMColors.primary : '#8a8f98')};
820
+ cursor: ${props => (props.$locked ? 'default' : 'pointer')};
821
+ transition: background 0.2s ease, color 0.2s ease, border-color 0.2s ease;
822
+
823
+ &:hover:not(:disabled) {
824
+ background: ${props => (props.$active ? `${TMColors.primary}12` : 'rgba(0, 0, 0, 0.05)')};
825
+ color: ${props => (props.$success ? '#2e7d32' : props.$active ? TMColors.primary : '#242424')};
826
+ }
827
+
828
+ &:focus-visible {
829
+ outline: 2px solid ${TMColors.primary}55;
830
+ outline-offset: 1px;
831
+ }
832
+
833
+ &:disabled {
834
+ opacity: 0.35;
835
+ cursor: default;
836
+ }
837
+ `;
838
+ const SentBadge = styled.span `
839
+ display: inline-flex;
840
+ align-items: center;
841
+ gap: 4px;
842
+ margin-left: 6px;
843
+ padding: 3px 9px 3px 7px;
844
+ border-radius: 999px;
845
+ background: #e8f5e9;
846
+ border: 1px solid #c8e6c9;
847
+ color: #2e7d32;
848
+ font-size: 11px;
849
+ font-weight: 600;
850
+ line-height: 1;
851
+ letter-spacing: 0.02em;
852
+ animation: ${badgeIn} 0.35s ease-out;
853
+
854
+ @media (prefers-reduced-motion: reduce) {
855
+ animation: none;
856
+ }
857
+ `;
858
+ const FeedbackPanel = styled.div `
859
+ margin-top: 6px;
860
+ padding: 14px 16px;
861
+ border: 1px solid #e5e7eb;
862
+ border-radius: 12px;
863
+ background: white;
864
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.06);
865
+ scroll-margin: 12px;
866
+ animation: ${feedbackIn} 0.2s ease-out;
867
+ `;
868
+ const FeedbackPanelHeader = styled.div `
869
+ display: flex;
870
+ align-items: flex-start;
871
+ justify-content: space-between;
872
+ gap: 12px;
873
+ margin-bottom: 10px;
874
+ `;
875
+ const FeedbackPanelTitle = styled.div `
876
+ font-size: 14px;
877
+ font-weight: 600;
878
+ color: #242424;
879
+ line-height: 1.35;
880
+ `;
881
+ const FeedbackCloseButton = styled.button `
882
+ display: flex;
883
+ align-items: center;
884
+ justify-content: center;
885
+ width: 24px;
886
+ height: 24px;
887
+ padding: 0;
888
+ border: none;
889
+ border-radius: 6px;
890
+ background: transparent;
891
+ color: #6b7280;
892
+ cursor: pointer;
893
+ flex-shrink: 0;
894
+ transition: background 0.2s ease, color 0.2s ease;
895
+
896
+ &:hover { background: rgba(0, 0, 0, 0.06); color: #242424; }
897
+ `;
898
+ const FeedbackLabel = styled.div `
899
+ margin: 0 0 8px 0;
900
+ font-size: 12px;
901
+ font-weight: 600;
902
+ color: #6b7280;
903
+ `;
904
+ const FeedbackTags = styled.div `
905
+ display: flex;
906
+ flex-wrap: wrap;
907
+ gap: 8px;
908
+ margin-bottom: 14px;
909
+ `;
910
+ const FeedbackTag = styled.button `
911
+ padding: 6px 12px;
912
+ border-radius: 8px;
913
+ border: 1px solid ${props => (props.$selected ? TMColors.primary : '#dcdfe3')};
914
+ background: ${props => (props.$selected ? `${TMColors.primary}10` : 'white')};
915
+ color: ${props => (props.$selected ? TMColors.primary : '#242424')};
916
+ font-family: inherit;
917
+ font-size: 13px;
918
+ font-weight: ${props => (props.$selected ? 600 : 400)};
919
+ line-height: 1.2;
920
+ cursor: pointer;
921
+ transition: border-color 0.2s ease, background 0.2s ease, color 0.2s ease;
922
+
923
+ &:hover { border-color: ${TMColors.primary}88; }
924
+
925
+ &:focus-visible {
926
+ outline: 2px solid ${TMColors.primary}55;
927
+ outline-offset: 1px;
928
+ }
929
+ `;
930
+ const FeedbackTextarea = styled.textarea `
931
+ display: block;
932
+ width: 100%;
933
+ min-height: 70px;
934
+ padding: 9px 11px;
935
+ border: 1px solid #dcdfe3;
936
+ border-radius: 8px;
937
+ font-family: inherit;
938
+ font-size: 13px;
939
+ line-height: 1.45;
940
+ color: #242424;
941
+ background: white;
942
+ resize: none;
943
+ box-sizing: border-box;
944
+ transition: border-color 0.2s ease, box-shadow 0.2s ease;
945
+
946
+ &::placeholder { color: #9ca3af; }
947
+
948
+ &:focus {
949
+ outline: none;
950
+ border-color: ${TMColors.primary};
951
+ box-shadow: 0 0 0 3px ${TMColors.primary}15;
952
+ }
953
+ `;
954
+ const FeedbackPanelFooter = styled.div `
955
+ display: flex;
956
+ align-items: center;
957
+ justify-content: space-between;
958
+ margin-top: 10px;
959
+ `;
960
+ const FeedbackCounter = styled.span `
961
+ font-size: 11px;
962
+ color: ${props => (props.$full ? '#c62828' : '#9ca3af')};
963
+ font-variant-numeric: tabular-nums;
964
+ `;
965
+ const FeedbackSubmitButton = styled.button `
966
+ padding: 7px 18px;
967
+ border: none;
968
+ border-radius: 8px;
969
+ background: ${TMColors.primary};
970
+ color: white;
971
+ font-family: inherit;
972
+ font-size: 13px;
973
+ font-weight: 600;
974
+ cursor: pointer;
975
+ transition: opacity 0.2s ease, transform 0.2s ease, box-shadow 0.2s ease;
976
+
977
+ &:hover:not(:disabled) {
978
+ box-shadow: 0 4px 12px ${TMColors.primary}40;
979
+ transform: translateY(-1px);
980
+ }
981
+
982
+ &:active:not(:disabled) { transform: translateY(0); }
983
+
984
+ &:disabled {
985
+ opacity: 0.4;
986
+ cursor: default;
987
+ }
988
+ `;
989
+ const MarkdownContent = styled.div `
990
+ & > *:first-child { margin-top: 0; }
991
+ & > *:last-child { margin-bottom: 0; }
992
+
993
+ a { color: ${TMColors.primary}; text-decoration: underline; }
994
+ strong { font-weight: 600; }
995
+ `;
996
+ const MdParagraph = styled.p `
997
+ margin: 0 0 8px 0;
998
+ line-height: 1.55;
999
+ `;
1000
+ const MdHeading = styled.div `
1001
+ margin: 12px 0 6px 0;
1002
+ font-weight: 700;
1003
+ line-height: 1.3;
1004
+ font-size: ${props => `${Math.max(14, 20 - (props.$level - 1) * 2)}px`};
1005
+ `;
1006
+ const MdUl = styled.ul `
1007
+ margin: 4px 0 8px 0;
1008
+ padding-left: 20px;
1009
+ li { margin: 2px 0; line-height: 1.5; }
1010
+ `;
1011
+ const MdOl = styled.ol `
1012
+ margin: 4px 0 8px 0;
1013
+ padding-left: 22px;
1014
+ li { margin: 2px 0; line-height: 1.5; }
1015
+ `;
1016
+ const MdCode = styled.code `
1017
+ background: rgba(0, 0, 0, 0.06);
1018
+ padding: 1px 5px;
1019
+ border-radius: 4px;
1020
+ font-family: 'Consolas', 'Monaco', monospace;
1021
+ font-size: 0.9em;
1022
+ `;
1023
+ const MdPre = styled.pre `
1024
+ background: rgba(0, 0, 0, 0.06);
1025
+ padding: 10px 12px;
1026
+ border-radius: 8px;
1027
+ overflow-x: auto;
1028
+ margin: 8px 0;
1029
+ font-family: 'Consolas', 'Monaco', monospace;
1030
+ font-size: 0.88em;
1031
+ white-space: pre;
1032
+ `;
1033
+ const MdTableWrapper = styled.div `
1034
+ margin: 8px 0;
1035
+ max-width: 100%;
1036
+ overflow-x: auto;
1037
+ border: 1px solid #dcdfe3;
1038
+ border-radius: 8px;
1039
+
1040
+ &::-webkit-scrollbar { height: 6px; }
1041
+ &::-webkit-scrollbar-track { background: transparent; }
1042
+ &::-webkit-scrollbar-thumb { background: #ccc; border-radius: 3px; }
1043
+ &::-webkit-scrollbar-thumb:hover { background: #999; }
1044
+ `;
1045
+ const MdTable = styled.table `
1046
+ border-collapse: collapse;
1047
+ width: 100%;
1048
+ font-size: 0.92em;
1049
+ background: white;
1050
+ `;
1051
+ const MdTh = styled.th `
1052
+ padding: 7px 10px;
1053
+ background: ${TMColors.primary}14;
1054
+ color: #242424;
1055
+ font-weight: 600;
1056
+ text-align: ${props => props.$align ?? 'left'};
1057
+ border-bottom: 1px solid #dcdfe3;
1058
+ white-space: nowrap;
1059
+
1060
+ &:not(:last-child) { border-right: 1px solid #e6e8eb; }
1061
+ `;
1062
+ const MdTd = styled.td `
1063
+ padding: 7px 10px;
1064
+ text-align: ${props => props.$align ?? 'left'};
1065
+ vertical-align: top;
1066
+ border-top: 1px solid #eceef0;
1067
+
1068
+ &:not(:last-child) { border-right: 1px solid #eceef0; }
1069
+
1070
+ tr:nth-child(even) & { background: #fafbfc; }
1071
+ `;
1072
+ const MdBlockquote = styled.blockquote `
1073
+ margin: 8px 0;
1074
+ padding: 6px 12px;
1075
+ border-left: 3px solid ${TMColors.primary}66;
1076
+ background: ${TMColors.primary}0a;
1077
+ border-radius: 0 6px 6px 0;
1078
+ color: #444;
1079
+
1080
+ & > *:first-child { margin-top: 0; }
1081
+ & > *:last-child { margin-bottom: 0; }
1082
+ `;
1083
+ const MdHr = styled.hr `
1084
+ border: none;
1085
+ border-top: 1px solid #dcdfe3;
1086
+ margin: 12px 0;
1087
+ `;
1088
+ const ThinkingIndicator = styled.div `
1089
+ display: flex;
1090
+ align-items: center;
1091
+ gap: 10px;
1092
+ max-width: 80%;
1093
+ padding: 7px 12px;
1094
+ background: #f0f2f5;
1095
+ border-radius: 12px;
1096
+ border-bottom-left-radius: 4px;
1097
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
1098
+ `;
1099
+ const ThinkingCaption = styled.div `
1100
+ display: flex;
1101
+ flex-direction: column;
1102
+ align-items: flex-start;
1103
+ gap: 0;
1104
+ min-width: 0;
1105
+ `;
1106
+ const ThinkingPhrase = styled.span `
1107
+ display: inline-flex;
1108
+ align-items: center;
1109
+ min-width: 0;
1110
+ font-size: 12px;
1111
+ font-style: italic;
1112
+ line-height: 1.15;
1113
+ color: #6b7280;
1114
+ animation: ${phraseIn} 0.25s ease-out;
1115
+ `;
1116
+ const ThinkingDots = styled.span `
1117
+ display: inline-flex;
1118
+ width: 12px;
1119
+ flex-shrink: 0;
1120
+ `;
1121
+ const ThinkingDot = styled.span `
1122
+ animation: ${dotCycle} 1.2s linear infinite;
1123
+ animation-delay: ${props => props.$delay}s;
1124
+ will-change: opacity;
1125
+
1126
+ @media (prefers-reduced-motion: reduce) {
1127
+ animation: none;
1128
+ opacity: 1;
1129
+ }
1130
+ `;
1131
+ const ThinkingCounter = styled.span `
1132
+ margin-top: 2px;
1133
+ font-size: 10px;
1134
+ font-weight: 600;
1135
+ line-height: 1.1;
1136
+ letter-spacing: 0.02em;
1137
+ color: ${TMColors.primary}b3;
1138
+ font-variant-numeric: tabular-nums;
1139
+ font-feature-settings: 'tnum';
1140
+ opacity: ${props => (props.$visible ? 1 : 0)};
1141
+ transition: opacity 0.3s ease;
1142
+ `;
1143
+ const ChatFooter = styled.div `
1144
+ padding: 16px 20px;
1145
+ background: white;
1146
+ border-top: 1px solid #e1e5e9;
1147
+ box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.05);
1148
+ `;
1149
+ const FooterHint = styled.p `
1150
+ margin: 6px 0 0 0;
1151
+ font-size: 11px;
1152
+ color: #999;
1153
+ text-align: center;
1154
+ `;
1155
+ const ChatInputWrapper = styled.div `
1156
+ position: relative;
1157
+ flex: 1;
1158
+ display: flex;
1159
+ `;
1160
+ const ChatInputTextarea = styled.textarea `
1161
+ width: 100%;
1162
+ padding: 14px 60px 14px 16px;
1163
+ border: 2px solid #e1e5e9;
1164
+ border-radius: 12px;
1165
+ font-size: 15px;
1166
+ font-family: inherit;
1167
+ line-height: 1.5;
1168
+ transition: all 0.2s ease;
1169
+ background: #f8f9fa;
1170
+ resize: none;
1171
+ min-height: 100px;
1172
+ max-height: 120px;
1173
+ overflow-y: hidden;
1174
+
1175
+ &:focus {
1176
+ outline: none;
1177
+ border-color: ${TMColors.primary};
1178
+ background: white;
1179
+ box-shadow: 0 0 0 4px ${TMColors.primary}15;
1180
+ }
1181
+
1182
+ &::placeholder {
1183
+ color: #999;
1184
+ }
1185
+
1186
+ &::-webkit-scrollbar {
1187
+ width: 6px;
1188
+ }
1189
+
1190
+ &::-webkit-scrollbar-track {
1191
+ background: transparent;
1192
+ }
1193
+
1194
+ &::-webkit-scrollbar-thumb {
1195
+ background: #ccc;
1196
+ border-radius: 3px;
1197
+ }
1198
+
1199
+ &::-webkit-scrollbar-thumb:hover {
1200
+ background: #999;
1201
+ }
1202
+ `;
1203
+ const InlineSendButton = styled.button `
1204
+ position: absolute;
1205
+ bottom: 8px;
1206
+ right: 8px;
1207
+ width: 40px;
1208
+ height: 40px;
1209
+ border-radius: 10px;
1210
+ background: ${props => props.$disabled ? '#ccc' : '#4caf50'};
1211
+ border: none;
1212
+ color: white;
1213
+ cursor: ${props => props.$disabled ? 'default' : 'pointer'};
1214
+ display: flex;
1215
+ align-items: center;
1216
+ justify-content: center;
1217
+ transition: all 0.2s ease;
1218
+
1219
+ &:hover:not(:disabled) {
1220
+ background: #45a049;
1221
+ transform: scale(1.05);
1222
+ }
1223
+
1224
+ &:active:not(:disabled) {
1225
+ transform: scale(0.95);
1226
+ }
1227
+
1228
+ &:disabled {
1229
+ opacity: 0.6;
1230
+ }
1231
+ `;