@topconsultnpm/sdkui-react 6.22.0-dev3.3 → 6.22.0-dev3.31

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 (173) hide show
  1. package/lib/components/NewComponents/ContextMenu/styles.d.ts +45 -43
  2. package/lib/components/NewComponents/FloatingMenuBar/styles.d.ts +67 -60
  3. package/lib/components/base/Styled.d.ts +93 -77
  4. package/lib/components/base/Styled.js +7 -5
  5. package/lib/components/base/TMAlert.js +6 -8
  6. package/lib/components/base/TMAreaManager.js +53 -55
  7. package/lib/components/base/TMCounterBar.d.ts +2 -2
  8. package/lib/components/base/TMCounterContainer.d.ts +2 -1
  9. package/lib/components/base/TMCustomButton.d.ts +1 -1
  10. package/lib/components/base/TMCustomButton.js +40 -48
  11. package/lib/components/base/TMDataGrid.js +2 -2
  12. package/lib/components/base/TMDataGridExportForm.d.ts +2 -1
  13. package/lib/components/base/TMFileManager.d.ts +2 -1
  14. package/lib/components/base/TMFileManagerDataGridView.d.ts +2 -1
  15. package/lib/components/base/TMFileManagerThumbnailItems.d.ts +1 -1
  16. package/lib/components/base/TMFileManagerThumbnailsView.d.ts +1 -1
  17. package/lib/components/base/TMFileManagerUtils.d.ts +4 -6
  18. package/lib/components/base/TMLayout.d.ts +4 -4
  19. package/lib/components/base/TMList.d.ts +2 -1
  20. package/lib/components/base/TMListView.d.ts +1 -1
  21. package/lib/components/base/TMPanel.js +2 -2
  22. package/lib/components/base/TMSpinner.d.ts +4 -2
  23. package/lib/components/base/TMSpinner.js +9 -7
  24. package/lib/components/base/TMTab.d.ts +4 -3
  25. package/lib/components/base/TMTabControl.d.ts +106 -0
  26. package/lib/components/base/TMTabControl.js +664 -0
  27. package/lib/components/base/TMTooltip.d.ts +1 -1
  28. package/lib/components/base/TMTreeView.d.ts +14 -8
  29. package/lib/components/base/TMTreeView.js +33 -1
  30. package/lib/components/base/TMUserAvatar.d.ts +2 -1
  31. package/lib/components/base/TMVilViewer.d.ts +2 -1
  32. package/lib/components/base/TMWaitPanel.d.ts +3 -2
  33. package/lib/components/base/TMWaitPanel.js +1 -1
  34. package/lib/components/base/waitPanel/TMWaitPanelConfirm.d.ts +12 -0
  35. package/lib/components/base/waitPanel/TMWaitPanelConfirm.js +185 -0
  36. package/lib/components/base/waitPanel/TMWaitPanelManager.d.ts +169 -0
  37. package/lib/components/base/waitPanel/TMWaitPanelManager.js +320 -0
  38. package/lib/components/base/waitPanel/TMWaitPanelView.d.ts +53 -0
  39. package/lib/components/base/waitPanel/TMWaitPanelView.js +274 -0
  40. package/lib/components/base/waitPanel/index.d.ts +1 -0
  41. package/lib/components/base/waitPanel/index.js +1 -0
  42. package/lib/components/choosers/TMDynDataListItemChooser.d.ts +1 -1
  43. package/lib/components/choosers/TMInvoiceRetrieveFormats.d.ts +2 -1
  44. package/lib/components/choosers/TMOrderRetrieveFormats.d.ts +2 -1
  45. package/lib/components/choosers/TMPathChooser.js +17 -34
  46. package/lib/components/choosers/TMQuickSearchInfo.d.ts +2 -1
  47. package/lib/components/choosers/TMRelationChooser.d.ts +3 -3
  48. package/lib/components/choosers/TMUserChooser.d.ts +2 -2
  49. package/lib/components/editors/TMEditorStyled.d.ts +20 -42
  50. package/lib/components/editors/TMFormulaEditor.d.ts +1 -1
  51. package/lib/components/editors/TMHtmlContentDisplay.d.ts +2 -1
  52. package/lib/components/editors/TMHtmlEditor.d.ts +2 -1
  53. package/lib/components/editors/TMMetadataValues.js +5 -5
  54. package/lib/components/editors/TMTreeDropDown.d.ts +1 -1
  55. package/lib/components/features/archive/TMArchive.js +7 -2
  56. package/lib/components/features/assistant/TMHelpOnLineChat.d.ts +28 -0
  57. package/lib/components/features/assistant/TMHelpOnLineChat.js +888 -0
  58. package/lib/components/features/assistant/TMToppyDraggableHelpCenter.d.ts +1 -1
  59. package/lib/components/features/assistant/TMToppyDraggableHelpCenter.js +2 -2
  60. package/lib/components/features/blog/TMBlogCommentForm.d.ts +2 -1
  61. package/lib/components/features/documents/TMBatchUpdateForm.js +3 -4
  62. package/lib/components/features/documents/TMCopyToFolderForm.js +50 -42
  63. package/lib/components/features/documents/TMDcmtForm.js +51 -62
  64. package/lib/components/features/documents/TMDcmtFormActionButtons.d.ts +1 -1
  65. package/lib/components/features/documents/TMDcmtIcon.d.ts +2 -3
  66. package/lib/components/features/documents/TMDcmtIcon.js +3 -5
  67. package/lib/components/features/documents/TMDcmtPreview.d.ts +8 -6
  68. package/lib/components/features/documents/TMDcmtPreview.js +5 -3
  69. package/lib/components/features/documents/TMDcmtTasks.d.ts +2 -1
  70. package/lib/components/features/documents/TMDragDropOverlay.d.ts +1 -1
  71. package/lib/components/features/documents/TMFileUploader.js +26 -26
  72. package/lib/components/features/documents/TMMasterDetailDcmts.d.ts +2 -0
  73. package/lib/components/features/documents/TMMasterDetailDcmts.js +54 -129
  74. package/lib/components/features/documents/TMMasterInfoFields.d.ts +2 -1
  75. package/lib/components/features/documents/TMMasterInfoFields.js +3 -2
  76. package/lib/components/features/documents/TMMergeToPdfForm.d.ts +2 -1
  77. package/lib/components/features/documents/TMMergeToPdfForm.js +56 -54
  78. package/lib/components/features/documents/TMMultiMasterDetailDcmtsForm.d.ts +2 -1
  79. package/lib/components/features/documents/TMMultiMasterDetailDcmtsForm.js +2 -5
  80. package/lib/components/features/documents/TMMultiMasterDetailDcmtsUtils.d.ts +5 -5
  81. package/lib/components/features/documents/TMMultiMasterDetailDcmtsUtils.js +3 -3
  82. package/lib/components/features/documents/TMRelationViewer.d.ts +16 -9
  83. package/lib/components/features/documents/TMRelationViewer.js +238 -166
  84. package/lib/components/features/documents/relationTreeState.d.ts +32 -0
  85. package/lib/components/features/documents/relationTreeState.js +89 -0
  86. package/lib/components/features/search/TMDcmtCheckoutInfoForm.d.ts +2 -1
  87. package/lib/components/features/search/TMMetadataOutputForm.d.ts +2 -1
  88. package/lib/components/features/search/TMMetadataSorterForm.d.ts +2 -1
  89. package/lib/components/features/search/TMSavedQuerySelector.d.ts +2 -2
  90. package/lib/components/features/search/TMSearch.d.ts +1 -1
  91. package/lib/components/features/search/TMSearch.js +68 -9
  92. package/lib/components/features/search/TMSearchQueryPanel.d.ts +9 -3
  93. package/lib/components/features/search/TMSearchResult.d.ts +5 -0
  94. package/lib/components/features/search/TMSearchResult.js +19 -12
  95. package/lib/components/features/search/TMSearchResultFloatingActionButton.d.ts +1 -1
  96. package/lib/components/features/search/TMSignatureInfoContent.d.ts +2 -1
  97. package/lib/components/features/search/TMTreeSelector.js +38 -36
  98. package/lib/components/features/search/TMViewHistoryDcmt.d.ts +2 -1
  99. package/lib/components/features/search/TMViewHistoryDcmt.js +14 -25
  100. package/lib/components/features/tasks/TMTaskForm.d.ts +1 -1
  101. package/lib/components/features/tasks/TMTaskFormUtils.d.ts +10 -10
  102. package/lib/components/features/tasks/TMTasksAgenda.d.ts +1 -1
  103. package/lib/components/features/tasks/TMTasksCalendar.d.ts +1 -1
  104. package/lib/components/features/tasks/TMTasksHeader.d.ts +1 -1
  105. package/lib/components/features/tasks/TMTasksPanelContent.d.ts +1 -1
  106. package/lib/components/features/tasks/TMTasksUtilsView.d.ts +5 -5
  107. package/lib/components/features/tasks/TMTasksView.d.ts +1 -1
  108. package/lib/components/features/tasks/TMTasksView.js +96 -101
  109. package/lib/components/features/wg/TMWGsCopyMoveForm.d.ts +3 -2
  110. package/lib/components/features/wg/TMWGsCopyMoveForm.js +91 -91
  111. package/lib/components/features/workflow/TMWorkflowPopup.d.ts +8 -7
  112. package/lib/components/features/workflow/diagram/WorkitemRecipientsEditor.d.ts +3 -1
  113. package/lib/components/forms/Login/ChangePasswordInputs.d.ts +3 -1
  114. package/lib/components/forms/Login/Chooser.d.ts +2 -2
  115. package/lib/components/forms/TMChooserForm.d.ts +2 -1
  116. package/lib/components/forms/TMResultDialog.js +1 -1
  117. package/lib/components/forms/TMSaveForm.d.ts +4 -4
  118. package/lib/components/grids/TMBlogAttachments.d.ts +2 -1
  119. package/lib/components/grids/TMBlogHeader.d.ts +1 -1
  120. package/lib/components/grids/TMBlogsPost.d.ts +1 -1
  121. package/lib/components/grids/TMBlogsPost.js +92 -96
  122. package/lib/components/grids/TMBlogsPostUtils.d.ts +9 -9
  123. package/lib/components/grids/TMValidationItemsList.d.ts +2 -1
  124. package/lib/components/index.d.ts +6 -0
  125. package/lib/components/index.js +5 -0
  126. package/lib/components/layout/panelManager/TMPanelManagerContainer.d.ts +2 -1
  127. package/lib/components/layout/panelManager/TMPanelManagerContext.d.ts +2 -2
  128. package/lib/components/layout/panelManager/TMPanelManagerToolbar.d.ts +5 -6
  129. package/lib/components/layout/panelManager/TMPanelManagerWithPersistenceProvider.d.ts +2 -2
  130. package/lib/components/layout/panelManager/TMPanelWrapper.d.ts +2 -2
  131. package/lib/components/pages/TMPage.d.ts +1 -1
  132. package/lib/components/pages/TMPage.js +29 -31
  133. package/lib/components/query/TMQueryEditor.d.ts +17 -10
  134. package/lib/components/query/TMQueryEditor.js +2 -1
  135. package/lib/components/settings/SettingsAppearance.d.ts +2 -1
  136. package/lib/components/sidebar/TMAboutApp.d.ts +2 -1
  137. package/lib/components/sidebar/TMCommandsPanel.d.ts +4 -4
  138. package/lib/components/sidebar/TMHeader.d.ts +4 -3
  139. package/lib/components/sidebar/TMHeader.js +2 -2
  140. package/lib/components/viewers/TMDataListItemViewer.d.ts +3 -2
  141. package/lib/components/viewers/TMDataUserIdItemViewer.d.ts +3 -2
  142. package/lib/components/viewers/TMMidViewer.d.ts +2 -2
  143. package/lib/components/viewers/TMTidViewer.d.ts +2 -2
  144. package/lib/helper/Enum_Localizator.js +1 -0
  145. package/lib/helper/SDKUI_Localizator.d.ts +24 -0
  146. package/lib/helper/SDKUI_Localizator.js +240 -0
  147. package/lib/helper/TMAppUpdatedModal.d.ts +2 -1
  148. package/lib/helper/TMAppUpdatedModal.js +93 -93
  149. package/lib/helper/TMCommandsContextMenu.d.ts +1 -1
  150. package/lib/helper/TMIcons.d.ts +280 -280
  151. package/lib/helper/TMPdfViewer.d.ts +2 -1
  152. package/lib/helper/TMToppyMessage.d.ts +2 -2
  153. package/lib/helper/TMUtils.d.ts +10 -4
  154. package/lib/helper/ZipManager.d.ts +1 -1
  155. package/lib/helper/ZipManager.js +2 -1
  156. package/lib/helper/dcmtsHelper.d.ts +2 -0
  157. package/lib/helper/dcmtsHelper.js +3 -1
  158. package/lib/helper/helpers.d.ts +1 -1
  159. package/lib/hooks/useCheckInOutOperations.d.ts +0 -6
  160. package/lib/hooks/useCheckInOutOperations.js +14 -34
  161. package/lib/hooks/useDcmtOperations.d.ts +3 -12
  162. package/lib/hooks/useDcmtOperations.js +187 -179
  163. package/lib/hooks/useDocumentOperations.d.ts +1 -0
  164. package/lib/hooks/useDocumentOperations.js +14 -25
  165. package/lib/hooks/useInputDialog.d.ts +2 -1
  166. package/lib/hooks/useMultiMasterDetailDcmts.d.ts +0 -15
  167. package/lib/hooks/useMultiMasterDetailDcmts.js +65 -67
  168. package/lib/hooks/usePreventFileDrop.js +9 -0
  169. package/lib/hooks/useWorkflowApprove.js +33 -17
  170. package/lib/services/caseflow/CaseFlowService.d.ts +36 -6
  171. package/lib/services/caseflow/CaseFlowService.js +55 -14
  172. package/lib/services/platform_services.d.ts +3 -2
  173. package/package.json +71 -71
@@ -0,0 +1,888 @@
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 { HolAskDescriptor, SDK_Globals, TopMediaServer } from '@topconsultnpm/sdk-ts';
5
+ import TMTooltip from '../../base/TMTooltip';
6
+ import { TMColors } from '../../../utils/theme';
7
+ import { SDKUI_Localizator } from '../../../helper';
8
+ import ToppyImage from '../../../assets/Toppy-help-center.png';
9
+ const generateGUID = () => {
10
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replaceAll(/[xy]/g, (c) => {
11
+ const r = Math.trunc(Math.random() * 16);
12
+ const v = c === 'x' ? r : (r & 0x3 | 0x8);
13
+ return v.toString(16);
14
+ });
15
+ };
16
+ const PANEL_DEFAULT_WIDTH = 600;
17
+ const PANEL_MIN_WIDTH = 340;
18
+ const PANEL_MAX_WIDTH = 900;
19
+ const getSafeSession = () => {
20
+ try {
21
+ return SDK_Globals.tmSession;
22
+ }
23
+ catch {
24
+ return undefined;
25
+ }
26
+ };
27
+ let preLoginSession;
28
+ let preLoginSessionUrl;
29
+ const getPreLoginSession = (endpointUrl) => {
30
+ if (!endpointUrl) {
31
+ return undefined;
32
+ }
33
+ if (!preLoginSession || preLoginSessionUrl !== endpointUrl) {
34
+ const tmServer = new TopMediaServer(endpointUrl);
35
+ preLoginSession = tmServer.NewSession();
36
+ preLoginSessionUrl = endpointUrl;
37
+ }
38
+ return preLoginSession;
39
+ };
40
+ const TMHelpOnLineChat = ({ isOpen, showChatButton, isLogged, messages, conversationId, isThinking, endpointUrl, onClose, onToggle, onNewConversation, onAddMessage, onSetThinking, onSetConversationId }) => {
41
+ const [width, setWidth] = useState(PANEL_DEFAULT_WIDTH);
42
+ const showFab = !isLogged && showChatButton && !isOpen;
43
+ 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 })] })), showFab && (_jsx(Fab, { onClick: onToggle, title: "Chiedi a Toppy", "aria-label": "Chiedi a Toppy", children: _jsx(FabAvatar, { src: ToppyImage, alt: "Toppy" }) }))] }));
44
+ };
45
+ export default TMHelpOnLineChat;
46
+ //#region Header button
47
+ export const TMToppyHeaderButton = ({ showChatButton, onToggle }) => {
48
+ if (!showChatButton)
49
+ return null;
50
+ 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" })] }) }));
51
+ };
52
+ const ChatPanel = ({ width, onWidthChange, messages, conversationId, isThinking, endpointUrl, onClose, onNewConversation, onAddMessage, onSetThinking, onSetConversationId }) => {
53
+ const [chatInput, setChatInput] = useState('');
54
+ const inputRef = useRef(null);
55
+ const messagesEndRef = useRef(null);
56
+ const onCloseRef = useRef(onClose);
57
+ onCloseRef.current = onClose;
58
+ const userName = getSafeSession()?.SessionDescr?.userName ?? '';
59
+ useEffect(() => {
60
+ messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
61
+ }, [messages, isThinking]);
62
+ useEffect(() => {
63
+ inputRef.current?.focus();
64
+ }, []);
65
+ useEffect(() => {
66
+ const onKeyDown = (e) => {
67
+ if (e.key === 'Escape')
68
+ onCloseRef.current();
69
+ };
70
+ window.addEventListener('keydown', onKeyDown);
71
+ return () => window.removeEventListener('keydown', onKeyDown);
72
+ }, []);
73
+ const onResizeStart = useCallback((e) => {
74
+ e.preventDefault();
75
+ const startX = e.clientX;
76
+ const startWidth = width;
77
+ const onMove = (ev) => {
78
+ const next = startWidth + (startX - ev.clientX);
79
+ const max = Math.min(PANEL_MAX_WIDTH, globalThis.innerWidth - 40);
80
+ onWidthChange(Math.min(Math.max(next, PANEL_MIN_WIDTH), max));
81
+ };
82
+ const onUp = () => {
83
+ document.body.style.userSelect = '';
84
+ document.body.style.cursor = '';
85
+ globalThis.removeEventListener('mousemove', onMove);
86
+ globalThis.removeEventListener('mouseup', onUp);
87
+ };
88
+ document.body.style.userSelect = 'none';
89
+ document.body.style.cursor = 'col-resize';
90
+ globalThis.addEventListener('mousemove', onMove);
91
+ globalThis.addEventListener('mouseup', onUp);
92
+ }, [width, onWidthChange]);
93
+ const askHandler = useCallback(async () => {
94
+ const question = chatInput.trim();
95
+ if (question.length < 2 || isThinking) {
96
+ return;
97
+ }
98
+ onAddMessage({ id: generateGUID(), text: question, isUser: true });
99
+ setChatInput('');
100
+ onSetThinking(true);
101
+ let convId = conversationId;
102
+ if (!convId) {
103
+ convId = generateGUID();
104
+ onSetConversationId(convId);
105
+ }
106
+ try {
107
+ const globalSession = getSafeSession();
108
+ const preSession = globalSession ? undefined : getPreLoginSession(endpointUrl);
109
+ const session = globalSession ?? preSession;
110
+ let answer = '';
111
+ if (session) {
112
+ const hol_d = new HolAskDescriptor();
113
+ hol_d.question = question;
114
+ hol_d.conversationId = convId;
115
+ const raw = await session.HelpOnLineAskAsync(hol_d);
116
+ const parsed = typeof raw === 'string' ? safeJsonParse(raw) : raw;
117
+ if (parsed && typeof parsed === 'object') {
118
+ answer = parsed.answer ?? '';
119
+ }
120
+ else if (typeof raw === 'string') {
121
+ answer = raw;
122
+ }
123
+ }
124
+ else {
125
+ console.error('[HOL] NO SESSION -> nothing called. endpointUrl =', endpointUrl);
126
+ }
127
+ onAddMessage({ id: generateGUID(), text: answer || 'Nessuna risposta ricevuta.', isUser: false });
128
+ }
129
+ catch (error) {
130
+ onAddMessage({ id: generateGUID(), text: 'Si è verificato un errore, riprova più tardi.', isUser: false });
131
+ console.error('[HOL]', error);
132
+ }
133
+ finally {
134
+ onSetThinking(false);
135
+ }
136
+ }, [chatInput, conversationId, isThinking, endpointUrl, onAddMessage, onSetThinking, onSetConversationId]);
137
+ 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 => (_jsxs(MessageBubble, { $isUser: msg.isUser, children: [!msg.isUser && _jsx(BotAvatar, { src: ToppyImage, alt: "Toppy" }), _jsx(MessageContent, { $isUser: msg.isUser, children: msg.isUser ? msg.text : _jsx(MarkdownContent, { children: renderMarkdown(msg.text) }) })] }, 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 })] })] }));
138
+ };
139
+ const TMChatInput = ({ value, onChange, onSend, placeholder = 'Scrivi la tua domanda...', disabled = false, inputRef, tooltip = 'Ricerca AI' }) => {
140
+ const isDisabled = disabled || value.length < 2;
141
+ return (_jsxs(ChatInputWrapper, { children: [_jsx(ChatInputTextarea, { ref: inputRef, placeholder: placeholder, value: value, onChange: (e) => onChange(e.target.value), onKeyDown: (e) => {
142
+ if (e.key !== 'Enter')
143
+ return;
144
+ e.stopPropagation();
145
+ if (!e.shiftKey && !e.nativeEvent.isComposing) {
146
+ e.preventDefault();
147
+ if (!isDisabled)
148
+ onSend();
149
+ }
150
+ } }), _jsx(TMTooltip, { content: tooltip, children: _jsx(InlineSendButton, { $disabled: isDisabled, disabled: isDisabled, onClick: onSend, title: tooltip, children: _jsx(IconSendFilled, { fontSize: 20 }) }) })] }));
151
+ };
152
+ //#endregion
153
+ //#region Thinking status (phrases + elapsed seconds)
154
+ const getThinkingPhrases = () => [
155
+ { at: 0, text: SDKUI_Localizator.HelpOnLineThinking01 },
156
+ { at: 3, text: SDKUI_Localizator.HelpOnLineThinking02 },
157
+ { at: 7, text: SDKUI_Localizator.HelpOnLineThinking03 },
158
+ { at: 12, text: SDKUI_Localizator.HelpOnLineThinking04 },
159
+ { at: 18, text: SDKUI_Localizator.HelpOnLineThinking05 },
160
+ { at: 25, text: SDKUI_Localizator.HelpOnLineThinking06 },
161
+ { at: 33, text: SDKUI_Localizator.HelpOnLineThinking07 },
162
+ { at: 42, text: SDKUI_Localizator.HelpOnLineThinking08 },
163
+ { at: 55, text: SDKUI_Localizator.HelpOnLineThinking09 },
164
+ { at: 70, text: SDKUI_Localizator.HelpOnLineThinking10 },
165
+ ];
166
+ const COUNTER_VISIBLE_FROM = 2;
167
+ const getPhraseIndex = (seconds, phrases) => {
168
+ let index = 0;
169
+ for (let i = 1; i < phrases.length; i++) {
170
+ if (seconds < phrases[i].at)
171
+ break;
172
+ index = i;
173
+ }
174
+ return index;
175
+ };
176
+ const formatElapsed = (seconds) => seconds < 60 ? `${seconds}s` : `${Math.floor(seconds / 60)}:${String(seconds % 60).padStart(2, '0')}`;
177
+ const ThinkingStatus = () => {
178
+ const [seconds, setSeconds] = useState(0);
179
+ useEffect(() => {
180
+ const startedAt = performance.now();
181
+ const intervalId = globalThis.setInterval(() => {
182
+ setSeconds(Math.floor((performance.now() - startedAt) / 1000));
183
+ }, 1000);
184
+ return () => globalThis.clearInterval(intervalId);
185
+ }, []);
186
+ const phrases = getThinkingPhrases();
187
+ const phraseIndex = getPhraseIndex(seconds, phrases);
188
+ 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) })] }) }));
189
+ };
190
+ //#endregion
191
+ //#region Markdown rendering (no third-party library)
192
+ const safeJsonParse = (value) => {
193
+ try {
194
+ return JSON.parse(value);
195
+ }
196
+ catch {
197
+ return value;
198
+ }
199
+ };
200
+ const renderInline = (text, keyPrefix) => {
201
+ const nodes = [];
202
+ const pattern = /(\*\*([^*]+)\*\*)|(~~([^~]+)~~)|(`([^`]+)`)|(\[([^\]]+)\]\(([^)]+)\))|(\*([^*\n]+)\*)|(_([^_\n]+)_)/g;
203
+ let lastIndex = 0;
204
+ let match;
205
+ let i = 0;
206
+ while ((match = pattern.exec(text)) !== null) {
207
+ if (match.index > lastIndex)
208
+ nodes.push(text.slice(lastIndex, match.index));
209
+ const key = `${keyPrefix}-${i}`;
210
+ if (match[2] !== undefined) {
211
+ nodes.push(_jsx("strong", { children: renderInline(match[2], key) }, key));
212
+ }
213
+ else if (match[4] !== undefined) {
214
+ nodes.push(_jsx("s", { children: renderInline(match[4], key) }, key));
215
+ }
216
+ else if (match[6] !== undefined) {
217
+ nodes.push(_jsx(MdCode, { children: match[6] }, key));
218
+ }
219
+ else if (match[8] !== undefined) {
220
+ nodes.push(_jsx("a", { href: match[9], target: "_blank", rel: "noopener noreferrer", children: match[8] }, key));
221
+ }
222
+ else if (match[11] !== undefined) {
223
+ nodes.push(_jsx("em", { children: match[11] }, key));
224
+ }
225
+ else if (match[13] !== undefined) {
226
+ nodes.push(_jsx("em", { children: match[13] }, key));
227
+ }
228
+ lastIndex = pattern.lastIndex;
229
+ i++;
230
+ }
231
+ if (lastIndex < text.length)
232
+ nodes.push(text.slice(lastIndex));
233
+ return nodes;
234
+ };
235
+ const splitTableCells = (row) => {
236
+ let s = row.trim();
237
+ if (s.startsWith('|'))
238
+ s = s.slice(1);
239
+ if (s.endsWith('|') && !s.endsWith('\\|'))
240
+ s = s.slice(0, -1);
241
+ const cells = [];
242
+ let cur = '';
243
+ for (let i = 0; i < s.length; i++) {
244
+ if (s[i] === '\\' && s[i + 1] === '|') {
245
+ cur += '|';
246
+ i++;
247
+ continue;
248
+ }
249
+ if (s[i] === '|') {
250
+ cells.push(cur.trim());
251
+ cur = '';
252
+ continue;
253
+ }
254
+ cur += s[i];
255
+ }
256
+ cells.push(cur.trim());
257
+ return cells;
258
+ };
259
+ const isTableSeparator = (line) => {
260
+ if (!line?.includes('-'))
261
+ return false;
262
+ const cells = splitTableCells(line);
263
+ return cells.length > 0 && cells.every(c => /^:?-+:?$/.test(c));
264
+ };
265
+ const getCellAlign = (sep) => {
266
+ const left = sep.startsWith(':');
267
+ const right = sep.endsWith(':');
268
+ if (left && right)
269
+ return 'center';
270
+ if (right)
271
+ return 'right';
272
+ if (left)
273
+ return 'left';
274
+ return undefined;
275
+ };
276
+ //#endregion
277
+ const startsBlock = (lines, idx) => {
278
+ const line = lines[idx];
279
+ if (line.trim() === '')
280
+ return true;
281
+ if (line.trim().startsWith('```'))
282
+ return true;
283
+ if (/^#{1,6}\s+/.test(line))
284
+ return true;
285
+ if (/^\s*[-*+]\s+/.test(line))
286
+ return true;
287
+ if (/^\s*\d+\.\s+/.test(line))
288
+ return true;
289
+ if (/^\s*>\s?/.test(line))
290
+ return true;
291
+ if (/^\s*(-{3,}|\*{3,}|_{3,})\s*$/.test(line))
292
+ return true;
293
+ if (line.includes('|') && isTableSeparator(lines[idx + 1]))
294
+ return true;
295
+ return false;
296
+ };
297
+ const renderMarkdown = (raw) => {
298
+ const lines = raw.replace(/\r\n/g, '\n').split('\n');
299
+ const blocks = [];
300
+ let i = 0;
301
+ let key = 0;
302
+ while (i < lines.length) {
303
+ const line = lines[i];
304
+ if (line.trim().startsWith('```')) {
305
+ const codeLines = [];
306
+ i++;
307
+ while (i < lines.length && !lines[i].trim().startsWith('```')) {
308
+ codeLines.push(lines[i]);
309
+ i++;
310
+ }
311
+ i++;
312
+ blocks.push(_jsx(MdPre, { children: codeLines.join('\n') }, `b-${key++}`));
313
+ continue;
314
+ }
315
+ if (line.includes('|') && isTableSeparator(lines[i + 1])) {
316
+ const headers = splitTableCells(line);
317
+ const aligns = splitTableCells(lines[i + 1]).map(getCellAlign);
318
+ i += 2;
319
+ const rows = [];
320
+ while (i < lines.length && lines[i].trim() !== '' && lines[i].includes('|')) {
321
+ rows.push(splitTableCells(lines[i]));
322
+ i++;
323
+ }
324
+ const tKey = key++;
325
+ 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}`));
326
+ continue;
327
+ }
328
+ if (/^\s*(-{3,}|\*{3,}|_{3,})\s*$/.test(line)) {
329
+ blocks.push(_jsx(MdHr, {}, `b-${key++}`));
330
+ i++;
331
+ continue;
332
+ }
333
+ if (/^\s*>\s?/.test(line)) {
334
+ const quoteLines = [];
335
+ while (i < lines.length && /^\s*>\s?/.test(lines[i])) {
336
+ quoteLines.push(lines[i].replace(/^\s*>\s?/, ''));
337
+ i++;
338
+ }
339
+ blocks.push(_jsx(MdBlockquote, { children: renderMarkdown(quoteLines.join('\n')) }, `b-${key++}`));
340
+ continue;
341
+ }
342
+ const heading = line.match(/^(#{1,6})\s+(.*)$/);
343
+ if (heading) {
344
+ const level = heading[1].length;
345
+ blocks.push(_jsx(MdHeading, { $level: level, children: renderInline(heading[2], `h-${key}`) }, `b-${key}`));
346
+ key++;
347
+ i++;
348
+ continue;
349
+ }
350
+ if (/^\s*[-*+]\s+/.test(line)) {
351
+ const items = [];
352
+ while (i < lines.length && /^\s*[-*+]\s+/.test(lines[i])) {
353
+ const content = lines[i].replace(/^\s*[-*+]\s+/, '');
354
+ items.push(_jsx("li", { children: renderInline(content, `li-${key}-${items.length}`) }, `li-${key}-${items.length}`));
355
+ i++;
356
+ }
357
+ blocks.push(_jsx(MdUl, { children: items }, `b-${key++}`));
358
+ continue;
359
+ }
360
+ if (/^\s*\d+\.\s+/.test(line)) {
361
+ const items = [];
362
+ while (i < lines.length && /^\s*\d+\.\s+/.test(lines[i])) {
363
+ const content = lines[i].replace(/^\s*\d+\.\s+/, '');
364
+ items.push(_jsx("li", { children: renderInline(content, `oi-${key}-${items.length}`) }, `oi-${key}-${items.length}`));
365
+ i++;
366
+ }
367
+ blocks.push(_jsx(MdOl, { children: items }, `b-${key++}`));
368
+ continue;
369
+ }
370
+ if (line.trim() === '') {
371
+ i++;
372
+ continue;
373
+ }
374
+ const paraLines = [];
375
+ while (i < lines.length && !startsBlock(lines, i)) {
376
+ paraLines.push(lines[i]);
377
+ i++;
378
+ }
379
+ const paraNodes = paraLines.flatMap((pl, idx) => {
380
+ const inline = renderInline(pl, `p-${key}-${idx}`);
381
+ return idx === 0 ? inline : [_jsx("br", {}, `br-${key}-${idx}`), ...inline];
382
+ });
383
+ blocks.push(_jsx(MdParagraph, { children: paraNodes }, `b-${key++}`));
384
+ }
385
+ return blocks;
386
+ };
387
+ //#endregion
388
+ //#region Icons
389
+ function IconClose(props) {
390
+ 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" }) }));
391
+ }
392
+ function IconSendFilled(props) {
393
+ 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" })] })] }));
394
+ }
395
+ function IconNewChat(props) {
396
+ 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" }) }));
397
+ }
398
+ //#endregion
399
+ //#region Styled Components
400
+ const fadeIn = keyframes `
401
+ from { opacity: 0; }
402
+ to { opacity: 1; }
403
+ `;
404
+ const slideInRight = keyframes `
405
+ from { transform: translateX(100%); }
406
+ to { transform: translateX(0); }
407
+ `;
408
+ const phraseIn = keyframes `
409
+ from { opacity: 0; transform: translateY(4px); }
410
+ to { opacity: 1; transform: translateY(0); }
411
+ `;
412
+ const dotCycle = keyframes `
413
+ 0% { opacity: 0; }
414
+ 25%, 75% { opacity: 1; }
415
+ 100% { opacity: 0; }
416
+ `;
417
+ const ToppyHeaderButton = styled.button `
418
+ display: flex;
419
+ align-items: center;
420
+ gap: 8px;
421
+ height: 36px;
422
+ padding: 0 14px 0 5px;
423
+ border-radius: 18px;
424
+ border: 1px solid ${TMColors.primary}35;
425
+ background: ${TMColors.primary}0d;
426
+ color: ${TMColors.primary};
427
+ font-size: 13px;
428
+ font-weight: 600;
429
+ white-space: nowrap;
430
+ cursor: pointer;
431
+ flex-shrink: 0;
432
+ transition: all 0.2s ease;
433
+
434
+ &:hover {
435
+ background: ${TMColors.primary}1a;
436
+ border-color: ${TMColors.primary}66;
437
+ transform: translateY(-1px);
438
+ box-shadow: 0 4px 12px ${TMColors.primary}25;
439
+ }
440
+ &:active { transform: translateY(0); }
441
+ `;
442
+ const ToppyHeaderAvatar = styled.img `
443
+ width: 28px;
444
+ height: 28px;
445
+ border-radius: 50%;
446
+ object-fit: contain;
447
+ pointer-events: none;
448
+ `;
449
+ const ToppyHeaderText = styled.span `
450
+ line-height: 1;
451
+ `;
452
+ const Fab = styled.button `
453
+ position: fixed;
454
+ bottom: 24px;
455
+ right: 24px;
456
+ width: 60px;
457
+ height: 60px;
458
+ border-radius: 50%;
459
+ border: none;
460
+ padding: 0;
461
+ cursor: pointer;
462
+ display: flex;
463
+ align-items: center;
464
+ justify-content: center;
465
+ background: white;
466
+ box-shadow: 0 6px 20px rgba(0, 0, 0, 0.25);
467
+ z-index: 100000;
468
+ transition: transform 0.2s ease, box-shadow 0.2s ease;
469
+ animation: ${fadeIn} 0.3s ease-out;
470
+
471
+ &:hover { transform: scale(1.08); box-shadow: 0 8px 26px rgba(0, 0, 0, 0.3); }
472
+ &:active { transform: scale(0.96); }
473
+ `;
474
+ const FabAvatar = styled.img `
475
+ width: 52px;
476
+ height: 52px;
477
+ border-radius: 50%;
478
+ object-fit: contain;
479
+ pointer-events: none;
480
+ `;
481
+ const Overlay = styled.div `
482
+ position: fixed;
483
+ inset: 0;
484
+ background: rgba(0, 0, 0, 0.45);
485
+ z-index: 100000;
486
+ animation: ${fadeIn} 0.2s ease-out;
487
+ `;
488
+ const PanelContainer = styled.div `
489
+ position: fixed;
490
+ top: 0;
491
+ right: 0;
492
+ height: 100vh;
493
+ width: ${props => props.$width}px;
494
+ max-width: 100vw;
495
+ background: white;
496
+ display: flex;
497
+ flex-direction: column;
498
+ box-shadow: -8px 0 32px rgba(0, 0, 0, 0.28);
499
+ z-index: 100001;
500
+ animation: ${slideInRight} 0.25s ease-out;
501
+ `;
502
+ const ResizeHandle = styled.div `
503
+ position: absolute;
504
+ left: 0;
505
+ top: 0;
506
+ bottom: 0;
507
+ width: 6px;
508
+ cursor: col-resize;
509
+ background: transparent;
510
+ z-index: 2;
511
+ transition: background 0.2s ease;
512
+
513
+ &:hover { background: ${TMColors.primary}55; }
514
+ `;
515
+ const ChatHeader = styled.div `
516
+ display: flex;
517
+ align-items: center;
518
+ justify-content: space-between;
519
+ padding: 16px 20px;
520
+ background: linear-gradient(135deg, ${TMColors.primary} 0%, ${TMColors.primary}dd 100%);
521
+ color: white;
522
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
523
+ `;
524
+ const HeaderLeft = styled.div `
525
+ display: flex;
526
+ align-items: center;
527
+ gap: 12px;
528
+ flex: 1;
529
+ min-width: 0;
530
+ `;
531
+ const HeaderRight = styled.div `
532
+ display: flex;
533
+ align-items: center;
534
+ gap: 8px;
535
+ margin-left: 12px;
536
+ flex-shrink: 0;
537
+ `;
538
+ const ToppyAvatar = styled.img `
539
+ width: 44px;
540
+ height: 44px;
541
+ border-radius: 50%;
542
+ background: white;
543
+ padding: 4px;
544
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
545
+ flex-shrink: 0;
546
+ object-fit: contain;
547
+ `;
548
+ const HeaderText = styled.div `
549
+ display: flex;
550
+ flex-direction: column;
551
+ gap: 2px;
552
+ min-width: 0;
553
+ `;
554
+ const HeaderGreeting = styled.h2 `
555
+ margin: 0;
556
+ font-size: 17px;
557
+ font-weight: 600;
558
+ color: white;
559
+ white-space: nowrap;
560
+ overflow: hidden;
561
+ text-overflow: ellipsis;
562
+ `;
563
+ const HeaderQuestion = styled.p `
564
+ margin: 0;
565
+ font-size: 13px;
566
+ color: rgba(255, 255, 255, 0.9);
567
+ `;
568
+ const HeaderButton = styled.button `
569
+ width: 32px;
570
+ height: 32px;
571
+ border-radius: 50%;
572
+ background: rgba(255, 255, 255, 0.2);
573
+ border: 1px solid rgba(255, 255, 255, 0.3);
574
+ color: white;
575
+ cursor: pointer;
576
+ display: flex;
577
+ align-items: center;
578
+ justify-content: center;
579
+ flex-shrink: 0;
580
+ transition: all 0.2s ease;
581
+
582
+ &:hover:not(:disabled) { background: rgba(255, 255, 255, 0.3); transform: scale(1.05); }
583
+ &:active:not(:disabled) { transform: scale(0.95); }
584
+ &:disabled { opacity: 0.45; cursor: default; }
585
+ `;
586
+ const ChatBody = styled.div `
587
+ flex: 1;
588
+ padding: 20px;
589
+ overflow-y: auto;
590
+ background: linear-gradient(to bottom, #f8f9fa 0%, #ffffff 100%);
591
+ `;
592
+ const WelcomeMessage = styled.div `
593
+ display: flex;
594
+ gap: 16px;
595
+ padding: 18px;
596
+ background: white;
597
+ border-radius: 12px;
598
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
599
+ border-left: 4px solid ${TMColors.primary};
600
+ animation: ${fadeIn} 0.5s ease-out;
601
+ `;
602
+ const WelcomeIcon = styled.div `
603
+ font-size: 30px;
604
+ flex-shrink: 0;
605
+ `;
606
+ const WelcomeText = styled.p `
607
+ margin: 0;
608
+ font-size: 14px;
609
+ line-height: 1.6;
610
+ color: #242424;
611
+
612
+ strong { color: ${TMColors.primary}; font-weight: 600; }
613
+ `;
614
+ const MessageBubble = styled.div `
615
+ display: flex;
616
+ gap: 10px;
617
+ margin-bottom: 16px;
618
+ align-items: flex-start;
619
+ justify-content: ${props => (props.$isUser ? 'flex-end' : 'flex-start')};
620
+ animation: ${fadeIn} 0.3s ease-out;
621
+ `;
622
+ const BotAvatar = styled.img `
623
+ width: 32px;
624
+ height: 32px;
625
+ border-radius: 50%;
626
+ background: white;
627
+ padding: 2px;
628
+ box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
629
+ flex-shrink: 0;
630
+ object-fit: contain;
631
+ `;
632
+ const MessageContent = styled.div `
633
+ max-width: 80%;
634
+ padding: 10px 14px;
635
+ border-radius: 12px;
636
+ font-size: 14px;
637
+ line-height: 1.5;
638
+ background: ${props => (props.$isUser ? TMColors.primary : '#f0f2f5')};
639
+ color: ${props => (props.$isUser ? 'white' : '#242424')};
640
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
641
+ word-wrap: break-word;
642
+ overflow-wrap: anywhere;
643
+ white-space: ${props => (props.$isUser ? 'pre-wrap' : 'normal')};
644
+ border-bottom-${props => (props.$isUser ? 'right' : 'left')}-radius: 4px;
645
+ `;
646
+ const MarkdownContent = styled.div `
647
+ & > *:first-child { margin-top: 0; }
648
+ & > *:last-child { margin-bottom: 0; }
649
+
650
+ a { color: ${TMColors.primary}; text-decoration: underline; }
651
+ strong { font-weight: 600; }
652
+ `;
653
+ const MdParagraph = styled.p `
654
+ margin: 0 0 8px 0;
655
+ line-height: 1.55;
656
+ `;
657
+ const MdHeading = styled.div `
658
+ margin: 12px 0 6px 0;
659
+ font-weight: 700;
660
+ line-height: 1.3;
661
+ font-size: ${props => `${Math.max(14, 20 - (props.$level - 1) * 2)}px`};
662
+ `;
663
+ const MdUl = styled.ul `
664
+ margin: 4px 0 8px 0;
665
+ padding-left: 20px;
666
+ li { margin: 2px 0; line-height: 1.5; }
667
+ `;
668
+ const MdOl = styled.ol `
669
+ margin: 4px 0 8px 0;
670
+ padding-left: 22px;
671
+ li { margin: 2px 0; line-height: 1.5; }
672
+ `;
673
+ const MdCode = styled.code `
674
+ background: rgba(0, 0, 0, 0.06);
675
+ padding: 1px 5px;
676
+ border-radius: 4px;
677
+ font-family: 'Consolas', 'Monaco', monospace;
678
+ font-size: 0.9em;
679
+ `;
680
+ const MdPre = styled.pre `
681
+ background: rgba(0, 0, 0, 0.06);
682
+ padding: 10px 12px;
683
+ border-radius: 8px;
684
+ overflow-x: auto;
685
+ margin: 8px 0;
686
+ font-family: 'Consolas', 'Monaco', monospace;
687
+ font-size: 0.88em;
688
+ white-space: pre;
689
+ `;
690
+ const MdTableWrapper = styled.div `
691
+ margin: 8px 0;
692
+ max-width: 100%;
693
+ overflow-x: auto;
694
+ border: 1px solid #dcdfe3;
695
+ border-radius: 8px;
696
+
697
+ &::-webkit-scrollbar { height: 6px; }
698
+ &::-webkit-scrollbar-track { background: transparent; }
699
+ &::-webkit-scrollbar-thumb { background: #ccc; border-radius: 3px; }
700
+ &::-webkit-scrollbar-thumb:hover { background: #999; }
701
+ `;
702
+ const MdTable = styled.table `
703
+ border-collapse: collapse;
704
+ width: 100%;
705
+ font-size: 0.92em;
706
+ background: white;
707
+ `;
708
+ const MdTh = styled.th `
709
+ padding: 7px 10px;
710
+ background: ${TMColors.primary}14;
711
+ color: #242424;
712
+ font-weight: 600;
713
+ text-align: ${props => props.$align ?? 'left'};
714
+ border-bottom: 1px solid #dcdfe3;
715
+ white-space: nowrap;
716
+
717
+ &:not(:last-child) { border-right: 1px solid #e6e8eb; }
718
+ `;
719
+ const MdTd = styled.td `
720
+ padding: 7px 10px;
721
+ text-align: ${props => props.$align ?? 'left'};
722
+ vertical-align: top;
723
+ border-top: 1px solid #eceef0;
724
+
725
+ &:not(:last-child) { border-right: 1px solid #eceef0; }
726
+
727
+ tr:nth-child(even) & { background: #fafbfc; }
728
+ `;
729
+ const MdBlockquote = styled.blockquote `
730
+ margin: 8px 0;
731
+ padding: 6px 12px;
732
+ border-left: 3px solid ${TMColors.primary}66;
733
+ background: ${TMColors.primary}0a;
734
+ border-radius: 0 6px 6px 0;
735
+ color: #444;
736
+
737
+ & > *:first-child { margin-top: 0; }
738
+ & > *:last-child { margin-bottom: 0; }
739
+ `;
740
+ const MdHr = styled.hr `
741
+ border: none;
742
+ border-top: 1px solid #dcdfe3;
743
+ margin: 12px 0;
744
+ `;
745
+ const ThinkingIndicator = styled.div `
746
+ display: flex;
747
+ align-items: center;
748
+ gap: 10px;
749
+ max-width: 80%;
750
+ padding: 7px 12px;
751
+ background: #f0f2f5;
752
+ border-radius: 12px;
753
+ border-bottom-left-radius: 4px;
754
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
755
+ `;
756
+ const ThinkingCaption = styled.div `
757
+ display: flex;
758
+ flex-direction: column;
759
+ align-items: flex-start;
760
+ gap: 0;
761
+ min-width: 0;
762
+ `;
763
+ const ThinkingPhrase = styled.span `
764
+ display: inline-flex;
765
+ align-items: center;
766
+ min-width: 0;
767
+ font-size: 12px;
768
+ font-style: italic;
769
+ line-height: 1.15;
770
+ color: #6b7280;
771
+ animation: ${phraseIn} 0.25s ease-out;
772
+ `;
773
+ const ThinkingDots = styled.span `
774
+ display: inline-flex;
775
+ width: 12px;
776
+ flex-shrink: 0;
777
+ `;
778
+ const ThinkingDot = styled.span `
779
+ animation: ${dotCycle} 1.2s linear infinite;
780
+ animation-delay: ${props => props.$delay}s;
781
+ will-change: opacity;
782
+
783
+ @media (prefers-reduced-motion: reduce) {
784
+ animation: none;
785
+ opacity: 1;
786
+ }
787
+ `;
788
+ const ThinkingCounter = styled.span `
789
+ margin-top: 2px;
790
+ font-size: 10px;
791
+ font-weight: 600;
792
+ line-height: 1.1;
793
+ letter-spacing: 0.02em;
794
+ color: ${TMColors.primary}b3;
795
+ font-variant-numeric: tabular-nums;
796
+ font-feature-settings: 'tnum';
797
+ opacity: ${props => (props.$visible ? 1 : 0)};
798
+ transition: opacity 0.3s ease;
799
+ `;
800
+ const ChatFooter = styled.div `
801
+ padding: 16px 20px;
802
+ background: white;
803
+ border-top: 1px solid #e1e5e9;
804
+ box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.05);
805
+ `;
806
+ const FooterHint = styled.p `
807
+ margin: 6px 0 0 0;
808
+ font-size: 11px;
809
+ color: #999;
810
+ text-align: center;
811
+ `;
812
+ const ChatInputWrapper = styled.div `
813
+ position: relative;
814
+ flex: 1;
815
+ display: flex;
816
+ `;
817
+ const ChatInputTextarea = styled.textarea `
818
+ width: 100%;
819
+ padding: 14px 60px 14px 16px;
820
+ border: 2px solid #e1e5e9;
821
+ border-radius: 12px;
822
+ font-size: 15px;
823
+ font-family: inherit;
824
+ line-height: 1.5;
825
+ transition: all 0.2s ease;
826
+ background: #f8f9fa;
827
+ resize: none;
828
+ min-height: 100px;
829
+ max-height: 120px;
830
+ overflow-y: hidden;
831
+
832
+ &:focus {
833
+ outline: none;
834
+ border-color: ${TMColors.primary};
835
+ background: white;
836
+ box-shadow: 0 0 0 4px ${TMColors.primary}15;
837
+ }
838
+
839
+ &::placeholder {
840
+ color: #999;
841
+ }
842
+
843
+ &::-webkit-scrollbar {
844
+ width: 6px;
845
+ }
846
+
847
+ &::-webkit-scrollbar-track {
848
+ background: transparent;
849
+ }
850
+
851
+ &::-webkit-scrollbar-thumb {
852
+ background: #ccc;
853
+ border-radius: 3px;
854
+ }
855
+
856
+ &::-webkit-scrollbar-thumb:hover {
857
+ background: #999;
858
+ }
859
+ `;
860
+ const InlineSendButton = styled.button `
861
+ position: absolute;
862
+ bottom: 8px;
863
+ right: 8px;
864
+ width: 40px;
865
+ height: 40px;
866
+ border-radius: 10px;
867
+ background: ${props => props.$disabled ? '#ccc' : '#4caf50'};
868
+ border: none;
869
+ color: white;
870
+ cursor: ${props => props.$disabled ? 'default' : 'pointer'};
871
+ display: flex;
872
+ align-items: center;
873
+ justify-content: center;
874
+ transition: all 0.2s ease;
875
+
876
+ &:hover:not(:disabled) {
877
+ background: #45a049;
878
+ transform: scale(1.05);
879
+ }
880
+
881
+ &:active:not(:disabled) {
882
+ transform: scale(0.95);
883
+ }
884
+
885
+ &:disabled {
886
+ opacity: 0.6;
887
+ }
888
+ `;