@messenger-box/tailwind-ui-inbox 10.0.3-alpha.71 → 10.0.3-alpha.73

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 (143) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/lib/components/AIAgent/AIAgent.d.ts +14 -0
  3. package/lib/components/AIAgent/AIAgent.d.ts.map +1 -0
  4. package/lib/components/AIAgent/AIAgent.js +1148 -0
  5. package/lib/components/AIAgent/AIAgent.js.map +1 -0
  6. package/lib/components/AIAgent/index.d.ts +2 -0
  7. package/lib/components/AIAgent/index.d.ts.map +1 -0
  8. package/lib/components/InboxMessage/InputComponent.d.ts +9 -0
  9. package/lib/components/InboxMessage/InputComponent.d.ts.map +1 -0
  10. package/lib/components/InboxMessage/InputComponent.js +210 -0
  11. package/lib/components/InboxMessage/InputComponent.js.map +1 -0
  12. package/lib/components/InboxMessage/MessageInput.d.ts.map +1 -1
  13. package/lib/components/InboxMessage/MessageInput.js +14 -10
  14. package/lib/components/InboxMessage/MessageInput.js.map +1 -1
  15. package/lib/components/InboxMessage/MessageInputComponent.d.ts +9 -0
  16. package/lib/components/InboxMessage/MessageInputComponent.d.ts.map +1 -0
  17. package/lib/components/InboxMessage/Messages.d.ts.map +1 -1
  18. package/lib/components/InboxMessage/Messages.js +4 -54
  19. package/lib/components/InboxMessage/Messages.js.map +1 -1
  20. package/lib/components/InboxMessage/MessagesBuilderUi.d.ts +17 -0
  21. package/lib/components/InboxMessage/MessagesBuilderUi.d.ts.map +1 -0
  22. package/lib/components/InboxMessage/UploadImageButton.d.ts +1 -0
  23. package/lib/components/InboxMessage/UploadImageButton.d.ts.map +1 -1
  24. package/lib/components/InboxMessage/UploadImageButton.js +3 -3
  25. package/lib/components/InboxMessage/UploadImageButton.js.map +1 -1
  26. package/lib/components/InboxMessage/index.d.ts +3 -0
  27. package/lib/components/InboxMessage/index.d.ts.map +1 -1
  28. package/lib/components/InboxMessage/message-widgets/CommonMessage.d.ts.map +1 -1
  29. package/lib/components/InboxMessage/message-widgets/CommonMessage.js +11 -6
  30. package/lib/components/InboxMessage/message-widgets/CommonMessage.js.map +1 -1
  31. package/lib/components/InboxMessage/message-widgets/ModernMessageGroup.d.ts +14 -0
  32. package/lib/components/InboxMessage/message-widgets/ModernMessageGroup.d.ts.map +1 -0
  33. package/lib/components/InboxMessage/message-widgets/ModernMessageGroup.js +1525 -0
  34. package/lib/components/InboxMessage/message-widgets/ModernMessageGroup.js.map +1 -0
  35. package/lib/components/InboxMessage/message-widgets/PlainMessage.d.ts.map +1 -1
  36. package/lib/components/InboxMessage/message-widgets/PlainMessage.js +6 -3
  37. package/lib/components/InboxMessage/message-widgets/PlainMessage.js.map +1 -1
  38. package/lib/components/InboxMessage/message-widgets/SlackLikeMessageGroup.d.ts.map +1 -1
  39. package/lib/components/InboxMessage/message-widgets/SlackLikeMessageGroup.js +207 -12
  40. package/lib/components/InboxMessage/message-widgets/SlackLikeMessageGroup.js.map +1 -1
  41. package/lib/components/InboxMessage/message-widgets/index.d.ts +1 -0
  42. package/lib/components/InboxMessage/message-widgets/index.d.ts.map +1 -1
  43. package/lib/components/index.d.ts +2 -1
  44. package/lib/components/index.d.ts.map +1 -1
  45. package/lib/compute.d.ts.map +1 -1
  46. package/lib/compute.js +79 -3
  47. package/lib/compute.js.map +1 -1
  48. package/lib/config/env-config.d.ts +6 -0
  49. package/lib/config/env-config.d.ts.map +1 -1
  50. package/lib/config/env-config.js +19 -1
  51. package/lib/config/env-config.js.map +1 -1
  52. package/lib/container/AiInbox.d.ts +15 -0
  53. package/lib/container/AiInbox.d.ts.map +1 -0
  54. package/lib/container/AiInboxWithLoader.d.ts +36 -0
  55. package/lib/container/AiInboxWithLoader.d.ts.map +1 -0
  56. package/lib/container/AiLandingInput.d.ts +4 -0
  57. package/lib/container/AiLandingInput.d.ts.map +1 -0
  58. package/lib/container/AiLandingInput.js +164 -0
  59. package/lib/container/AiLandingInput.js.map +1 -0
  60. package/lib/container/Inbox.d.ts.map +1 -1
  61. package/lib/container/Inbox.js +6 -4
  62. package/lib/container/Inbox.js.map +1 -1
  63. package/lib/container/InboxAiMessagesLoader.d.ts +36 -0
  64. package/lib/container/InboxAiMessagesLoader.d.ts.map +1 -0
  65. package/lib/container/InboxAiMessagesLoader.js +44 -0
  66. package/lib/container/InboxAiMessagesLoader.js.map +1 -0
  67. package/lib/container/InboxContainer.d.ts +12 -0
  68. package/lib/container/InboxContainer.d.ts.map +1 -0
  69. package/lib/container/InboxContainer.js +31 -0
  70. package/lib/container/InboxContainer.js.map +1 -0
  71. package/lib/container/InboxTemplate1.d.ts +15 -0
  72. package/lib/container/InboxTemplate1.d.ts.map +1 -0
  73. package/lib/container/InboxTemplate1WithLoader.d.ts +36 -0
  74. package/lib/container/InboxTemplate1WithLoader.d.ts.map +1 -0
  75. package/lib/container/InboxTemplate2.d.ts +15 -0
  76. package/lib/container/InboxTemplate2.d.ts.map +1 -0
  77. package/lib/container/InboxWithAiLoader.d.ts +15 -0
  78. package/lib/container/InboxWithAiLoader.d.ts.map +1 -0
  79. package/lib/container/InboxWithAiLoader.js +56 -0
  80. package/lib/container/InboxWithAiLoader.js.map +1 -0
  81. package/lib/container/ServiceInbox.js +1 -1
  82. package/lib/container/ServiceInbox.js.map +1 -1
  83. package/lib/container/ThreadMessages.js +1 -1
  84. package/lib/container/ThreadMessages.js.map +1 -1
  85. package/lib/container/ThreadMessagesInbox.js +1 -1
  86. package/lib/container/ThreadMessagesInbox.js.map +1 -1
  87. package/lib/container/Threads.js +1 -1
  88. package/lib/container/Threads.js.map +1 -1
  89. package/lib/container/index.d.ts +4 -1
  90. package/lib/container/index.d.ts.map +1 -1
  91. package/lib/index.d.ts +3 -2
  92. package/lib/index.d.ts.map +1 -1
  93. package/lib/index.js +1 -1
  94. package/lib/machines/aiAgentMachine.d.ts +3 -0
  95. package/lib/machines/aiAgentMachine.d.ts.map +1 -0
  96. package/lib/machines/aiAgentMachine.js +1040 -0
  97. package/lib/machines/aiAgentMachine.js.map +1 -0
  98. package/lib/machines/types.d.ts +77 -0
  99. package/lib/machines/types.d.ts.map +1 -0
  100. package/lib/routes.json +40 -0
  101. package/lib/templates/InboxWithAi.d.ts +15 -0
  102. package/lib/templates/InboxWithAi.d.ts.map +1 -0
  103. package/lib/templates/InboxWithAi.js +405 -0
  104. package/lib/templates/InboxWithAi.js.map +1 -0
  105. package/lib/templates/InboxWithAi.tsx +502 -0
  106. package/lib/templates/index.d.ts +2 -0
  107. package/lib/templates/index.d.ts.map +1 -0
  108. package/lib/templates/index.ts +1 -0
  109. package/package.json +7 -5
  110. package/src/components/AIAgent/AIAgent.tsx +1351 -0
  111. package/src/components/AIAgent/README.md +82 -0
  112. package/src/components/AIAgent/index.ts +1 -0
  113. package/src/components/InboxMessage/InputComponent.tsx +263 -0
  114. package/src/components/InboxMessage/MessageInput.tsx +73 -66
  115. package/src/components/InboxMessage/MessageInputComponent.tsx +245 -0
  116. package/src/components/InboxMessage/Messages.tsx +2 -56
  117. package/src/components/InboxMessage/MessagesBuilderUi.tsx +205 -0
  118. package/src/components/InboxMessage/UploadImageButton.tsx +3 -2
  119. package/src/components/InboxMessage/index.ts +3 -0
  120. package/src/components/InboxMessage/message-widgets/CommonMessage.tsx +39 -21
  121. package/src/components/InboxMessage/message-widgets/ModernMessageGroup.tsx +1968 -0
  122. package/src/components/InboxMessage/message-widgets/PlainMessage.tsx +6 -2
  123. package/src/components/InboxMessage/message-widgets/SlackLikeMessageGroup.tsx +306 -54
  124. package/src/components/InboxMessage/message-widgets/index.ts +1 -0
  125. package/src/components/index.ts +4 -0
  126. package/src/compute.ts +83 -2
  127. package/src/config/env-config.ts +6 -0
  128. package/src/container/AiInbox.tsx +1796 -0
  129. package/src/container/AiInboxWithLoader.tsx +356 -0
  130. package/src/container/AiLandingInput.tsx +168 -0
  131. package/src/container/Inbox.tsx +8 -5
  132. package/src/container/InboxAiMessagesLoader.tsx +58 -0
  133. package/src/container/InboxContainer.tsx +35 -0
  134. package/src/container/InboxTemplate1.tsx +1542 -0
  135. package/src/container/InboxTemplate1WithLoader.tsx +338 -0
  136. package/src/container/InboxTemplate2.tsx +1606 -0
  137. package/src/container/InboxWithAiLoader.tsx +76 -0
  138. package/src/container/index.ts +21 -1
  139. package/src/index.ts +12 -1
  140. package/src/machines/aiAgentMachine.ts +1248 -0
  141. package/src/machines/types.ts +59 -0
  142. package/src/templates/InboxWithAi.tsx +502 -0
  143. package/src/templates/index.ts +1 -0
@@ -0,0 +1,1525 @@
1
+ import React__default,{useEffect}from'react';import {format,differenceInMinutes}from'date-fns';import {FilesList}from'../../inbox/FilesList.js';import'../../inbox/MessageItem.js';import'../../inbox/ThreadItem.js';// Enhanced CSS styles for HTML content rendering with prettification
2
+ const htmlContentStyles = `
3
+ .html-content {
4
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
5
+ line-height: 1.6;
6
+ color: #374151;
7
+ }
8
+
9
+ .html-content h1, .html-content h2, .html-content h3, .html-content h4, .html-content h5, .html-content h6 {
10
+ margin-top: 1.5rem;
11
+ margin-bottom: 1rem;
12
+ font-weight: 600;
13
+ line-height: 1.25;
14
+ color: #111827;
15
+ }
16
+
17
+ .html-content h1 {
18
+ font-size: 1.875rem;
19
+ border-bottom: 2px solid #e5e7eb;
20
+ padding-bottom: 0.5rem;
21
+ }
22
+
23
+ .html-content h2 {
24
+ font-size: 1.5rem;
25
+ border-bottom: 1px solid #e5e7eb;
26
+ padding-bottom: 0.375rem;
27
+ }
28
+
29
+ .html-content h3 {
30
+ font-size: 1.25rem;
31
+ }
32
+
33
+ .html-content p {
34
+ margin-bottom: 1rem;
35
+ line-height: 1.7;
36
+ }
37
+
38
+ .html-content ul, .html-content ol {
39
+ margin-bottom: 1rem;
40
+ padding-left: 1.5rem;
41
+ }
42
+
43
+ .html-content ul {
44
+ list-style-type: disc;
45
+ }
46
+
47
+ .html-content ol {
48
+ list-style-type: decimal;
49
+ }
50
+
51
+ .html-content li {
52
+ margin-bottom: 0.5rem;
53
+ line-height: 1.6;
54
+ }
55
+
56
+ .html-content li > ul, .html-content li > ol {
57
+ margin-top: 0.5rem;
58
+ margin-bottom: 0.5rem;
59
+ }
60
+
61
+ .html-content a {
62
+ color: #2563eb;
63
+ text-decoration: none;
64
+ border-bottom: 1px solid transparent;
65
+ transition: all 0.2s ease;
66
+ }
67
+
68
+ .html-content a:hover {
69
+ color: #1d4ed8;
70
+ border-bottom-color: #1d4ed8;
71
+ }
72
+
73
+ .html-content strong, .html-content b {
74
+ font-weight: 600;
75
+ color: #111827;
76
+ }
77
+
78
+ .html-content em, .html-content i {
79
+ font-style: italic;
80
+ color: #6b7280;
81
+ }
82
+
83
+ .html-content code {
84
+ background-color: #f3f4f6;
85
+ padding: 0.25rem 0.5rem;
86
+ border-radius: 0.375rem;
87
+ font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace;
88
+ font-size: 0.875rem;
89
+ color: #dc2626;
90
+ border: 1px solid #e5e7eb;
91
+ }
92
+
93
+ .html-content pre {
94
+ background-color: #f9fafb;
95
+ padding: 1rem;
96
+ border-radius: 0.5rem;
97
+ overflow-x: auto;
98
+ font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace;
99
+ font-size: 0.875rem;
100
+ line-height: 1.5;
101
+ border: 1px solid #e5e7eb;
102
+ margin: 1.5rem 0;
103
+ }
104
+
105
+ .html-content pre code {
106
+ background-color: transparent;
107
+ padding: 0;
108
+ border: none;
109
+ color: #374151;
110
+ font-size: inherit;
111
+ }
112
+
113
+ .html-content blockquote {
114
+ border-left: 4px solid #3b82f6;
115
+ padding-left: 1rem;
116
+ margin: 1.5rem 0;
117
+ font-style: italic;
118
+ color: #6b7280;
119
+ background-color: #f8fafc;
120
+ padding: 1rem;
121
+ border-radius: 0.375rem;
122
+ }
123
+
124
+ .html-content blockquote p {
125
+ margin-bottom: 0;
126
+ }
127
+
128
+ .html-content table {
129
+ border-collapse: collapse;
130
+ border: 1px solid #e5e7eb;
131
+ width: 100%;
132
+ margin: 1.5rem 0;
133
+ border-radius: 0.5rem;
134
+ overflow: hidden;
135
+ box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1);
136
+ }
137
+
138
+ .html-content th,
139
+ .html-content td {
140
+ border: 1px solid #e5e7eb;
141
+ padding: 0.75rem;
142
+ text-align: left;
143
+ vertical-align: top;
144
+ }
145
+
146
+ .html-content th {
147
+ background-color: #f9fafb;
148
+ font-weight: 600;
149
+ color: #111827;
150
+ border-bottom: 2px solid #e5e7eb;
151
+ }
152
+
153
+ .html-content tr:nth-child(even) {
154
+ background-color: #f9fafb;
155
+ }
156
+
157
+ .html-content tr:hover {
158
+ background-color: #f3f4f6;
159
+ }
160
+
161
+ .html-content hr {
162
+ border: none;
163
+ border-top: 2px solid #e5e7eb;
164
+ margin: 2rem 0;
165
+ }
166
+
167
+ .html-content img {
168
+ max-width: 100%;
169
+ height: auto;
170
+ border-radius: 0.5rem;
171
+ margin: 1rem 0;
172
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
173
+ }
174
+
175
+ .html-content .highlight {
176
+ background-color: #fef3c7;
177
+ padding: 0.25rem 0.5rem;
178
+ border-radius: 0.25rem;
179
+ border: 1px solid #f59e0b;
180
+ }
181
+
182
+ .html-content .info-box {
183
+ background-color: #dbeafe;
184
+ border: 1px solid #3b82f6;
185
+ border-radius: 0.5rem;
186
+ padding: 1rem;
187
+ margin: 1rem 0;
188
+ }
189
+
190
+ .html-content .warning-box {
191
+ background-color: #fef3c7;
192
+ border: 1px solid #f59e0b;
193
+ border-radius: 0.5rem;
194
+ padding: 1rem;
195
+ margin: 1rem 0;
196
+ }
197
+
198
+ .html-content .success-box {
199
+ background-color: #d1fae5;
200
+ border: 1px solid #10b981;
201
+ border-radius: 0.5rem;
202
+ padding: 1rem;
203
+ margin: 1rem 0;
204
+ }
205
+
206
+ .html-content .error-box {
207
+ background-color: #fee2e2;
208
+ border: 1px solid #ef4444;
209
+ border-radius: 0.5rem;
210
+ padding: 1rem;
211
+ margin: 1rem 0;
212
+ }
213
+
214
+ .html-content .html-heading {
215
+ margin-top: 2rem;
216
+ margin-bottom: 1rem;
217
+ font-weight: 700;
218
+ line-height: 1.2;
219
+ color: #111827;
220
+ }
221
+
222
+ .html-content .html-heading-1 {
223
+ font-size: 2rem;
224
+ border-bottom: 3px solid #3b82f6;
225
+ padding-bottom: 0.75rem;
226
+ }
227
+
228
+ .html-content .html-heading-2 {
229
+ font-size: 1.5rem;
230
+ border-bottom: 2px solid #e5e7eb;
231
+ padding-bottom: 0.5rem;
232
+ }
233
+
234
+ .html-content .html-heading-3 {
235
+ font-size: 1.25rem;
236
+ color: #374151;
237
+ }
238
+
239
+ .html-content .html-paragraph {
240
+ margin-bottom: 1.25rem;
241
+ line-height: 1.8;
242
+ color: #4b5563;
243
+ }
244
+
245
+ .html-content .html-list {
246
+ margin: 1.5rem 0;
247
+ padding-left: 2rem;
248
+ }
249
+
250
+ .html-content .html-list li {
251
+ margin-bottom: 0.75rem;
252
+ line-height: 1.7;
253
+ position: relative;
254
+ }
255
+
256
+ .html-content .html-list-unordered li::before {
257
+ content: "•";
258
+ color: #3b82f6;
259
+ font-weight: bold;
260
+ position: absolute;
261
+ left: -1.5rem;
262
+ }
263
+
264
+ .html-content .html-list-ordered {
265
+ counter-reset: list-counter;
266
+ }
267
+
268
+ .html-content .html-list-ordered li {
269
+ counter-increment: list-counter;
270
+ }
271
+
272
+ .html-content .html-list-ordered li::before {
273
+ content: counter(list-counter) ".";
274
+ color: #3b82f6;
275
+ font-weight: 600;
276
+ position: absolute;
277
+ left: -2rem;
278
+ }
279
+
280
+ .html-content .html-inline-code {
281
+ background-color: #f3f4f6;
282
+ padding: 0.25rem 0.5rem;
283
+ border-radius: 0.375rem;
284
+ font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace;
285
+ font-size: 0.875rem;
286
+ color: #dc2626;
287
+ border: 1px solid #e5e7eb;
288
+ }
289
+
290
+ .html-content .html-code-block {
291
+ background-color: #1f2937;
292
+ color: #f9fafb;
293
+ padding: 1.5rem;
294
+ border-radius: 0.75rem;
295
+ overflow-x: auto;
296
+ font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace;
297
+ font-size: 0.875rem;
298
+ line-height: 1.6;
299
+ border: 1px solid #374151;
300
+ margin: 2rem 0;
301
+ box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
302
+ }
303
+
304
+ .html-content .html-blockquote {
305
+ border-left: 4px solid #3b82f6;
306
+ background: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%);
307
+ padding: 1.5rem;
308
+ margin: 2rem 0;
309
+ border-radius: 0.5rem;
310
+ font-style: italic;
311
+ color: #475569;
312
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
313
+ }
314
+
315
+ .html-content .html-table {
316
+ border-collapse: collapse;
317
+ border: 2px solid #e5e7eb;
318
+ width: 100%;
319
+ margin: 2rem 0;
320
+ border-radius: 0.75rem;
321
+ overflow: hidden;
322
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
323
+ }
324
+
325
+ .html-content .html-table-header {
326
+ background: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%);
327
+ color: white;
328
+ font-weight: 700;
329
+ padding: 1rem;
330
+ text-align: left;
331
+ border-bottom: 2px solid #1d4ed8;
332
+ }
333
+
334
+ .html-content .html-table-cell {
335
+ border: 1px solid #e5e7eb;
336
+ padding: 1rem;
337
+ text-align: left;
338
+ vertical-align: top;
339
+ background-color: white;
340
+ }
341
+
342
+ .html-content .html-table tr:nth-child(even) .html-table-cell {
343
+ background-color: #f9fafb;
344
+ }
345
+
346
+ .html-content .html-table tr:hover .html-table-cell {
347
+ background-color: #f3f4f6;
348
+ }
349
+
350
+ /* Enhanced code block styling */
351
+ .html-content pre {
352
+ background-color: #1f2937;
353
+ color: #f9fafb;
354
+ padding: 1.5rem;
355
+ border-radius: 0.75rem;
356
+ overflow-x: auto;
357
+ font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace;
358
+ font-size: 0.875rem;
359
+ line-height: 1.6;
360
+ border: 1px solid #374151;
361
+ margin: 1.5rem 0;
362
+ box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
363
+ }
364
+
365
+ .html-content pre code {
366
+ background-color: transparent;
367
+ padding: 0;
368
+ border: none;
369
+ color: #f9fafb;
370
+ font-size: inherit;
371
+ }
372
+
373
+ /* Code block container styling */
374
+ .html-content .code-block-container {
375
+ border-radius: 0.75rem;
376
+ overflow: hidden;
377
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
378
+ margin: 1.5rem 0;
379
+ }
380
+
381
+ .html-content .code-block-header {
382
+ background: linear-gradient(135deg, #f3f4f6 0%, #e5e7eb 100%);
383
+ padding: 0.75rem 1rem;
384
+ border-bottom: 1px solid #d1d5db;
385
+ font-weight: 600;
386
+ color: #374151;
387
+ font-size: 0.875rem;
388
+ text-transform: uppercase;
389
+ letter-spacing: 0.05em;
390
+ }
391
+
392
+ .html-content .code-block-content {
393
+ background-color: #1f2937;
394
+ padding: 1.5rem;
395
+ overflow-x: auto;
396
+ }
397
+ `;
398
+ // Function to prettify HTML content
399
+ const prettifyHtmlContent = htmlContent => {
400
+ // Add semantic classes for better styling
401
+ let prettified = htmlContent;
402
+ // Enhance headings with better styling
403
+ prettified = prettified.replace(/<h([1-6])>/g, '<h$1 class="html-heading html-heading-$1">');
404
+ // Enhance lists with better styling
405
+ prettified = prettified.replace(/<ul>/g, '<ul class="html-list html-list-unordered">');
406
+ prettified = prettified.replace(/<ol>/g, '<ol class="html-list html-list-ordered">');
407
+ // Enhance paragraphs with better spacing
408
+ prettified = prettified.replace(/<p>/g, '<p class="html-paragraph">');
409
+ // Enhance code blocks
410
+ prettified = prettified.replace(/<code>/g, '<code class="html-inline-code">');
411
+ prettified = prettified.replace(/<pre>/g, '<pre class="html-code-block">');
412
+ // Enhance blockquotes
413
+ prettified = prettified.replace(/<blockquote>/g, '<blockquote class="html-blockquote">');
414
+ // Enhance tables
415
+ prettified = prettified.replace(/<table>/g, '<table class="html-table">');
416
+ prettified = prettified.replace(/<th>/g, '<th class="html-table-header">');
417
+ prettified = prettified.replace(/<td>/g, '<td class="html-table-cell">');
418
+ // Add info boxes for certain content patterns
419
+ prettified = prettified.replace(/<p>(Note|Tip|Info|Warning|Error):\s*(.*?)<\/p>/gi, '<div class="html-info-box"><strong>$1:</strong> $2</div>');
420
+ return prettified;
421
+ };
422
+ // Hook to inject CSS styles
423
+ const useInjectStyles = () => {
424
+ useEffect(() => {
425
+ // Check if styles are already injected
426
+ if (document.getElementById('html-content-styles')) {
427
+ return;
428
+ }
429
+ // Create and inject style element
430
+ const styleElement = document.createElement('style');
431
+ styleElement.id = 'html-content-styles';
432
+ styleElement.textContent = htmlContentStyles;
433
+ document.head.appendChild(styleElement);
434
+ // Cleanup function
435
+ return () => {
436
+ const existingStyle = document.getElementById('html-content-styles');
437
+ if (existingStyle) {
438
+ existingStyle.remove();
439
+ }
440
+ };
441
+ }, []);
442
+ };
443
+ // Enhanced utility function to group messages by user and time
444
+ const groupMessagesByUserAndTime = (messages, timeThresholdMinutes = 5) => {
445
+ if (!messages || messages.length === 0) return [];
446
+ const groups = [];
447
+ let currentGroup = [];
448
+ let lastMessage = null;
449
+ for (const message of messages) {
450
+ if (typeof message === 'string') continue; // Skip date separators
451
+ const shouldStartNewGroup = !lastMessage || lastMessage.author?.id !== message.author?.id || differenceInMinutes(new Date(message.createdAt), new Date(lastMessage.createdAt)) > timeThresholdMinutes;
452
+ if (shouldStartNewGroup) {
453
+ if (currentGroup.length > 0) {
454
+ groups.push(currentGroup);
455
+ }
456
+ currentGroup = [message];
457
+ } else {
458
+ currentGroup.push(message);
459
+ }
460
+ lastMessage = message;
461
+ }
462
+ if (currentGroup.length > 0) {
463
+ groups.push(currentGroup);
464
+ }
465
+ return groups;
466
+ };
467
+ // Enhanced HTML detection that recognizes more HTML patterns
468
+ const isProbablyHTML = value => {
469
+ if (!value) return false;
470
+ // Check for HTML tags (including self-closing tags)
471
+ const htmlTagPattern = /<\/?[a-z][\s\S]*>/i;
472
+ // Check for HTML entities
473
+ const htmlEntityPattern = /&[a-z0-9#]+;/i;
474
+ // Check for common HTML attributes
475
+ const htmlAttrPattern = /\s+[a-z-]+\s*=\s*["'][^"']*["']/i;
476
+ // Check for HTML-like structure
477
+ const htmlStructurePattern = /<[^>]+>[^<]*<\/[^>]+>/i;
478
+ return htmlTagPattern.test(value.trim()) || htmlEntityPattern.test(value.trim()) || htmlAttrPattern.test(value.trim()) || htmlStructurePattern.test(value.trim());
479
+ };
480
+ // Detect if a string looks like a code block
481
+ const isCodeBlock = text => {
482
+ if (!text || text.length < 10) return false;
483
+ // Check for common programming patterns
484
+ const codePatterns = [/\b(if|else|for|while|switch|case|break|continue|return|function|class|import|export|const|let|var|default)\b/, /\b(public|private|protected|static|final|abstract|interface|extends|implements)\b/, /\b(try|catch|finally|throw|throws)\b/, /\b(new|this|super|null|undefined|true|false)\b/,
485
+ // Narrow punctuation: exclude parentheses, brackets, hyphen, question/colon to reduce false positives
486
+ /[{}<>;=+*/%&|^~]/, /\b(System\.out\.println|console\.log|print|printf)\b/, /\b(int|string|boolean|float|double|long|char|byte|short)\b/, /\b(void|int|main|args)\b/, /\/\/.*$/m,
487
+ // Single line comments
488
+ /\/\*[\s\S]*?\*\//m,
489
+ // Multi-line comments
490
+ /^\s*[a-zA-Z_$][a-zA-Z0-9_$]*\s*[=:]\s*/,
491
+ // Variable assignment
492
+ /^\s*[a-zA-Z_$][a-zA-Z0-9_$]*\s*\(.*\)\s*{/,
493
+ // Function definition
494
+ /\bexport\s+default\b/,
495
+ // Export default statements
496
+ /\breturn\s+\(/,
497
+ // Return with JSX
498
+ /\bJSX\.Element\b/ // JSX types
499
+ ];
500
+ // Count how many patterns match
501
+ let matchCount = 0;
502
+ codePatterns.forEach(pattern => {
503
+ if (pattern.test(text)) {
504
+ matchCount++;
505
+ }
506
+ });
507
+ // Debug logging
508
+ console.log('Code block detection for:', text.substring(0, 100) + '...');
509
+ console.log('Match count:', matchCount);
510
+ console.log('Contains export default:', /\bexport\s+default\b/.test(text));
511
+ console.log('Contains function:', /\bfunction\b/.test(text));
512
+ console.log('Contains braces:', /[{}<>;]/.test(text));
513
+ // If multiple patterns match or if it contains specific strong indicators, consider it code
514
+ const result = matchCount >= 2 || /\b(if|else|for|while|function|class|export)\b/.test(text) || /[{}<>;]/.test(text) || /\bexport\s+default\b/.test(text);
515
+ console.log('Is code block:', result);
516
+ return result;
517
+ };
518
+ // Enhanced sanitizer that allows most HTML tags while maintaining security
519
+ const sanitizeHtml = html => {
520
+ try {
521
+ if (typeof window === 'undefined' || typeof window.DOMParser === 'undefined') {
522
+ return html.replace(/<script[\s\S]*?>[\s\S]*?<\/script>/gi, '').replace(/<style[\s\S]*?>[\s\S]*?<\/style>/gi, '').replace(/on\w+\s*=\s*"[^"]*"/gi, '').replace(/on\w+\s*=\s*'[^']*'/gi, '').replace(/on\w+\s*=\s*[^\s>]+/gi, '').replace(/javascript:/gi, '').replace(/data:text\/html/gi, '');
523
+ }
524
+ const parser = new window.DOMParser();
525
+ const doc = parser.parseFromString(html, 'text/html');
526
+ // Only remove the most dangerous tags
527
+ const dangerousTags = ['script', 'style'];
528
+ dangerousTags.forEach(tag => {
529
+ doc.querySelectorAll(tag).forEach(el => el.remove());
530
+ });
531
+ const walker = doc.createTreeWalker(doc.body, NodeFilter.SHOW_ELEMENT);
532
+ let node = walker.nextNode();
533
+ while (node) {
534
+ Array.from(node.attributes).forEach(attr => {
535
+ const name = attr.name.toLowerCase();
536
+ const value = (attr.value || '').toLowerCase();
537
+ // Remove event handlers and javascript protocols
538
+ if (name.startsWith('on') || value.startsWith('javascript:')) {
539
+ node?.removeAttribute(attr.name);
540
+ }
541
+ // Allow most attributes but validate URLs for src/href
542
+ if ((name === 'src' || name === 'href') && !/^https?:|^\/.*/.test(attr.value)) {
543
+ node?.removeAttribute(attr.name);
544
+ }
545
+ });
546
+ node = walker.nextNode();
547
+ }
548
+ return doc.body.innerHTML;
549
+ } catch (e) {
550
+ return html.replace(/<script[\s\S]*?>[\s\S]*?<\/script>/gi, '');
551
+ }
552
+ };
553
+ // Minimal Builder-like blocks renderer (text/image/button/columns)
554
+ const BuilderLikeRenderer = ({
555
+ blocks
556
+ }) => {
557
+ if (!blocks || !Array.isArray(blocks) || blocks.length === 0) return null;
558
+ return React__default.createElement("div", {
559
+ className: "space-y-3"
560
+ }, blocks.map((block, idx) => {
561
+ const type = block?.['@type'] || block?.type;
562
+ if (!type) return null;
563
+ if (/text/i.test(type)) {
564
+ const html = sanitizeHtml(block?.text || block?.data?.text || '');
565
+ return React__default.createElement("div", {
566
+ key: idx,
567
+ className: "prose prose-sm max-w-none text-gray-800",
568
+ dangerouslySetInnerHTML: {
569
+ __html: html
570
+ }
571
+ });
572
+ }
573
+ if (/image/i.test(type)) {
574
+ const src = block?.src || block?.image || block?.data?.src;
575
+ const alt = block?.alt || block?.data?.alt || '';
576
+ if (!src) return null;
577
+ return React__default.createElement("div", {
578
+ key: idx,
579
+ className: "rounded-lg overflow-hidden border border-gray-200"
580
+ }, React__default.createElement("img", {
581
+ className: "w-full h-auto",
582
+ src: src,
583
+ alt: alt
584
+ }));
585
+ }
586
+ if (/button/i.test(type)) {
587
+ const text = block?.text || block?.data?.text || 'Button';
588
+ const href = block?.href || block?.link || block?.data?.href || '#';
589
+ return React__default.createElement("a", {
590
+ key: idx,
591
+ href: href,
592
+ target: "_blank",
593
+ rel: "noopener noreferrer",
594
+ className: "inline-flex items-center px-3 py-1.5 rounded-md bg-blue-600 text-white text-sm hover:bg-blue-700"
595
+ }, text);
596
+ }
597
+ if (/columns?/i.test(type)) {
598
+ const cols = block?.columns || block?.data?.columns || [];
599
+ return React__default.createElement("div", {
600
+ key: idx,
601
+ className: "grid grid-cols-1 sm:grid-cols-2 gap-3"
602
+ }, cols.map((col, colIdx) => React__default.createElement("div", {
603
+ key: colIdx,
604
+ className: "space-y-2"
605
+ }, React__default.createElement(BuilderLikeRenderer, {
606
+ blocks: col?.blocks || col?.children
607
+ }))));
608
+ }
609
+ return React__default.createElement("pre", {
610
+ key: idx,
611
+ className: "text-xs text-gray-600 bg-gray-50 p-2 rounded overflow-x-auto not-prose"
612
+ }, JSON.stringify(block, null, 2));
613
+ }));
614
+ };
615
+ // Enhanced markdown-like renderer for rich text content
616
+ // Helper: render multiple inline lists from a single paragraph like
617
+ // "Intro A: - item1 - item2 Intro B: - item3 - item4"
618
+ const tryRenderMultipleInlineLists = text => {
619
+ if (!text || !text.includes(' - ') || !text.includes(':')) return null;
620
+ // Split while keeping the section headers (ending with ":")
621
+ const segments = text.split(/([^:]+:\s*)/).filter(s => s.length > 0);
622
+ if (segments.length < 3) return null; // need at least header + content
623
+ const nodes = [];
624
+ // Handle leading text before the first header
625
+ if (segments[0] && !segments[0].endsWith(':')) {
626
+ const leading = segments[0].trim();
627
+ if (leading) {
628
+ nodes.push(React__default.createElement("p", {
629
+ key: `inline-leading`,
630
+ className: "text-gray-700 leading-relaxed"
631
+ }, leading));
632
+ }
633
+ }
634
+ for (let i = 1; i < segments.length; i += 2) {
635
+ const header = (segments[i] || '').trim();
636
+ const rest = (segments[i + 1] || '').trim();
637
+ if (!header.endsWith(':')) continue;
638
+ const parts = rest.split(/\s-\s+/).filter(p => p.trim());
639
+ // When split on " - ", the first element is the tail right after header; ignore if empty
640
+ const items = parts.length && !rest.startsWith('- ') ? parts.slice(1) : parts;
641
+ if (items.length >= 2) {
642
+ nodes.push(React__default.createElement("div", {
643
+ key: `inline-group-${i}`,
644
+ className: "space-y-2"
645
+ }, React__default.createElement("p", {
646
+ className: "text-gray-900 font-semibold leading-relaxed"
647
+ }, header.replace(/:$/, '')), React__default.createElement("ul", {
648
+ className: "space-y-2"
649
+ }, items.map((it, idx) => React__default.createElement("li", {
650
+ key: `inline-item-${i}-${idx}`,
651
+ className: "flex items-start space-x-3 items-center"
652
+ }, React__default.createElement("svg", {
653
+ className: "w-5 h-5 text-black mt-0.5 flex-shrink-0",
654
+ fill: "currentColor",
655
+ viewBox: "0 0 20 20"
656
+ }, React__default.createElement("path", {
657
+ fillRule: "evenodd",
658
+ d: "M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z",
659
+ clipRule: "evenodd"
660
+ })), React__default.createElement("span", {
661
+ className: "text-gray-700 leading-relaxed"
662
+ }, it.trim()))))));
663
+ } else {
664
+ // Not enough items; treat as plain text
665
+ const combined = `${header} ${rest}`.trim();
666
+ if (combined) {
667
+ nodes.push(React__default.createElement("p", {
668
+ key: `inline-fallback-${i}`,
669
+ className: "text-gray-700 leading-relaxed"
670
+ }, combined));
671
+ }
672
+ }
673
+ }
674
+ return nodes.length ? nodes : null;
675
+ };
676
+ const FormattedMessageContent = ({
677
+ content
678
+ }) => {
679
+ if (!content) return null;
680
+ // Debug logging for content
681
+ console.log('FormattedMessageContent received:', content.substring(0, 200) + '...');
682
+ // Direct check for a code-looking message (common for AI replies with fenced blocks)
683
+ if (content.includes('export default function Home()') || content.includes('export default') && content.includes('function') && content.includes('return')) {
684
+ console.log('Direct code pattern match detected!');
685
+ // If content has fenced code, extract language and code, removing the fences
686
+ const fenceMatch = content.match(/```([\w-]*)\n?([\s\S]*?)```/);
687
+ let language = 'typescript';
688
+ let codeBody = content;
689
+ if (fenceMatch) {
690
+ language = (fenceMatch[1] || 'code').trim() || 'code';
691
+ codeBody = fenceMatch[2];
692
+ }
693
+ // Clean up the code content for better display
694
+ const cleanCode = codeBody.replace(/^\s+/, '') // Remove leading whitespace
695
+ .replace(/\s+$/, '') // Remove trailing whitespace
696
+ .split('\n').map(line => line.trim()).filter(line => line.length > 0).join('\n');
697
+ return React__default.createElement("div", {
698
+ className: "rounded-xl border border-gray-200 bg-gray-50 overflow-hidden"
699
+ }, React__default.createElement("div", {
700
+ className: "px-4 py-2 text-sm font-bold text-gray-900"
701
+ }, language), React__default.createElement("div", {
702
+ className: "px-4 pb-4 overflow-x-auto"
703
+ }, React__default.createElement("pre", {
704
+ className: "text-sm text-gray-900 font-mono leading-relaxed whitespace-pre-wrap not-prose"
705
+ }, React__default.createElement("code", null, cleanCode))));
706
+ }
707
+ // Normalize escaped fences (\``` -> ```)
708
+ const normalizedContent = content.replace(/\\`{3}/g, '```');
709
+ // Global fenced-code parse as an early pass (handles cases where block splitting interferes)
710
+ if (normalizedContent.includes('```')) {
711
+ const parts = [];
712
+ const pushTextBlock = (text, key) => {
713
+ const t = (text || '').trim();
714
+ if (!t) return;
715
+ // Try to render multiple inline lists in one paragraph
716
+ const multiInline = tryRenderMultipleInlineLists(t);
717
+ if (multiInline) {
718
+ multiInline.forEach((n, idx) => parts.push(React__default.createElement(React__default.Fragment, {
719
+ key: `${key}-mil-${idx}`
720
+ }, n)));
721
+ return;
722
+ }
723
+ if (t.startsWith('# ')) {
724
+ parts.push(React__default.createElement("h1", {
725
+ key: key,
726
+ className: "text-2xl font-bold text-gray-900 mb-4 bg-gradient-to-r from-blue-600 to-purple-600 bg-clip-text text-transparent"
727
+ }, t.substring(2)));
728
+ return;
729
+ }
730
+ if (t.startsWith('## ')) {
731
+ parts.push(React__default.createElement("h2", {
732
+ key: key,
733
+ className: "text-xl font-semibold text-gray-800 mb-3 border-b border-gray-200 pb-2"
734
+ }, t.substring(3)));
735
+ return;
736
+ }
737
+ if (t.startsWith('### ')) {
738
+ parts.push(React__default.createElement("h3", {
739
+ key: key,
740
+ className: "text-lg font-medium text-gray-700 mb-2"
741
+ }, t.substring(4)));
742
+ return;
743
+ }
744
+ // Inline list heuristic: bullet items written on one line separated by " - "
745
+ if (!t.includes('\n') && t.includes(' - ') && t.split(' - ').length >= 3) {
746
+ const [intro, ...rawItems] = t.split(/\s-\s+/);
747
+ parts.push(React__default.createElement("div", {
748
+ key: `${key}-inline-list`,
749
+ className: "space-y-2"
750
+ }, intro.trim() ? React__default.createElement("p", {
751
+ className: "text-gray-700 leading-relaxed"
752
+ }, intro.trim()) : null, React__default.createElement("ul", {
753
+ className: "space-y-2"
754
+ }, rawItems.map((item, itemIndex) => React__default.createElement("li", {
755
+ key: `${key}-inli-${itemIndex}`,
756
+ className: "flex items-start space-x-3 items-center"
757
+ }, React__default.createElement("svg", {
758
+ className: "w-5 h-5 text-black mt-0.5 flex-shrink-0",
759
+ fill: "currentColor",
760
+ viewBox: "0 0 20 20"
761
+ }, React__default.createElement("path", {
762
+ fillRule: "evenodd",
763
+ d: "M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z",
764
+ clipRule: "evenodd"
765
+ })), React__default.createElement("span", {
766
+ className: "text-gray-700 leading-relaxed"
767
+ }, item.trim()))))));
768
+ return;
769
+ }
770
+ if (t.startsWith('- ') || t.startsWith('• ')) {
771
+ const items = t.split('\n').filter(line => line.trim());
772
+ parts.push(React__default.createElement("div", {
773
+ key: key,
774
+ className: "bg-blue-50 border-l-4 border-blue-500 p-4 rounded-r-lg"
775
+ }, React__default.createElement("ul", {
776
+ className: "space-y-2"
777
+ }, items.map((item, itemIndex) => React__default.createElement("li", {
778
+ key: `${key}-li-${itemIndex}`,
779
+ className: "flex items-start space-x-3 items-center"
780
+ }, React__default.createElement("svg", {
781
+ className: "w-5 h-5 text-black mt-0.5 flex-shrink-0",
782
+ fill: "currentColor",
783
+ viewBox: "0 0 20 20"
784
+ }, React__default.createElement("path", {
785
+ fillRule: "evenodd",
786
+ d: "M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z",
787
+ clipRule: "evenodd"
788
+ })), React__default.createElement("span", {
789
+ className: "text-gray-700 leading-relaxed"
790
+ }, item.replace(/^[\u2212\-•]\s*/, '')))))));
791
+ return;
792
+ }
793
+ if (isProbablyHTML(t)) {
794
+ parts.push(React__default.createElement("div", {
795
+ key: key,
796
+ className: "prose prose-sm max-w-none text-gray-800",
797
+ dangerouslySetInnerHTML: {
798
+ __html: sanitizeHtml(t)
799
+ }
800
+ }));
801
+ return;
802
+ }
803
+ if (t.includes('**') || t.includes('`')) {
804
+ const formatted = t.replace(/\*\*(.*?)\*\*/g, '<span class="font-semibold text-gray-900 bg-yellow-100 px-1 py-0.5 rounded">$1</span>').replace(/`([^`]+)`/g, '<code class="bg-gray-100 px-2 py-1 rounded text-sm font-mono text-gray-800">$1</code>');
805
+ parts.push(React__default.createElement("div", {
806
+ key: key,
807
+ className: "text-gray-700 leading-relaxed",
808
+ dangerouslySetInnerHTML: {
809
+ __html: sanitizeHtml(formatted)
810
+ }
811
+ }));
812
+ return;
813
+ }
814
+ // Check if the text looks like a code block (contains programming keywords, syntax, etc.)
815
+ if (isCodeBlock(t)) {
816
+ // Clean up the code content for better display
817
+ const cleanCode = t.replace(/^\s+/, '') // Remove leading whitespace
818
+ .replace(/\s+$/, '') // Remove trailing whitespace
819
+ .split('\n').map(line => line.trim()).filter(line => line.length > 0).join('\n');
820
+ parts.push(React__default.createElement("div", {
821
+ key: key,
822
+ className: "rounded-xl border border-gray-200 bg-gray-50 overflow-hidden"
823
+ }, React__default.createElement("div", {
824
+ className: "px-4 py-2 text-sm font-bold text-gray-900"
825
+ }, "typescript"), React__default.createElement("div", {
826
+ className: "px-4 pb-4 overflow-x-auto"
827
+ }, React__default.createElement("pre", {
828
+ className: "text-sm text-gray-900 font-mono leading-relaxed whitespace-pre-wrap not-prose"
829
+ }, React__default.createElement("code", null, cleanCode)))));
830
+ return;
831
+ }
832
+ parts.push(React__default.createElement("p", {
833
+ key: key,
834
+ className: "text-gray-700 leading-relaxed whitespace-pre-wrap"
835
+ }, t));
836
+ };
837
+ // Improved regex to handle multiline code blocks better
838
+ const codeRegex = /```([\w-]*)\n?([\s\S]*?)```/g;
839
+ let lastIndex = 0;
840
+ let m;
841
+ let foundAnyFence = false;
842
+ while ((m = codeRegex.exec(normalizedContent)) !== null) {
843
+ foundAnyFence = true;
844
+ const [full, lang, code] = m;
845
+ const before = normalizedContent.slice(lastIndex, m.index);
846
+ pushTextBlock(before, `global-before-${lastIndex}`);
847
+ const language = (lang || '').trim() || 'code';
848
+ // Clean up the code content properly
849
+ const cleanCode = code.replace(/^\s+/, '') // Remove leading whitespace
850
+ .replace(/\s+$/, '') // Remove trailing whitespace
851
+ .split('\n').map(line => line.trim()).filter(line => line.length > 0).join('\n');
852
+ parts.push(React__default.createElement("div", {
853
+ key: `global-code-${m.index}`,
854
+ className: "rounded-xl border border-gray-200 bg-gray-50 overflow-hidden shadow-sm"
855
+ }, React__default.createElement("div", {
856
+ className: "px-4 py-2 text-sm font-bold text-gray-900 bg-gray-100 border-b border-gray-200"
857
+ }, language), React__default.createElement("div", {
858
+ className: "px-4 py-4 overflow-x-auto bg-white"
859
+ }, React__default.createElement("pre", {
860
+ className: "text-sm text-gray-900 font-mono leading-relaxed whitespace-pre-wrap not-prose"
861
+ }, React__default.createElement("code", null, cleanCode)))));
862
+ lastIndex = m.index + full.length;
863
+ }
864
+ const after = normalizedContent.slice(lastIndex);
865
+ if (!foundAnyFence) {
866
+ // Fallback: opening fence exists but no closing fence found
867
+ const fenceIndex = normalizedContent.indexOf('```');
868
+ const before = normalizedContent.slice(0, fenceIndex);
869
+ const afterFence = normalizedContent.slice(fenceIndex + 3); // skip opening backticks
870
+ // Try to read language up to end of line. If none, treat whole remainder as code.
871
+ const firstNewline = afterFence.indexOf('\n');
872
+ const language = firstNewline >= 0 ? afterFence.slice(0, firstNewline).trim() || 'code' : 'code';
873
+ const rawCodeBody = firstNewline >= 0 ? afterFence.slice(firstNewline + 1) : afterFence;
874
+ const codeBody = rawCodeBody.replace(/^\s+/, '').replace(/\s+$/, '').split('\n').map(line => line.trimEnd()).join('\n');
875
+ pushTextBlock(before, `global-fallback-before-${fenceIndex}`);
876
+ parts.push(React__default.createElement("div", {
877
+ key: `global-fallback-code-${fenceIndex}`,
878
+ className: "rounded-xl border border-gray-200 bg-gray-50 overflow-hidden shadow-sm"
879
+ }, React__default.createElement("div", {
880
+ className: "px-4 py-2 text-sm font-bold text-gray-900 bg-gray-100 border-b border-gray-200"
881
+ }, language), React__default.createElement("div", {
882
+ className: "px-4 py-4 overflow-x-auto bg-white"
883
+ }, React__default.createElement("pre", {
884
+ className: "text-sm text-gray-900 font-mono leading-relaxed whitespace-pre-wrap not-prose"
885
+ }, React__default.createElement("code", null, codeBody)))));
886
+ } else {
887
+ // If there's a dangling opening fence in the tail, render it as a fallback code block
888
+ if (after.includes('```')) {
889
+ const fenceIndexTail = after.indexOf('```');
890
+ const beforeTail = after.slice(0, fenceIndexTail);
891
+ const afterFenceTail = after.slice(fenceIndexTail + 3);
892
+ const firstNewlineTail = afterFenceTail.indexOf('\n');
893
+ const languageTail = firstNewlineTail >= 0 ? afterFenceTail.slice(0, firstNewlineTail).trim() || 'code' : 'code';
894
+ const rawCodeTail = firstNewlineTail >= 0 ? afterFenceTail.slice(firstNewlineTail + 1) : afterFenceTail;
895
+ const cleanTail = rawCodeTail.replace(/^\s+/, '').replace(/\s+$/, '').split('\n').map(line => line.trimEnd()).join('\n');
896
+ pushTextBlock(beforeTail, `global-after-text-${lastIndex}`);
897
+ parts.push(React__default.createElement("div", {
898
+ key: `global-after-fallback-code-${lastIndex}`,
899
+ className: "rounded-xl border border-gray-200 bg-gray-50 overflow-hidden shadow-sm"
900
+ }, React__default.createElement("div", {
901
+ className: "px-4 py-2 text-sm font-bold text-gray-900 bg-gray-100 border-b border-gray-200"
902
+ }, languageTail), React__default.createElement("div", {
903
+ className: "px-4 py-4 overflow-x-auto bg-white"
904
+ }, React__default.createElement("pre", {
905
+ className: "text-sm text-gray-900 font-mono leading-relaxed whitespace-pre-wrap not-prose"
906
+ }, React__default.createElement("code", null, cleanTail)))));
907
+ } else {
908
+ pushTextBlock(after, `global-after-${lastIndex}`);
909
+ }
910
+ }
911
+ return React__default.createElement("div", {
912
+ className: "space-y-4"
913
+ }, parts);
914
+ }
915
+ // Split content into blocks for better formatting
916
+ const blocks = normalizedContent.split('\n\n').filter(block => block.trim());
917
+ // Debug logging for blocks
918
+ console.log('Content blocks:', blocks.map(b => b.substring(0, 100) + '...'));
919
+ return React__default.createElement("div", {
920
+ className: "space-y-4"
921
+ }, blocks.map((block, index) => {
922
+ const trimmedBlock = block.trim();
923
+ // Debug logging for individual blocks
924
+ console.log(`Block ${index}:`, trimmedBlock.substring(0, 100) + '...');
925
+ console.log(`Block ${index} isCodeBlock:`, isCodeBlock(trimmedBlock));
926
+ // If the block contains fenced code anywhere, render text parts + code parts in order
927
+ if (trimmedBlock.includes('```')) {
928
+ const parts = [];
929
+ const pushTextBlock = (text, key) => {
930
+ const t = (text || '').trim();
931
+ if (!t) return;
932
+ const multiInlineInner = tryRenderMultipleInlineLists(t);
933
+ if (multiInlineInner) {
934
+ multiInlineInner.forEach((n, idx) => parts.push(React__default.createElement(React__default.Fragment, {
935
+ key: `${key}-mil-${idx}`
936
+ }, n)));
937
+ return;
938
+ }
939
+ if (t.startsWith('# ')) {
940
+ parts.push(React__default.createElement("h1", {
941
+ key: key,
942
+ className: "text-2xl font-bold text-gray-900 mb-4 bg-gradient-to-r from-blue-600 to-purple-600 bg-clip-text text-transparent"
943
+ }, t.substring(2)));
944
+ return;
945
+ }
946
+ if (t.startsWith('## ')) {
947
+ parts.push(React__default.createElement("h2", {
948
+ key: key,
949
+ className: "text-xl font-semibold text-gray-800 mb-3 border-b border-gray-200 pb-2"
950
+ }, t.substring(3)));
951
+ return;
952
+ }
953
+ if (t.startsWith('### ')) {
954
+ parts.push(React__default.createElement("h3", {
955
+ key: key,
956
+ className: "text-lg font-medium text-gray-700 mb-2"
957
+ }, t.substring(4)));
958
+ return;
959
+ }
960
+ // Inline list heuristic inside block
961
+ if (!t.includes('\n') && t.includes(' - ') && t.split(' - ').length >= 3) {
962
+ const [intro, ...rawItems] = t.split(/\s-\s+/);
963
+ parts.push(React__default.createElement("div", {
964
+ key: `${key}-inline-list`,
965
+ className: "space-y-2"
966
+ }, intro.trim() ? React__default.createElement("p", {
967
+ className: "text-gray-700 leading-relaxed"
968
+ }, intro.trim()) : null, React__default.createElement("ul", {
969
+ className: "space-y-2"
970
+ }, rawItems.map((item, itemIndex) => React__default.createElement("li", {
971
+ key: `${key}-inli-${itemIndex}`,
972
+ className: "flex items-start space-x-3 items-center"
973
+ }, React__default.createElement("svg", {
974
+ className: "w-5 h-5 text-black mt-0.5 flex-shrink-0",
975
+ fill: "currentColor",
976
+ viewBox: "0 0 20 20"
977
+ }, React__default.createElement("path", {
978
+ fillRule: "evenodd",
979
+ d: "M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z",
980
+ clipRule: "evenodd"
981
+ })), React__default.createElement("span", {
982
+ className: "text-gray-700 leading-relaxed"
983
+ }, item.trim()))))));
984
+ return;
985
+ }
986
+ if (t.startsWith('- ') || t.startsWith('• ')) {
987
+ const items = t.split('\n').filter(line => line.trim());
988
+ parts.push(
989
+ // <div key={key} className="bg-blue-50 border-l-4 border-blue-500 p-4 rounded-r-lg">
990
+ React__default.createElement("div", {
991
+ key: key,
992
+ className: " p-4 rounded-r-lg"
993
+ }, React__default.createElement("ul", {
994
+ className: "space-y-2"
995
+ }, items.map((item, itemIndex) => React__default.createElement("li", {
996
+ key: `${key}-li-${itemIndex}`,
997
+ className: "flex items-start space-x-3 items-center"
998
+ }, React__default.createElement("svg", {
999
+ className: "w-5 h-5 text-black mt-0.5 flex-shrink-0",
1000
+ fill: "currentColor",
1001
+ viewBox: "0 0 20 20"
1002
+ }, React__default.createElement("path", {
1003
+ fillRule: "evenodd",
1004
+ d: "M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z",
1005
+ clipRule: "evenodd"
1006
+ })), React__default.createElement("span", {
1007
+ className: "text-gray-700 leading-relaxed"
1008
+ }, item.replace(/^[\u2212\-•]\s*/, '')))))));
1009
+ return;
1010
+ }
1011
+ if (t.includes('**') || t.includes('`')) {
1012
+ const formatted = t.replace(/\*\*(.*?)\*\*/g, '<span class="font-semibold text-gray-900 bg-yellow-100 px-1 py-0.5 rounded">$1</span>').replace(/`([^`]+)`/g, '<code class="bg-gray-100 px-2 py-1 rounded text-sm font-mono text-gray-800">$1</code>');
1013
+ parts.push(React__default.createElement("div", {
1014
+ key: key,
1015
+ className: "text-gray-700 leading-relaxed",
1016
+ dangerouslySetInnerHTML: {
1017
+ __html: sanitizeHtml(formatted)
1018
+ }
1019
+ }));
1020
+ return;
1021
+ }
1022
+ // Check if the text looks like a code block (contains programming keywords, syntax, etc.)
1023
+ if (isCodeBlock(t)) {
1024
+ // Clean up the code content for better display
1025
+ const cleanCode = t.replace(/^\s+/, '') // Remove leading whitespace
1026
+ .replace(/\s+$/, '') // Remove trailing whitespace
1027
+ .split('\n').map(line => line.trim()).filter(line => line.length > 0).join('\n');
1028
+ parts.push(React__default.createElement("div", {
1029
+ key: key,
1030
+ className: "rounded-xl border border-gray-200 bg-gray-50 overflow-hidden"
1031
+ }, React__default.createElement("div", {
1032
+ className: "px-4 py-2 text-sm font-bold text-gray-900"
1033
+ }, "typescript"), React__default.createElement("div", {
1034
+ className: "px-4 pb-4 overflow-x-auto"
1035
+ }, React__default.createElement("pre", {
1036
+ className: "text-sm text-gray-900 font-mono leading-relaxed whitespace-pre-wrap not-prose"
1037
+ }, React__default.createElement("code", null, cleanCode)))));
1038
+ return;
1039
+ }
1040
+ parts.push(React__default.createElement("p", {
1041
+ key: key,
1042
+ className: "text-gray-700 leading-relaxed whitespace-pre-wrap"
1043
+ }, t));
1044
+ };
1045
+ const codeRegex = /```([\w-]*)\n?([\s\S]*?)```/g;
1046
+ let lastIndex = 0;
1047
+ let match;
1048
+ while ((match = codeRegex.exec(trimmedBlock)) !== null) {
1049
+ const [full, lang, code] = match;
1050
+ const before = trimmedBlock.slice(lastIndex, match.index).trim();
1051
+ pushTextBlock(before, `${index}-before-${lastIndex}`);
1052
+ const language = (lang || '').trim() || 'code';
1053
+ // Clean up the code content properly
1054
+ const cleanCode = code.replace(/^\s+/, '') // Remove leading whitespace
1055
+ .replace(/\s+$/, '') // Remove trailing whitespace
1056
+ .split('\n').map(line => line.trim()).filter(line => line.length > 0).join('\n');
1057
+ parts.push(React__default.createElement("div", {
1058
+ key: `${index}-code-${match.index}`,
1059
+ className: "rounded-xl border border-gray-200 bg-gray-50 overflow-hidden shadow-sm"
1060
+ }, React__default.createElement("div", {
1061
+ className: "px-4 py-2 text-sm font-bold text-gray-900 bg-gray-100 border-b border-gray-200"
1062
+ }, language), React__default.createElement("div", {
1063
+ className: "px-4 py-4 overflow-x-auto bg-white"
1064
+ }, React__default.createElement("pre", {
1065
+ className: "text-sm text-gray-900 font-mono leading-relaxed whitespace-pre-wrap not-prose"
1066
+ }, React__default.createElement("code", null, cleanCode)))));
1067
+ lastIndex = match.index + full.length;
1068
+ }
1069
+ const after = trimmedBlock.slice(lastIndex).trim();
1070
+ pushTextBlock(after, `${index}-after`);
1071
+ return React__default.createElement("div", {
1072
+ key: index,
1073
+ className: "space-y-3"
1074
+ }, parts);
1075
+ }
1076
+ // Raw HTML support per block
1077
+ if (isProbablyHTML(trimmedBlock)) {
1078
+ return React__default.createElement("div", {
1079
+ key: index,
1080
+ className: "prose prose-sm max-w-none text-gray-800",
1081
+ dangerouslySetInnerHTML: {
1082
+ __html: sanitizeHtml(trimmedBlock)
1083
+ }
1084
+ });
1085
+ }
1086
+ // Check for different content types
1087
+ if (trimmedBlock.startsWith('# ')) {
1088
+ // Main heading
1089
+ return React__default.createElement("h1", {
1090
+ key: index,
1091
+ className: "text-2xl font-bold text-gray-900 mb-4 bg-gradient-to-r from-blue-600 to-purple-600 bg-clip-text text-transparent"
1092
+ }, trimmedBlock.substring(2));
1093
+ } else if (trimmedBlock.startsWith('## ')) {
1094
+ // Secondary heading
1095
+ return React__default.createElement("h2", {
1096
+ key: index,
1097
+ className: "text-xl font-semibold text-gray-800 mb-3 border-b border-gray-200 pb-2"
1098
+ }, trimmedBlock.substring(3));
1099
+ } else if (trimmedBlock.startsWith('### ')) {
1100
+ // Tertiary heading
1101
+ return React__default.createElement("h3", {
1102
+ key: index,
1103
+ className: "text-lg font-medium text-gray-700 mb-2"
1104
+ }, trimmedBlock.substring(4));
1105
+ } else if (trimmedBlock.startsWith('- ') || trimmedBlock.startsWith('• ')) {
1106
+ // Bullet points
1107
+ const items = trimmedBlock.split('\n').filter(line => line.trim());
1108
+ return (
1109
+ // <div key={index} className="bg-blue-50 border-l-4 border-blue-500 p-4 rounded-r-lg">
1110
+ React__default.createElement("div", {
1111
+ key: index,
1112
+ className: " p-4 rounded-r-lg"
1113
+ }, React__default.createElement("ul", {
1114
+ className: "space-y-2"
1115
+ }, items.map((item, itemIndex) => React__default.createElement("li", {
1116
+ key: itemIndex,
1117
+ className: "flex items-start space-x-3 items-center"
1118
+ }, React__default.createElement("svg", {
1119
+ className: "w-5 h-5 text-black mt-0.5 flex-shrink-0",
1120
+ fill: "currentColor",
1121
+ viewBox: "0 0 20 20"
1122
+ }, React__default.createElement("path", {
1123
+ fillRule: "evenodd",
1124
+ d: "M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z",
1125
+ clipRule: "evenodd"
1126
+ })), React__default.createElement("span", {
1127
+ className: "text-gray-700 leading-relaxed"
1128
+ }, item.replace(/^[-•]\s*/, '').split(/(\*\*.*?\*\*)/).map((part, partIndex) => {
1129
+ if (part.match(/\*\*.*?\*\*/)) {
1130
+ // Extract text between ** markers and make it bold
1131
+ const boldText = part.replace(/\*\*/g, '');
1132
+ return React__default.createElement("strong", {
1133
+ key: partIndex,
1134
+ className: "font-semibold text-gray-900"
1135
+ }, boldText);
1136
+ }
1137
+ return part;
1138
+ }))))))
1139
+ );
1140
+ } else if (trimmedBlock.startsWith('```')) {
1141
+ // Code block
1142
+ const codeMatch = trimmedBlock.match(/^```([\w-]*)\n?([\s\S]*?)```$/);
1143
+ if (codeMatch) {
1144
+ const [, language, codeContent] = codeMatch;
1145
+ const lang = (language || '').trim() || 'code';
1146
+ // Clean up the code content properly
1147
+ const cleanCode = codeContent.replace(/^\s+/, '') // Remove leading whitespace
1148
+ .replace(/\s+$/, '') // Remove trailing whitespace
1149
+ .split('\n').map(line => line.trim()).filter(line => line.length > 0).join('\n');
1150
+ return React__default.createElement("div", {
1151
+ key: index,
1152
+ className: "rounded-xl border border-gray-200 bg-gray-50 overflow-hidden shadow-sm"
1153
+ }, React__default.createElement("div", {
1154
+ className: "px-4 py-2 text-sm font-bold text-gray-900 bg-gray-100 border-b border-gray-200"
1155
+ }, lang), React__default.createElement("div", {
1156
+ className: "px-4 py-4 overflow-x-auto bg-white"
1157
+ }, React__default.createElement("pre", {
1158
+ className: "text-sm text-gray-900 font-mono leading-relaxed whitespace-pre-wrap not-prose"
1159
+ }, React__default.createElement("code", null, cleanCode))));
1160
+ }
1161
+ // Fallback for malformed code blocks
1162
+ const codeContent = trimmedBlock.replace(/^```[\w]*\n?/, '').replace(/```$/, '');
1163
+ // If the fenced code actually looks like plain bullet text, render as text instead of code
1164
+ const hyphenLines = codeContent.split('\n').filter(l => /^[-•]/.test(l.trim())).length;
1165
+ const hasCodeSymbols = /[{}<>;=]/.test(codeContent) || /\b(function|class|import|export)\b/.test(codeContent);
1166
+ if (hyphenLines >= 2 && !hasCodeSymbols) {
1167
+ return React__default.createElement("p", {
1168
+ key: index,
1169
+ className: "text-gray-700 leading-relaxed whitespace-pre-wrap"
1170
+ }, codeContent);
1171
+ }
1172
+ return React__default.createElement("div", {
1173
+ key: index,
1174
+ className: "rounded-xl border border-gray-200 bg-gray-50 overflow-hidden shadow-sm"
1175
+ }, React__default.createElement("div", {
1176
+ className: "px-4 py-2 text-sm font-bold text-gray-900 bg-gray-100 border-b border-gray-200"
1177
+ }, "code"), React__default.createElement("div", {
1178
+ className: "px-4 py-4 overflow-x-auto bg-white"
1179
+ }, React__default.createElement("pre", {
1180
+ className: "text-sm text-gray-900 font-mono leading-relaxed whitespace-pre-wrap not-prose"
1181
+ }, React__default.createElement("code", null, codeContent))));
1182
+ } else if (trimmedBlock.startsWith('🔧 ')) {
1183
+ // Tool status message - render as bordered container
1184
+ const toolText = trimmedBlock.substring(2); // Remove the 🔧 emoji
1185
+ return React__default.createElement("div", {
1186
+ key: index,
1187
+ className: "mt-2"
1188
+ }, React__default.createElement("div", {
1189
+ className: "inline-block px-3 py-1 bg-gray-100 border border-gray-300 rounded-lg text-sm text-gray-700"
1190
+ }, React__default.createElement("span", {
1191
+ className: "text-green-500 mr-2"
1192
+ }, "\uD83D\uDD27"), toolText));
1193
+ } else if (trimmedBlock.includes('**') || trimmedBlock.includes('`')) {
1194
+ // Inline formatting (bold, inline code, highlights)
1195
+ const formattedContent = trimmedBlock.replace(/\*\*(.*?)\*\*/g, '<span class="font-semibold text-gray-900 bg-yellow-100 px-1 py-0.5 rounded">$1</span>').replace(/`([^`]+)`/g, '<code class="bg-gray-100 px-2 py-1 rounded text-sm font-mono text-gray-800">$1</code>');
1196
+ return React__default.createElement("div", {
1197
+ key: index,
1198
+ className: "text-gray-700 leading-relaxed",
1199
+ dangerouslySetInnerHTML: {
1200
+ __html: sanitizeHtml(formattedContent)
1201
+ }
1202
+ });
1203
+ } else if (isCodeBlock(trimmedBlock)) {
1204
+ // Code block detection for content that looks like code
1205
+ // Clean up the code content for better display
1206
+ const cleanCode = trimmedBlock.replace(/^\s+/, '') // Remove leading whitespace
1207
+ .replace(/\s+$/, '') // Remove trailing whitespace
1208
+ .split('\n').map(line => line.trim()).filter(line => line.length > 0).join('\n');
1209
+ // Heuristic: if the "code" contains many leading hyphen bullets and no typical code symbols, treat as text
1210
+ const hyphenLines = cleanCode.split('\n').filter(l => /^[-•]/.test(l.trim())).length;
1211
+ const hasCodeSymbols = /[{}<>;=]/.test(cleanCode) || /\b(function|class|import|export)\b/.test(cleanCode);
1212
+ if (hyphenLines >= 2 && !hasCodeSymbols) {
1213
+ return React__default.createElement("p", {
1214
+ key: index,
1215
+ className: "text-gray-700 leading-relaxed whitespace-pre-wrap"
1216
+ }, trimmedBlock);
1217
+ }
1218
+ return React__default.createElement("div", {
1219
+ key: index,
1220
+ className: "rounded-xl border border-gray-200 bg-gray-50 overflow-hidden"
1221
+ }, React__default.createElement("div", {
1222
+ className: "px-4 py-2 text-sm font-bold text-gray-900"
1223
+ }, "typescript"), React__default.createElement("div", {
1224
+ className: "px-4 pb-4 overflow-x-auto"
1225
+ }, React__default.createElement("pre", {
1226
+ className: "text-sm text-gray-900 font-mono leading-relaxed whitespace-pre-wrap not-prose"
1227
+ }, React__default.createElement("code", null, cleanCode))));
1228
+ } else if (
1229
+ // Fallback: More aggressive code detection for specific patterns
1230
+ trimmedBlock.includes('export default') || trimmedBlock.includes('function') || trimmedBlock.includes('return (') || trimmedBlock.includes('className=') || trimmedBlock.includes('Route::') || trimmedBlock.includes('class Post') || trimmedBlock.includes('extends Model') || trimmedBlock.includes('extends Controller') || trimmedBlock.includes('{') && trimmedBlock.includes('}') && trimmedBlock.includes(';')) {
1231
+ console.log('Fallback code detection triggered for block:', trimmedBlock.substring(0, 100) + '...');
1232
+ // Clean up the code content for better display
1233
+ const cleanCode = trimmedBlock.replace(/^\s+/, '') // Remove leading whitespace
1234
+ .replace(/\s+$/, '') // Remove trailing whitespace
1235
+ .split('\n').map(line => line.trim()).filter(line => line.length > 0).join('\n');
1236
+ return React__default.createElement("div", {
1237
+ key: index,
1238
+ className: "rounded-xl border border-gray-200 bg-gray-50 overflow-hidden shadow-sm"
1239
+ }, React__default.createElement("div", {
1240
+ className: "px-4 py-2 text-sm font-bold text-gray-900 bg-gray-100 border-b border-gray-200"
1241
+ }, "code"), React__default.createElement("div", {
1242
+ className: "px-4 py-4 overflow-x-auto bg-white"
1243
+ }, React__default.createElement("pre", {
1244
+ className: "text-sm text-gray-900 font-mono leading-relaxed whitespace-pre-wrap not-prose"
1245
+ }, React__default.createElement("code", null, cleanCode))));
1246
+ } else {
1247
+ // Regular paragraph
1248
+ return React__default.createElement("p", {
1249
+ key: index,
1250
+ className: "text-gray-700 leading-relaxed whitespace-pre-wrap"
1251
+ }, trimmedBlock);
1252
+ }
1253
+ }));
1254
+ };
1255
+ // Detect predominant text direction (RTL/LTR) for international content
1256
+ const detectTextDirection = text => {
1257
+ if (!text) return 'ltr';
1258
+ const rtlRanges = /[\u0591-\u07FF\uFB1D-\uFDFD\uFE70-\uFEFC]/g; // Hebrew, Arabic, etc.
1259
+ const ltrRanges = /[A-Za-z\u00C0-\u024F\u1E00-\u1EFF]/g;
1260
+ const rtlCount = (text.match(rtlRanges) || []).length;
1261
+ const ltrCount = (text.match(ltrRanges) || []).length;
1262
+ return rtlCount > ltrCount ? 'rtl' : 'ltr';
1263
+ };
1264
+ // Lightweight language heuristic for lang attribute
1265
+ const detectLanguageTag = text => {
1266
+ if (!text) return 'en';
1267
+ if (/\p{Script=Arabic}/u.test(text)) return 'ar';
1268
+ if (/[\u0590-\u05FF]/.test(text)) return 'he';
1269
+ if (/[\u0600-\u06FF]/.test(text)) return 'fa';
1270
+ if (/[\u0900-\u097F]/.test(text)) return 'hi';
1271
+ if (/[\u4E00-\u9FFF]/.test(text)) return 'zh';
1272
+ if (/[\u3040-\u309F\u30A0-\u30FF]/.test(text)) return 'ja';
1273
+ if (/[\uAC00-\uD7AF]/.test(text)) return 'ko';
1274
+ if (/[\u0400-\u04FF]/.test(text)) return 'ru';
1275
+ if (/[\u0E00-\u0E7F]/.test(text)) return 'th';
1276
+ return 'en';
1277
+ };
1278
+ // Attempt to parse Builder.io-like JSON blocks embedded as message string
1279
+ const tryExtractBuilderBlocks = content => {
1280
+ if (!content || content.length < 2) return null;
1281
+ try {
1282
+ const trimmed = content.trim();
1283
+ const jsonMatch = trimmed.match(/([\[{][\s\S]*[\]}])/);
1284
+ const jsonText = jsonMatch ? jsonMatch[1] : trimmed;
1285
+ const parsed = JSON.parse(jsonText);
1286
+ if (Array.isArray(parsed)) {
1287
+ if (parsed.length && (parsed[0]['@type'] || parsed[0].type)) return parsed;
1288
+ } else if (parsed && typeof parsed === 'object') {
1289
+ if (Array.isArray(parsed.blocks)) return parsed.blocks;
1290
+ if (Array.isArray(parsed?.data?.blocks)) return parsed.data.blocks;
1291
+ }
1292
+ return null;
1293
+ } catch {
1294
+ return null;
1295
+ }
1296
+ };
1297
+ const ModernMessageGroup = ({
1298
+ author,
1299
+ messages,
1300
+ currentUser,
1301
+ onOpen,
1302
+ onMessageClick,
1303
+ isDesktopView = false,
1304
+ isSmallScreen = false
1305
+ }) => {
1306
+ // Inject CSS styles for HTML content
1307
+ useInjectStyles();
1308
+ const isOwnMessage = author?.id === currentUser?.id;
1309
+ const authorName = author?.givenName && author?.familyName ? `${author.givenName} ${author.familyName}` : author?.username || 'Unknown User';
1310
+ const firstMessage = messages[0];
1311
+ const formatTime = timestamp => {
1312
+ const date = new Date(timestamp);
1313
+ return format(date, 'h:mm a');
1314
+ };
1315
+ // Determine if this is an AI/system message for special styling
1316
+ const isSystemMessage = author?.username?.toLowerCase().includes('ai') || author?.username?.toLowerCase().includes('assistant') || author?.username?.toLowerCase().includes('system');
1317
+ // For user messages, don't show group header, just individual messages with avatars
1318
+ if (isOwnMessage) {
1319
+ return React__default.createElement("div", {
1320
+ className: `min-h-fit ${isDesktopView ? 'space-y-1 mb-3' : isSmallScreen ? 'space-y-0.5 mb-2' : 'space-y-0.5 mb-2'}`
1321
+ }, messages.map((message, index) => React__default.createElement(ModernMessageBubble, {
1322
+ key: message.id,
1323
+ message: message,
1324
+ isOwnMessage: isOwnMessage,
1325
+ isSystemMessage: isSystemMessage,
1326
+ isFirstInGroup: index === 0,
1327
+ isLastInGroup: index === messages.length - 1,
1328
+ onMessageClick: onMessageClick,
1329
+ formatTime: formatTime
1330
+ })));
1331
+ }
1332
+ // For other messages (non-user), show the traditional group layout
1333
+ return React__default.createElement("div", {
1334
+ className: `group transition-all duration-300 ease-in-out ${isDesktopView ? 'mb-4 px-4 py-3' : isSmallScreen ? 'mb-2 px-2 py-1' : 'mb-3 px-3 py-1'} ${isSystemMessage ? 'bg-white rounded-lg' : ' rounded-lg'}`
1335
+ }, React__default.createElement("div", {
1336
+ className: `flex items-start ${isDesktopView ? 'space-x-4' : isSmallScreen ? 'space-x-2' : 'space-x-3'}`
1337
+ }, !isSystemMessage && React__default.createElement("div", {
1338
+ className: "flex-shrink-0 mt-1"
1339
+ }, React__default.createElement("div", {
1340
+ className: "relative rounded-lg overflow-hidden"
1341
+ }, React__default.createElement("img", {
1342
+ className: `cursor-pointer hover:opacity-80 transition-opacity ${isDesktopView ? 'w-12 h-12' : isSmallScreen ? 'w-8 h-8' : 'w-10 h-10'} rounded-lg object-cover`,
1343
+ src: author?.picture || '/default-avatar.svg',
1344
+ alt: authorName,
1345
+ onClick: () => onOpen(firstMessage),
1346
+ onError: e => {
1347
+ e.currentTarget.src = '/default-avatar.svg';
1348
+ }
1349
+ }))), React__default.createElement("div", {
1350
+ className: "flex-1 min-w-0 overflow-hidden"
1351
+ }, !isSystemMessage && React__default.createElement("div", {
1352
+ className: "flex items-center space-x-3 mb-2"
1353
+ }, React__default.createElement("span", {
1354
+ className: "font-semibold truncate text-gray-900"
1355
+ }, authorName)), React__default.createElement("div", {
1356
+ className: "space-y-1"
1357
+ }, messages.map((message, index) => React__default.createElement(ModernMessageBubble, {
1358
+ key: message.id,
1359
+ message: message,
1360
+ isOwnMessage: isOwnMessage,
1361
+ isSystemMessage: isSystemMessage,
1362
+ isFirstInGroup: index === 0,
1363
+ isLastInGroup: index === messages.length - 1,
1364
+ onMessageClick: onMessageClick,
1365
+ formatTime: formatTime
1366
+ }))))));
1367
+ };
1368
+ const ModernMessageBubble = ({
1369
+ message,
1370
+ isOwnMessage,
1371
+ isSystemMessage,
1372
+ isFirstInGroup,
1373
+ isLastInGroup,
1374
+ onMessageClick,
1375
+ formatTime
1376
+ }) => {
1377
+ const handleClick = () => {
1378
+ onMessageClick?.(message);
1379
+ };
1380
+ // For user messages, create a right-aligned layout with avatar and name
1381
+ if (isOwnMessage) {
1382
+ const authorName = message.author?.givenName && message.author?.familyName ? `${message.author.givenName} ${message.author.familyName}` : message.author?.username || 'You';
1383
+ return React__default.createElement("div", {
1384
+ className: "py-1 hover:bg-gray-50 hover:bg-opacity-50 rounded px-1 sm:px-2 -mx-1 sm:-mx-2 group"
1385
+ }, React__default.createElement("div", {
1386
+ className: "flex items-start justify-end gap-2"
1387
+ }, React__default.createElement("div", {
1388
+ className: "flex flex-col items-end max-w-xs lg:max-w-md"
1389
+ }, React__default.createElement("div", {
1390
+ className: "flex items-end space-x-2 mb-0.5"
1391
+ }, React__default.createElement("span", {
1392
+ className: "text-sm font-semibold text-gray-900"
1393
+ }, authorName)), React__default.createElement("div", {
1394
+ className: "text-sm text-gray-900 cursor-pointer hover:bg-gray-100 px-1 sm:px-2 py-1 rounded",
1395
+ onClick: handleClick,
1396
+ dir: detectTextDirection(message?.message || ''),
1397
+ lang: detectLanguageTag(message?.message || '')
1398
+ }, message.message && React__default.createElement("div", {
1399
+ className: "prose prose-sm max-w-none"
1400
+ }, isProbablyHTML(message.message) ? React__default.createElement("div", {
1401
+ className: "text-gray-800 html-content",
1402
+ dangerouslySetInnerHTML: {
1403
+ __html: prettifyHtmlContent(sanitizeHtml(message.message))
1404
+ }
1405
+ }) : React__default.createElement(FormattedMessageContent, {
1406
+ content: message.message
1407
+ })), tryExtractBuilderBlocks(message?.message)?.length ? React__default.createElement("div", {
1408
+ className: "mt-2"
1409
+ }, React__default.createElement(BuilderLikeRenderer, {
1410
+ blocks: tryExtractBuilderBlocks(message?.message)
1411
+ })) : null, message?.props?.blocks?.length ? React__default.createElement("div", {
1412
+ className: "mt-2"
1413
+ }, React__default.createElement(BuilderLikeRenderer, {
1414
+ blocks: message.props.blocks
1415
+ })) : null, message.files?.totalCount > 0 && React__default.createElement("div", {
1416
+ className: "mt-2"
1417
+ }, React__default.createElement(FilesList, {
1418
+ uploaded: true,
1419
+ files: message.files.data
1420
+ })))), React__default.createElement("div", {
1421
+ className: "flex-shrink-0 mt-0.5"
1422
+ }, React__default.createElement("img", {
1423
+ className: "w-8 h-8 sm:w-10 sm:h-10 rounded-lg cursor-pointer hover:opacity-80 transition-opacity object-cover",
1424
+ src: message.author?.picture || '/default-avatar.svg',
1425
+ alt: authorName,
1426
+ onClick: handleClick,
1427
+ onError: e => {
1428
+ e.currentTarget.src = '/default-avatar.svg';
1429
+ }
1430
+ }))));
1431
+ }
1432
+ // For other messages (left-aligned with full formatting)
1433
+ return React__default.createElement("div", {
1434
+ className: `group/message transition-all duration-200 hover:bg-gray-50 rounded-lg px-3 py-1 -mx-3 ${isSystemMessage ? '' : 'cursor-pointer'}`,
1435
+ onClick: isSystemMessage ? undefined : handleClick
1436
+ }, React__default.createElement("div", {
1437
+ className: "flex items-start justify-between gap-3"
1438
+ }, React__default.createElement("div", {
1439
+ className: "flex-1 min-w-0"
1440
+ }, message.message && React__default.createElement("div", {
1441
+ className: `prose prose-sm max-w-none ${isSystemMessage ? 'text-gray-800' : 'text-gray-900'}`,
1442
+ dir: detectTextDirection(message?.message || ''),
1443
+ lang: detectLanguageTag(message?.message || '')
1444
+ }, message.message.includes('```') ? React__default.createElement(FormattedMessageContent, {
1445
+ content: message.message
1446
+ }) : isProbablyHTML(message.message) ? React__default.createElement("div", {
1447
+ className: "prose prose-sm max-w-none text-gray-800 html-content",
1448
+ dangerouslySetInnerHTML: {
1449
+ __html: prettifyHtmlContent(sanitizeHtml(message.message))
1450
+ }
1451
+ }) : React__default.createElement(FormattedMessageContent, {
1452
+ content: message.message
1453
+ })), tryExtractBuilderBlocks(message?.message)?.length ? React__default.createElement("div", {
1454
+ className: "mt-3 p-3 bg-gray-50 rounded-lg border border-gray-200"
1455
+ }, React__default.createElement(BuilderLikeRenderer, {
1456
+ blocks: tryExtractBuilderBlocks(message?.message)
1457
+ })) : null, message?.props?.blocks?.length ? React__default.createElement("div", {
1458
+ className: "mt-3 p-3 bg-gray-50 rounded-lg border border-gray-200"
1459
+ }, React__default.createElement(BuilderLikeRenderer, {
1460
+ blocks: message.props.blocks
1461
+ })) : null, message.files?.totalCount > 0 && React__default.createElement("div", {
1462
+ className: "mt-3 p-3 bg-gray-50 rounded-lg border border-gray-200"
1463
+ }, React__default.createElement(FilesList, {
1464
+ uploaded: true,
1465
+ files: message.files.data
1466
+ }))), !isSystemMessage && React__default.createElement("div", {
1467
+ className: "flex-shrink-0 mt-1"
1468
+ }, React__default.createElement("div", {
1469
+ className: "opacity-0 group-hover/message:opacity-100 transition-opacity duration-200 flex space-x-1"
1470
+ }, React__default.createElement("button", {
1471
+ className: "p-1 hover:bg-gray-200 rounded transition-colors"
1472
+ }, React__default.createElement("svg", {
1473
+ className: "w-3 h-3 text-gray-400",
1474
+ fill: "none",
1475
+ stroke: "currentColor",
1476
+ viewBox: "0 0 24 24"
1477
+ }, React__default.createElement("path", {
1478
+ strokeLinecap: "round",
1479
+ strokeLinejoin: "round",
1480
+ strokeWidth: 2,
1481
+ d: "M8.684 13.342C8.886 12.938 9 12.482 9 12c0-.482-.114-.938-.316-1.342m0 2.684a3 3 0 110-2.684m0 2.684l6.632 3.316m-6.632-6l6.632-3.316m0 0a3 3 0 105.367-2.684 3 3 0 00-5.367 2.684zm0 9.316a3 3 0 105.367 2.684 3 3 0 00-5.367-2.684z"
1482
+ }))), React__default.createElement("button", {
1483
+ className: "p-1 hover:bg-gray-200 rounded transition-colors"
1484
+ }, React__default.createElement("svg", {
1485
+ className: "w-3 h-3 text-gray-400",
1486
+ fill: "none",
1487
+ stroke: "currentColor",
1488
+ viewBox: "0 0 24 24"
1489
+ }, React__default.createElement("path", {
1490
+ strokeLinecap: "round",
1491
+ strokeLinejoin: "round",
1492
+ strokeWidth: 2,
1493
+ d: "M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z"
1494
+ })))))));
1495
+ };
1496
+ const ModernMessageGroupComponent = ({
1497
+ messages,
1498
+ currentUser,
1499
+ onOpen,
1500
+ onMessageClick,
1501
+ isDesktopView = false,
1502
+ isSmallScreen = false
1503
+ }) => {
1504
+ // Inject CSS styles for HTML content
1505
+ useInjectStyles();
1506
+ // Filter out non-message items (like date strings)
1507
+ const actualMessages = messages.filter(msg => typeof msg !== 'string');
1508
+ // Group messages by user and time
1509
+ const messageGroups = groupMessagesByUserAndTime(actualMessages);
1510
+ return React__default.createElement("div", {
1511
+ className: `min-h-fit ${isDesktopView ? 'space-y-6' : isSmallScreen ? 'space-y-4' : 'space-y-5'}`
1512
+ }, messageGroups.map((group, groupIndex) => {
1513
+ const author = group[0]?.author;
1514
+ return React__default.createElement(ModernMessageGroup, {
1515
+ key: `group-${groupIndex}-${group[0]?.id}`,
1516
+ author: author,
1517
+ messages: group,
1518
+ currentUser: currentUser,
1519
+ onOpen: onOpen,
1520
+ onMessageClick: onMessageClick,
1521
+ isDesktopView: isDesktopView,
1522
+ isSmallScreen: isSmallScreen
1523
+ });
1524
+ }));
1525
+ };export{ModernMessageGroupComponent,groupMessagesByUserAndTime};//# sourceMappingURL=ModernMessageGroup.js.map