@memori.ai/memori-react 8.8.5 → 8.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +38 -0
- package/README.md +28 -0
- package/dist/components/Avatar/AvatarView/AvatarComponent/avatarComponent.js +0 -1
- package/dist/components/Avatar/AvatarView/AvatarComponent/avatarComponent.js.map +1 -1
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/fullbodyAvatar.js +0 -10
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/fullbodyAvatar.js.map +1 -1
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/controllers/AvatarAnimator.js +0 -9
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/controllers/AvatarAnimator.js.map +1 -1
- package/dist/components/Chat/Chat.css +31 -0
- package/dist/components/Chat/Chat.js +18 -4
- package/dist/components/Chat/Chat.js.map +1 -1
- package/dist/components/ChatBubble/ChatBubble.js +1 -2
- package/dist/components/ChatBubble/ChatBubble.js.map +1 -1
- package/dist/components/ChatInputs/ChatInputs.css +23 -0
- package/dist/components/ChatInputs/ChatInputs.d.ts +1 -0
- package/dist/components/ChatInputs/ChatInputs.js +37 -21
- package/dist/components/ChatInputs/ChatInputs.js.map +1 -1
- package/dist/components/ChatTextArea/ChatTextArea.css +31 -0
- package/dist/components/ChatTextArea/ChatTextArea.d.ts +1 -0
- package/dist/components/ChatTextArea/ChatTextArea.js +9 -2
- package/dist/components/ChatTextArea/ChatTextArea.js.map +1 -1
- package/dist/components/FilePreview/FilePreview.css +39 -0
- package/dist/components/Header/Header.js +3 -16
- package/dist/components/Header/Header.js.map +1 -1
- package/dist/components/MediaWidget/LinkItemWidget.js +1 -1
- package/dist/components/MediaWidget/LinkItemWidget.js.map +1 -1
- package/dist/components/MediaWidget/MediaItemWidget.js +5 -9
- package/dist/components/MediaWidget/MediaItemWidget.js.map +1 -1
- package/dist/components/MemoriArtifactSystem/components/ArtifactHandler/ArtifactHandler.js +65 -51
- package/dist/components/MemoriArtifactSystem/components/ArtifactHandler/ArtifactHandler.js.map +1 -1
- package/dist/components/MemoriArtifactSystem/utils/ArtifactAPI.d.ts +5 -0
- package/dist/components/MemoriArtifactSystem/utils/ArtifactAPI.js +287 -0
- package/dist/components/MemoriArtifactSystem/utils/ArtifactAPI.js.map +1 -0
- package/dist/components/MemoriWidget/MemoriWidget.d.ts +12 -0
- package/dist/components/MemoriWidget/MemoriWidget.js +12 -3
- package/dist/components/MemoriWidget/MemoriWidget.js.map +1 -1
- package/dist/components/Snippet/Snippet.js +4 -3
- package/dist/components/Snippet/Snippet.js.map +1 -1
- package/dist/components/StartPanel/StartPanel.css +14 -0
- package/dist/components/StartPanel/StartPanel.js +2 -2
- package/dist/components/StartPanel/StartPanel.js.map +1 -1
- package/dist/components/UploadButton/UploadDocuments/UploadDocuments.js +0 -21
- package/dist/components/UploadButton/UploadDocuments/UploadDocuments.js.map +1 -1
- package/dist/components/VenueWidget/VenueWidget.js +0 -1
- package/dist/components/VenueWidget/VenueWidget.js.map +1 -1
- package/dist/components/layouts/HiddenChat.js +0 -15
- package/dist/components/layouts/HiddenChat.js.map +1 -1
- package/dist/components/layouts/chat.css +2 -2
- package/dist/context/visemeContext.js +0 -6
- package/dist/context/visemeContext.js.map +1 -1
- package/dist/helpers/constants.d.ts +11 -0
- package/dist/helpers/constants.js +24 -2
- package/dist/helpers/constants.js.map +1 -1
- package/dist/helpers/tts/useTTS.js +0 -3
- package/dist/helpers/tts/useTTS.js.map +1 -1
- package/dist/helpers/utils.d.ts +1 -0
- package/dist/helpers/utils.js +6 -1
- package/dist/helpers/utils.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/locales/de.json +2 -0
- package/dist/locales/en.json +2 -0
- package/dist/locales/es.json +2 -0
- package/dist/locales/fr.json +2 -0
- package/dist/locales/it.json +2 -0
- package/esm/components/Avatar/AvatarView/AvatarComponent/avatarComponent.js +0 -1
- package/esm/components/Avatar/AvatarView/AvatarComponent/avatarComponent.js.map +1 -1
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/fullbodyAvatar.js +0 -10
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/fullbodyAvatar.js.map +1 -1
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/controllers/AvatarAnimator.js +0 -9
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/controllers/AvatarAnimator.js.map +1 -1
- package/esm/components/Chat/Chat.css +31 -0
- package/esm/components/Chat/Chat.js +19 -5
- package/esm/components/Chat/Chat.js.map +1 -1
- package/esm/components/ChatBubble/ChatBubble.js +1 -2
- package/esm/components/ChatBubble/ChatBubble.js.map +1 -1
- package/esm/components/ChatInputs/ChatInputs.css +23 -0
- package/esm/components/ChatInputs/ChatInputs.d.ts +1 -0
- package/esm/components/ChatInputs/ChatInputs.js +37 -21
- package/esm/components/ChatInputs/ChatInputs.js.map +1 -1
- package/esm/components/ChatTextArea/ChatTextArea.css +31 -0
- package/esm/components/ChatTextArea/ChatTextArea.d.ts +1 -0
- package/esm/components/ChatTextArea/ChatTextArea.js +9 -2
- package/esm/components/ChatTextArea/ChatTextArea.js.map +1 -1
- package/esm/components/FilePreview/FilePreview.css +39 -0
- package/esm/components/Header/Header.js +3 -16
- package/esm/components/Header/Header.js.map +1 -1
- package/esm/components/MediaWidget/LinkItemWidget.js +1 -1
- package/esm/components/MediaWidget/LinkItemWidget.js.map +1 -1
- package/esm/components/MediaWidget/MediaItemWidget.js +5 -9
- package/esm/components/MediaWidget/MediaItemWidget.js.map +1 -1
- package/esm/components/MemoriArtifactSystem/components/ArtifactHandler/ArtifactHandler.js +65 -51
- package/esm/components/MemoriArtifactSystem/components/ArtifactHandler/ArtifactHandler.js.map +1 -1
- package/esm/components/MemoriArtifactSystem/utils/ArtifactAPI.d.ts +5 -0
- package/esm/components/MemoriArtifactSystem/utils/ArtifactAPI.js +282 -0
- package/esm/components/MemoriArtifactSystem/utils/ArtifactAPI.js.map +1 -0
- package/esm/components/MemoriWidget/MemoriWidget.d.ts +12 -0
- package/esm/components/MemoriWidget/MemoriWidget.js +12 -3
- package/esm/components/MemoriWidget/MemoriWidget.js.map +1 -1
- package/esm/components/Snippet/Snippet.js +4 -3
- package/esm/components/Snippet/Snippet.js.map +1 -1
- package/esm/components/StartPanel/StartPanel.css +14 -0
- package/esm/components/StartPanel/StartPanel.js +3 -3
- package/esm/components/StartPanel/StartPanel.js.map +1 -1
- package/esm/components/UploadButton/UploadDocuments/UploadDocuments.js +0 -21
- package/esm/components/UploadButton/UploadDocuments/UploadDocuments.js.map +1 -1
- package/esm/components/VenueWidget/VenueWidget.js +0 -1
- package/esm/components/VenueWidget/VenueWidget.js.map +1 -1
- package/esm/components/layouts/HiddenChat.js +0 -15
- package/esm/components/layouts/HiddenChat.js.map +1 -1
- package/esm/components/layouts/chat.css +2 -2
- package/esm/context/visemeContext.js +0 -6
- package/esm/context/visemeContext.js.map +1 -1
- package/esm/helpers/constants.d.ts +11 -0
- package/esm/helpers/constants.js +22 -1
- package/esm/helpers/constants.js.map +1 -1
- package/esm/helpers/tts/useTTS.js +0 -3
- package/esm/helpers/tts/useTTS.js.map +1 -1
- package/esm/helpers/utils.d.ts +1 -0
- package/esm/helpers/utils.js +4 -0
- package/esm/helpers/utils.js.map +1 -1
- package/esm/index.js.map +1 -1
- package/esm/locales/de.json +2 -0
- package/esm/locales/en.json +2 -0
- package/esm/locales/es.json +2 -0
- package/esm/locales/fr.json +2 -0
- package/esm/locales/it.json +2 -0
- package/package.json +1 -1
- package/src/components/Avatar/AvatarView/AvatarComponent/avatarComponent.tsx +0 -1
- package/src/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/fullbodyAvatar.tsx +0 -17
- package/src/components/Avatar/AvatarView/AvatarComponent/components/controllers/AvatarAnimator.ts +0 -20
- package/src/components/Chat/Chat.css +31 -0
- package/src/components/Chat/Chat.stories.tsx +503 -9
- package/src/components/Chat/Chat.tsx +23 -3
- package/src/components/Chat/__snapshots__/Chat.test.tsx.snap +73 -73
- package/src/components/ChatBubble/ChatBubble.tsx +1 -2
- package/src/components/ChatBubble/__snapshots__/ChatBubble.test.tsx.snap +25 -25
- package/src/components/ChatInputs/ChatInputs.css +23 -0
- package/src/components/ChatInputs/ChatInputs.tsx +36 -14
- package/src/components/ChatTextArea/ChatTextArea.css +31 -0
- package/src/components/ChatTextArea/ChatTextArea.tsx +11 -1
- package/src/components/FilePreview/FilePreview.css +39 -0
- package/src/components/Header/Header.tsx +0 -13
- package/src/components/MediaWidget/LinkItemWidget.tsx +1 -1
- package/src/components/MediaWidget/MediaItemWidget.stories.tsx +33 -0
- package/src/components/MediaWidget/MediaItemWidget.tsx +7 -10
- package/src/components/MediaWidget/__snapshots__/LinkItemWidget.test.tsx.snap +4 -4
- package/src/components/MediaWidget/__snapshots__/MediaItemWidget.test.tsx.snap +6 -6
- package/src/components/MediaWidget/__snapshots__/MediaWidget.test.tsx.snap +2 -2
- package/src/components/MemoriArtifactSystem/ArtifactDrawer.stories.tsx +766 -2
- package/src/components/MemoriArtifactSystem/components/ArtifactHandler/ArtifactHandler.tsx +103 -89
- package/src/components/MemoriArtifactSystem/utils/ArtifactAPI.test.tsx +307 -0
- package/src/components/MemoriArtifactSystem/utils/ArtifactAPI.tsx +373 -0
- package/src/components/MemoriWidget/MemoriWidget.tsx +26 -4
- package/src/components/Snippet/Snippet.tsx +3 -2
- package/src/components/StartPanel/StartPanel.css +14 -0
- package/src/components/StartPanel/StartPanel.tsx +23 -10
- package/src/components/StartPanel/__snapshots__/StartPanel.test.tsx.snap +206 -84
- package/src/components/UploadButton/UploadDocuments/UploadDocuments.tsx +0 -23
- package/src/components/VenueWidget/VenueWidget.tsx +0 -1
- package/src/components/layouts/HiddenChat.tsx +0 -16
- package/src/components/layouts/__snapshots__/Chat.test.tsx.snap +204 -82
- package/src/components/layouts/__snapshots__/FullPage.test.tsx.snap +408 -164
- package/src/components/layouts/__snapshots__/HiddenChat.test.tsx.snap +204 -82
- package/src/components/layouts/__snapshots__/Totem.test.tsx.snap +204 -82
- package/src/components/layouts/__snapshots__/ZoomedFullBody.test.tsx.snap +204 -82
- package/src/components/layouts/chat.css +2 -2
- package/src/context/visemeContext.tsx +0 -7
- package/src/helpers/constants.ts +28 -3
- package/src/helpers/tts/useTTS.ts +0 -2
- package/src/helpers/utils.ts +5 -0
- package/src/index.tsx +0 -1
- package/src/locales/de.json +2 -0
- package/src/locales/en.json +2 -0
- package/src/locales/es.json +2 -0
- package/src/locales/fr.json +2 -0
- package/src/locales/it.json +2 -0
|
@@ -39,9 +39,9 @@ const Template: Story<Props> = args => {
|
|
|
39
39
|
return (
|
|
40
40
|
<I18nWrapper>
|
|
41
41
|
<ArtifactProvider>
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
<Chat
|
|
43
|
+
{...args}
|
|
44
|
+
userMessage={userMessage}
|
|
45
45
|
onChangeUserMessage={setUserMessage}
|
|
46
46
|
/>
|
|
47
47
|
</ArtifactProvider>
|
|
@@ -100,7 +100,6 @@ WithHints.args = {
|
|
|
100
100
|
setSendOnEnter: () => {},
|
|
101
101
|
};
|
|
102
102
|
|
|
103
|
-
|
|
104
103
|
export const WithArtifacts = Template.bind({});
|
|
105
104
|
WithArtifacts.args = {
|
|
106
105
|
memori,
|
|
@@ -327,7 +326,6 @@ WithCustomUserAvatarAsElement.args = {
|
|
|
327
326
|
setSendOnEnter: () => {},
|
|
328
327
|
};
|
|
329
328
|
|
|
330
|
-
|
|
331
329
|
export const WithExpandable = Template.bind({});
|
|
332
330
|
WithExpandable.args = {
|
|
333
331
|
memori,
|
|
@@ -342,6 +340,434 @@ WithExpandable.args = {
|
|
|
342
340
|
resetTranscript: () => {},
|
|
343
341
|
};
|
|
344
342
|
|
|
343
|
+
export const WithMultipleArtifactsInOneMessage = Template.bind({});
|
|
344
|
+
WithMultipleArtifactsInOneMessage.args = {
|
|
345
|
+
memori,
|
|
346
|
+
tenant,
|
|
347
|
+
sessionID,
|
|
348
|
+
history: [
|
|
349
|
+
{
|
|
350
|
+
text: 'Can you help me build a landing page?',
|
|
351
|
+
fromUser: true,
|
|
352
|
+
timestamp: '2021-03-01T12:00:00.000Z',
|
|
353
|
+
},
|
|
354
|
+
{
|
|
355
|
+
text: `I'll create a complete landing page with HTML, CSS, and JavaScript for you:
|
|
356
|
+
|
|
357
|
+
<output class="memori-artifact" data-mimetype="html" data-title="Landing Page HTML">
|
|
358
|
+
<!DOCTYPE html>
|
|
359
|
+
<html lang="en">
|
|
360
|
+
<head>
|
|
361
|
+
<meta charset="UTF-8">
|
|
362
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
363
|
+
<title>Product Landing Page</title>
|
|
364
|
+
</head>
|
|
365
|
+
<body>
|
|
366
|
+
<header class="hero">
|
|
367
|
+
<h1>Welcome to Our Amazing Product</h1>
|
|
368
|
+
<p>The solution you've been waiting for</p>
|
|
369
|
+
<button id="ctaButton" class="cta-button">Get Started</button>
|
|
370
|
+
</header>
|
|
371
|
+
|
|
372
|
+
<section class="features">
|
|
373
|
+
<div class="feature">
|
|
374
|
+
<h3>⚡ Fast</h3>
|
|
375
|
+
<p>Lightning-quick performance</p>
|
|
376
|
+
</div>
|
|
377
|
+
<div class="feature">
|
|
378
|
+
<h3>🔒 Secure</h3>
|
|
379
|
+
<p>Enterprise-grade security</p>
|
|
380
|
+
</div>
|
|
381
|
+
<div class="feature">
|
|
382
|
+
<h3>📱 Responsive</h3>
|
|
383
|
+
<p>Works on all devices</p>
|
|
384
|
+
</div>
|
|
385
|
+
</section>
|
|
386
|
+
</body>
|
|
387
|
+
</html>
|
|
388
|
+
</output>
|
|
389
|
+
|
|
390
|
+
<output class="memori-artifact" data-mimetype="css" data-title="Landing Page Styles">
|
|
391
|
+
* {
|
|
392
|
+
margin: 0;
|
|
393
|
+
padding: 0;
|
|
394
|
+
box-sizing: border-box;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
body {
|
|
398
|
+
font-family: 'Segoe UI', system-ui, sans-serif;
|
|
399
|
+
line-height: 1.6;
|
|
400
|
+
color: #333;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
.hero {
|
|
404
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
405
|
+
color: white;
|
|
406
|
+
text-align: center;
|
|
407
|
+
padding: 100px 20px;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
.hero h1 {
|
|
411
|
+
font-size: 3rem;
|
|
412
|
+
margin-bottom: 20px;
|
|
413
|
+
animation: fadeInUp 0.8s ease-out;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
.hero p {
|
|
417
|
+
font-size: 1.5rem;
|
|
418
|
+
margin-bottom: 30px;
|
|
419
|
+
opacity: 0.9;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
.cta-button {
|
|
423
|
+
background: white;
|
|
424
|
+
color: #667eea;
|
|
425
|
+
border: none;
|
|
426
|
+
padding: 15px 40px;
|
|
427
|
+
font-size: 1.1rem;
|
|
428
|
+
font-weight: 600;
|
|
429
|
+
border-radius: 50px;
|
|
430
|
+
cursor: pointer;
|
|
431
|
+
transition: all 0.3s ease;
|
|
432
|
+
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
.cta-button:hover {
|
|
436
|
+
transform: translateY(-3px);
|
|
437
|
+
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
.features {
|
|
441
|
+
display: grid;
|
|
442
|
+
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
|
443
|
+
gap: 40px;
|
|
444
|
+
padding: 80px 20px;
|
|
445
|
+
max-width: 1200px;
|
|
446
|
+
margin: 0 auto;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
.feature {
|
|
450
|
+
text-align: center;
|
|
451
|
+
padding: 30px;
|
|
452
|
+
background: white;
|
|
453
|
+
border-radius: 10px;
|
|
454
|
+
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.08);
|
|
455
|
+
transition: transform 0.3s ease;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
.feature:hover {
|
|
459
|
+
transform: translateY(-5px);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
.feature h3 {
|
|
463
|
+
font-size: 2rem;
|
|
464
|
+
margin-bottom: 15px;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
@keyframes fadeInUp {
|
|
468
|
+
from {
|
|
469
|
+
opacity: 0;
|
|
470
|
+
transform: translateY(30px);
|
|
471
|
+
}
|
|
472
|
+
to {
|
|
473
|
+
opacity: 1;
|
|
474
|
+
transform: translateY(0);
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
</output>
|
|
478
|
+
|
|
479
|
+
<output class="memori-artifact" data-mimetype="javascript" data-title="Landing Page Script">
|
|
480
|
+
// Add interactivity to the landing page
|
|
481
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
482
|
+
const ctaButton = document.getElementById('ctaButton');
|
|
483
|
+
|
|
484
|
+
if (ctaButton) {
|
|
485
|
+
ctaButton.addEventListener('click', () => {
|
|
486
|
+
// Smooth scroll animation
|
|
487
|
+
const features = document.querySelector('.features');
|
|
488
|
+
if (features) {
|
|
489
|
+
features.scrollIntoView({
|
|
490
|
+
behavior: 'smooth',
|
|
491
|
+
block: 'start'
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
// Show a welcome message
|
|
496
|
+
setTimeout(() => {
|
|
497
|
+
alert('Welcome! Explore our amazing features below 🚀');
|
|
498
|
+
}, 500);
|
|
499
|
+
});
|
|
500
|
+
|
|
501
|
+
// Add pulse animation on hover
|
|
502
|
+
ctaButton.addEventListener('mouseenter', () => {
|
|
503
|
+
ctaButton.style.animation = 'pulse 0.5s ease';
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
ctaButton.addEventListener('animationend', () => {
|
|
507
|
+
ctaButton.style.animation = '';
|
|
508
|
+
});
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
// Add scroll reveal effect to features
|
|
512
|
+
const features = document.querySelectorAll('.feature');
|
|
513
|
+
const observerOptions = {
|
|
514
|
+
threshold: 0.2,
|
|
515
|
+
rootMargin: '0px 0px -50px 0px'
|
|
516
|
+
};
|
|
517
|
+
|
|
518
|
+
const observer = new IntersectionObserver((entries) => {
|
|
519
|
+
entries.forEach((entry, index) => {
|
|
520
|
+
if (entry.isIntersecting) {
|
|
521
|
+
setTimeout(() => {
|
|
522
|
+
entry.target.style.opacity = '1';
|
|
523
|
+
entry.target.style.transform = 'translateY(0)';
|
|
524
|
+
}, index * 100);
|
|
525
|
+
observer.unobserve(entry.target);
|
|
526
|
+
}
|
|
527
|
+
});
|
|
528
|
+
}, observerOptions);
|
|
529
|
+
|
|
530
|
+
features.forEach(feature => {
|
|
531
|
+
feature.style.opacity = '0';
|
|
532
|
+
feature.style.transform = 'translateY(20px)';
|
|
533
|
+
feature.style.transition = 'all 0.6s ease';
|
|
534
|
+
observer.observe(feature);
|
|
535
|
+
});
|
|
536
|
+
});
|
|
537
|
+
|
|
538
|
+
// Add dynamic CSS for pulse animation
|
|
539
|
+
const style = document.createElement('style');
|
|
540
|
+
style.textContent = \`
|
|
541
|
+
@keyframes pulse {
|
|
542
|
+
0%, 100% { transform: scale(1); }
|
|
543
|
+
50% { transform: scale(1.05); }
|
|
544
|
+
}
|
|
545
|
+
\`;
|
|
546
|
+
document.head.appendChild(style);
|
|
547
|
+
</output>
|
|
548
|
+
|
|
549
|
+
I've created three artifacts for you:
|
|
550
|
+
1. **HTML** - The page structure with a hero section and feature cards
|
|
551
|
+
2. **CSS** - Beautiful styling with gradients, animations, and responsive design
|
|
552
|
+
3. **JavaScript** - Interactive features including smooth scrolling and scroll animations
|
|
553
|
+
|
|
554
|
+
Click on each card to view and customize the code!`,
|
|
555
|
+
timestamp: '2021-03-01T12:01:00.000Z',
|
|
556
|
+
},
|
|
557
|
+
],
|
|
558
|
+
dialogState,
|
|
559
|
+
layout: 'DEFAULT',
|
|
560
|
+
simulateUserPrompt: () => {},
|
|
561
|
+
sendMessage: (msg: string) => console.log(msg),
|
|
562
|
+
stopListening: () => {},
|
|
563
|
+
resetTranscript: () => {},
|
|
564
|
+
setAttachmentsMenuOpen: () => {},
|
|
565
|
+
setSendOnEnter: () => {},
|
|
566
|
+
};
|
|
567
|
+
|
|
568
|
+
export const WithMultipleArtifactsInChatlogPanel = Template.bind({});
|
|
569
|
+
WithMultipleArtifactsInChatlogPanel.args = {
|
|
570
|
+
memori,
|
|
571
|
+
tenant,
|
|
572
|
+
sessionID,
|
|
573
|
+
isChatlogPanel: true,
|
|
574
|
+
history: [
|
|
575
|
+
{
|
|
576
|
+
text: 'Show me a React component with its styles and tests',
|
|
577
|
+
fromUser: true,
|
|
578
|
+
timestamp: '2021-03-01T12:00:00.000Z',
|
|
579
|
+
},
|
|
580
|
+
{
|
|
581
|
+
text: `Here's a complete React component setup with TypeScript, styles, and tests:
|
|
582
|
+
|
|
583
|
+
<output class="memori-artifact" data-mimetype="typescript" data-title="Button.tsx">
|
|
584
|
+
import React from 'react';
|
|
585
|
+
import './Button.css';
|
|
586
|
+
|
|
587
|
+
interface ButtonProps {
|
|
588
|
+
label: string;
|
|
589
|
+
onClick?: () => void;
|
|
590
|
+
variant?: 'primary' | 'secondary' | 'danger';
|
|
591
|
+
disabled?: boolean;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
export const Button: React.FC<ButtonProps> = ({
|
|
595
|
+
label,
|
|
596
|
+
onClick,
|
|
597
|
+
variant = 'primary',
|
|
598
|
+
disabled = false,
|
|
599
|
+
}) => {
|
|
600
|
+
return (
|
|
601
|
+
<button
|
|
602
|
+
className={\`btn btn-\${variant}\`}
|
|
603
|
+
onClick={onClick}
|
|
604
|
+
disabled={disabled}
|
|
605
|
+
aria-label={label}
|
|
606
|
+
>
|
|
607
|
+
{label}
|
|
608
|
+
</button>
|
|
609
|
+
);
|
|
610
|
+
};
|
|
611
|
+
</output>
|
|
612
|
+
|
|
613
|
+
<output class="memori-artifact" data-mimetype="css" data-title="Button.css">
|
|
614
|
+
.btn {
|
|
615
|
+
padding: 10px 20px;
|
|
616
|
+
font-size: 16px;
|
|
617
|
+
font-weight: 600;
|
|
618
|
+
border: none;
|
|
619
|
+
border-radius: 8px;
|
|
620
|
+
cursor: pointer;
|
|
621
|
+
transition: all 0.3s ease;
|
|
622
|
+
font-family: inherit;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
.btn:disabled {
|
|
626
|
+
opacity: 0.5;
|
|
627
|
+
cursor: not-allowed;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
.btn-primary {
|
|
631
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
632
|
+
color: white;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
.btn-primary:hover:not(:disabled) {
|
|
636
|
+
transform: translateY(-2px);
|
|
637
|
+
box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
.btn-secondary {
|
|
641
|
+
background: #6c757d;
|
|
642
|
+
color: white;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
.btn-secondary:hover:not(:disabled) {
|
|
646
|
+
background: #5a6268;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
.btn-danger {
|
|
650
|
+
background: #dc3545;
|
|
651
|
+
color: white;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
.btn-danger:hover:not(:disabled) {
|
|
655
|
+
background: #c82333;
|
|
656
|
+
}
|
|
657
|
+
</output>
|
|
658
|
+
|
|
659
|
+
<output class="memori-artifact" data-mimetype="typescript" data-title="Button.test.tsx">
|
|
660
|
+
import { render, screen, fireEvent } from '@testing-library/react';
|
|
661
|
+
import { Button } from './Button';
|
|
662
|
+
|
|
663
|
+
describe('Button Component', () => {
|
|
664
|
+
it('renders with correct label', () => {
|
|
665
|
+
render(<Button label="Click me" />);
|
|
666
|
+
expect(screen.getByText('Click me')).toBeInTheDocument();
|
|
667
|
+
});
|
|
668
|
+
|
|
669
|
+
it('calls onClick handler when clicked', () => {
|
|
670
|
+
const handleClick = jest.fn();
|
|
671
|
+
render(<Button label="Click me" onClick={handleClick} />);
|
|
672
|
+
|
|
673
|
+
fireEvent.click(screen.getByText('Click me'));
|
|
674
|
+
expect(handleClick).toHaveBeenCalledTimes(1);
|
|
675
|
+
});
|
|
676
|
+
|
|
677
|
+
it('applies correct variant class', () => {
|
|
678
|
+
const { rerender } = render(<Button label="Test" variant="primary" />);
|
|
679
|
+
expect(screen.getByRole('button')).toHaveClass('btn-primary');
|
|
680
|
+
|
|
681
|
+
rerender(<Button label="Test" variant="secondary" />);
|
|
682
|
+
expect(screen.getByRole('button')).toHaveClass('btn-secondary');
|
|
683
|
+
|
|
684
|
+
rerender(<Button label="Test" variant="danger" />);
|
|
685
|
+
expect(screen.getByRole('button')).toHaveClass('btn-danger');
|
|
686
|
+
});
|
|
687
|
+
|
|
688
|
+
it('is disabled when disabled prop is true', () => {
|
|
689
|
+
const handleClick = jest.fn();
|
|
690
|
+
render(<Button label="Click me" onClick={handleClick} disabled />);
|
|
691
|
+
|
|
692
|
+
const button = screen.getByRole('button');
|
|
693
|
+
expect(button).toBeDisabled();
|
|
694
|
+
|
|
695
|
+
fireEvent.click(button);
|
|
696
|
+
expect(handleClick).not.toHaveBeenCalled();
|
|
697
|
+
});
|
|
698
|
+
|
|
699
|
+
it('has correct accessibility attributes', () => {
|
|
700
|
+
render(<Button label="Submit Form" />);
|
|
701
|
+
const button = screen.getByRole('button');
|
|
702
|
+
expect(button).toHaveAttribute('aria-label', 'Submit Form');
|
|
703
|
+
});
|
|
704
|
+
});
|
|
705
|
+
</output>
|
|
706
|
+
|
|
707
|
+
<output class="memori-artifact" data-mimetype="markdown" data-title="Button Documentation">
|
|
708
|
+
# Button Component
|
|
709
|
+
|
|
710
|
+
A reusable button component with multiple variants and full TypeScript support.
|
|
711
|
+
|
|
712
|
+
## Usage
|
|
713
|
+
|
|
714
|
+
\`\`\`tsx
|
|
715
|
+
import { Button } from './Button';
|
|
716
|
+
|
|
717
|
+
function App() {
|
|
718
|
+
return (
|
|
719
|
+
<Button
|
|
720
|
+
label="Click me"
|
|
721
|
+
variant="primary"
|
|
722
|
+
onClick={() => console.log('Clicked!')}
|
|
723
|
+
/>
|
|
724
|
+
);
|
|
725
|
+
}
|
|
726
|
+
\`\`\`
|
|
727
|
+
|
|
728
|
+
## Props
|
|
729
|
+
|
|
730
|
+
| Prop | Type | Default | Description |
|
|
731
|
+
|------|------|---------|-------------|
|
|
732
|
+
| label | string | required | Button text content |
|
|
733
|
+
| onClick | function | - | Click handler function |
|
|
734
|
+
| variant | 'primary' \\| 'secondary' \\| 'danger' | 'primary' | Button style variant |
|
|
735
|
+
| disabled | boolean | false | Disabled state |
|
|
736
|
+
|
|
737
|
+
## Variants
|
|
738
|
+
|
|
739
|
+
- **primary**: Main action button with gradient background
|
|
740
|
+
- **secondary**: Secondary actions with gray background
|
|
741
|
+
- **danger**: Destructive actions with red background
|
|
742
|
+
|
|
743
|
+
## Accessibility
|
|
744
|
+
|
|
745
|
+
- Uses semantic \`<button>\` element
|
|
746
|
+
- Includes \`aria-label\` attribute
|
|
747
|
+
- Keyboard accessible
|
|
748
|
+
- Proper disabled state handling
|
|
749
|
+
|
|
750
|
+
## Testing
|
|
751
|
+
|
|
752
|
+
Run tests with:
|
|
753
|
+
\`\`\`bash
|
|
754
|
+
npm test Button.test.tsx
|
|
755
|
+
\`\`\`
|
|
756
|
+
</output>
|
|
757
|
+
|
|
758
|
+
You now have a complete component with implementation, styles, tests, and documentation! Each artifact can be clicked to view and modify.`,
|
|
759
|
+
timestamp: '2021-03-01T12:01:00.000Z',
|
|
760
|
+
},
|
|
761
|
+
],
|
|
762
|
+
dialogState,
|
|
763
|
+
layout: 'CHAT',
|
|
764
|
+
simulateUserPrompt: () => {},
|
|
765
|
+
sendMessage: (msg: string) => console.log(msg),
|
|
766
|
+
stopListening: () => {},
|
|
767
|
+
resetTranscript: () => {},
|
|
768
|
+
setAttachmentsMenuOpen: () => {},
|
|
769
|
+
setSendOnEnter: () => {},
|
|
770
|
+
};
|
|
345
771
|
|
|
346
772
|
export const WithLongHTMLTable = Template.bind({});
|
|
347
773
|
WithLongHTMLTable.args = {
|
|
@@ -360,7 +786,7 @@ WithUploads.args = {
|
|
|
360
786
|
sessionID,
|
|
361
787
|
history: [
|
|
362
788
|
{
|
|
363
|
-
text:
|
|
789
|
+
text: 'Ciao! Sono qui per aiutarti. Puoi condividere con me documenti, immagini o link che vorresti che analizzi.',
|
|
364
790
|
timestamp: '2021-03-01T12:00:00.000Z',
|
|
365
791
|
},
|
|
366
792
|
{
|
|
@@ -513,7 +939,7 @@ WithAllMediaTypes.args = {
|
|
|
513
939
|
sessionID,
|
|
514
940
|
history: [
|
|
515
941
|
{
|
|
516
|
-
text:
|
|
942
|
+
text: 'Ciao! Sono qui per aiutarti. Posso gestire molti tipi di file e contenuti multimediali. Dimmi cosa ti serve!',
|
|
517
943
|
timestamp: '2021-03-01T12:00:00.000Z',
|
|
518
944
|
},
|
|
519
945
|
{
|
|
@@ -753,9 +1179,44 @@ build-storybook = "build-storybook"`,
|
|
|
753
1179
|
fromUser: true,
|
|
754
1180
|
timestamp: '2021-03-01T12:04:00.000Z',
|
|
755
1181
|
text: 'E anche file di configurazione e dati strutturati:\n\n<document_attachment filename="database.sql" type="text/sql">-- Schema del database\nCREATE TABLE users (\n id SERIAL PRIMARY KEY,\n username VARCHAR(50) UNIQUE NOT NULL,\n email VARCHAR(100) UNIQUE NOT NULL,\n created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP\n);\n\nCREATE TABLE posts (\n id SERIAL PRIMARY KEY,\n user_id INTEGER REFERENCES users(id),\n title VARCHAR(200) NOT NULL,\n content TEXT,\n published BOOLEAN DEFAULT FALSE,\n created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP\n);\n\n-- Indici per performance\nCREATE INDEX idx_posts_user_id ON posts(user_id);\nCREATE INDEX idx_posts_published ON posts(published);</document_attachment>\n\n<document_attachment filename="data.xml" type="text/xml"><?xml version="1.0" encoding="UTF-8"?>\n<root>\n <users>\n <user id="1">\n <name>Mario Rossi</name>\n <email>mario@example.com</email>\n <role>admin</role>\n </user>\n <user id="2">\n <name>Giulia Bianchi</name>\n <email>giulia@example.com</email>\n <role>user</role>\n </user>\n </users>\n <settings>\n <theme>dark</theme>\n <language>it</language>\n <notifications>true</notifications>\n </settings>\n</root></document_attachment>',
|
|
1182
|
+
media: [
|
|
1183
|
+
{
|
|
1184
|
+
mediumID: 'long-2',
|
|
1185
|
+
mimeType: 'text/javascript',
|
|
1186
|
+
title: 'Long JSON',
|
|
1187
|
+
content: `{
|
|
1188
|
+
"id": 1,
|
|
1189
|
+
"title": "Ciao",
|
|
1190
|
+
"description": "I'm a test!",
|
|
1191
|
+
"refs": [
|
|
1192
|
+
{
|
|
1193
|
+
"id": 1,
|
|
1194
|
+
"tag": "TEST"
|
|
1195
|
+
}
|
|
1196
|
+
]
|
|
1197
|
+
}
|
|
1198
|
+
`,
|
|
1199
|
+
},
|
|
1200
|
+
{
|
|
1201
|
+
mediumID: 'long-3',
|
|
1202
|
+
mimeType: 'text/plain',
|
|
1203
|
+
title: 'Long Text',
|
|
1204
|
+
content: `{
|
|
1205
|
+
"id": 1,
|
|
1206
|
+
"title": "Ciao",
|
|
1207
|
+
"description": "I'm a test!",
|
|
1208
|
+
"refs": [
|
|
1209
|
+
{
|
|
1210
|
+
"id": 1,
|
|
1211
|
+
"tag": "TEST"
|
|
1212
|
+
}
|
|
1213
|
+
]
|
|
1214
|
+
}`,
|
|
1215
|
+
},
|
|
1216
|
+
],
|
|
756
1217
|
},
|
|
757
1218
|
{
|
|
758
|
-
text:
|
|
1219
|
+
text: "Perfetto! Come puoi vedere, posso gestire molti tipi di contenuti:\n\n• **Immagini**: JPEG, PNG, GIF\n• **Documenti**: PDF, Word, Excel\n• **Link**: Siti web con preview\n• **Video**: MP4, AVI, QuickTime\n• **Audio**: MP3, WAV\n• **Modelli 3D**: GLB, GLTF\n• **Codice**: JavaScript, Python, CSS, SQL\n• **Dati**: JSON, XML, Markdown\n\nTutti questi contenuti vengono visualizzati in modo appropriato e possono essere interagiti dall'utente!",
|
|
759
1220
|
timestamp: '2021-03-01T12:05:00.000Z',
|
|
760
1221
|
media: [
|
|
761
1222
|
{
|
|
@@ -770,6 +1231,39 @@ build-storybook = "build-storybook"`,
|
|
|
770
1231
|
mimeType: 'text/html',
|
|
771
1232
|
title: 'Documentazione completa',
|
|
772
1233
|
},
|
|
1234
|
+
{
|
|
1235
|
+
mediumID: 'long-2',
|
|
1236
|
+
mimeType: 'text/javascript',
|
|
1237
|
+
title: 'Long JSON',
|
|
1238
|
+
content: `{
|
|
1239
|
+
"id": 1,
|
|
1240
|
+
"title": "Ciao",
|
|
1241
|
+
"description": "I'm a test!",
|
|
1242
|
+
"refs": [
|
|
1243
|
+
{
|
|
1244
|
+
"id": 1,
|
|
1245
|
+
"tag": "TEST"
|
|
1246
|
+
}
|
|
1247
|
+
]
|
|
1248
|
+
}
|
|
1249
|
+
`,
|
|
1250
|
+
},
|
|
1251
|
+
{
|
|
1252
|
+
mediumID: 'long-3',
|
|
1253
|
+
mimeType: 'text/plain',
|
|
1254
|
+
title: 'Long Text',
|
|
1255
|
+
content: `{
|
|
1256
|
+
"id": 1,
|
|
1257
|
+
"title": "Ciao",
|
|
1258
|
+
"description": "I'm a test!",
|
|
1259
|
+
"refs": [
|
|
1260
|
+
{
|
|
1261
|
+
"id": 1,
|
|
1262
|
+
"tag": "TEST"
|
|
1263
|
+
}
|
|
1264
|
+
]
|
|
1265
|
+
}`,
|
|
1266
|
+
},
|
|
773
1267
|
],
|
|
774
1268
|
},
|
|
775
1269
|
],
|
|
@@ -781,4 +1275,4 @@ build-storybook = "build-storybook"`,
|
|
|
781
1275
|
resetTranscript: () => {},
|
|
782
1276
|
setAttachmentsMenuOpen: () => {},
|
|
783
1277
|
setSendOnEnter: () => {},
|
|
784
|
-
};
|
|
1278
|
+
};
|
|
@@ -124,11 +124,13 @@ const Chat: React.FC<Props> = ({
|
|
|
124
124
|
isChatlogPanel = false,
|
|
125
125
|
showFunctionCache = false,
|
|
126
126
|
}) => {
|
|
127
|
+
const [isTextareaExpanded, setIsTextareaExpanded] = useState(false);
|
|
128
|
+
|
|
127
129
|
const scrollToBottom = () => {
|
|
128
130
|
if (isHistoryView) return;
|
|
129
131
|
setTimeout(() => {
|
|
130
132
|
let userMsgs = document.querySelectorAll(
|
|
131
|
-
'.memori-chat
|
|
133
|
+
'.memori-chat-scroll-item'
|
|
132
134
|
);
|
|
133
135
|
userMsgs[userMsgs.length - 1]?.scrollIntoView?.();
|
|
134
136
|
}, 200);
|
|
@@ -137,6 +139,15 @@ const Chat: React.FC<Props> = ({
|
|
|
137
139
|
!preview && !isHistoryView && scrollToBottom();
|
|
138
140
|
}, [history, preview, isHistoryView]);
|
|
139
141
|
|
|
142
|
+
// Scroll to bottom when textarea is expanded
|
|
143
|
+
useEffect(() => {
|
|
144
|
+
if (isTextareaExpanded && !isHistoryView) {
|
|
145
|
+
setTimeout(() => {
|
|
146
|
+
scrollToBottom();
|
|
147
|
+
}, 250);
|
|
148
|
+
}
|
|
149
|
+
}, [isTextareaExpanded, isHistoryView]);
|
|
150
|
+
|
|
140
151
|
const onTextareaFocus = () => {
|
|
141
152
|
stopListening();
|
|
142
153
|
const hasTouch = hasTouchscreen();
|
|
@@ -168,10 +179,15 @@ const Chat: React.FC<Props> = ({
|
|
|
168
179
|
}
|
|
169
180
|
};
|
|
170
181
|
|
|
182
|
+
const onTextareaExpanded = (expanded: boolean) => {
|
|
183
|
+
setIsTextareaExpanded(expanded);
|
|
184
|
+
};
|
|
185
|
+
|
|
171
186
|
return (
|
|
172
187
|
<div
|
|
173
188
|
className={cx('memori-chat--wrapper', {
|
|
174
189
|
'memori-chat-wrapper--translate': translateTo,
|
|
190
|
+
'memori-chat-wrapper--expanded': isTextareaExpanded,
|
|
175
191
|
})}
|
|
176
192
|
id="chat-wrapper"
|
|
177
193
|
lang={translateTo?.toUpperCase()}
|
|
@@ -301,7 +317,7 @@ const Chat: React.FC<Props> = ({
|
|
|
301
317
|
// Filter out HTML and plain text media items from the message
|
|
302
318
|
...(message?.media?.filter(
|
|
303
319
|
m =>
|
|
304
|
-
m.mimeType !== 'text/html'
|
|
320
|
+
m.mimeType !== 'text/html'
|
|
305
321
|
) || []),
|
|
306
322
|
|
|
307
323
|
// Extract document attachments that are embedded in the message text
|
|
@@ -316,6 +332,7 @@ const Chat: React.FC<Props> = ({
|
|
|
316
332
|
|
|
317
333
|
const attachments: (Medium & { type?: string })[] = [];
|
|
318
334
|
let match;
|
|
335
|
+
let attachmentIndex = 0;
|
|
319
336
|
|
|
320
337
|
// Find all document attachments in the text
|
|
321
338
|
while (
|
|
@@ -330,7 +347,7 @@ const Chat: React.FC<Props> = ({
|
|
|
330
347
|
// - Trimmed content from the attachment
|
|
331
348
|
// - Properties to mark it as a document attachment
|
|
332
349
|
attachments.push({
|
|
333
|
-
mediumID: `doc_${Date.now()}_${Math.random()
|
|
350
|
+
mediumID: `doc_${Date.now()}_${attachmentIndex}_${Math.random()
|
|
334
351
|
.toString(36)
|
|
335
352
|
.substr(2, 9)}`,
|
|
336
353
|
url: '',
|
|
@@ -340,6 +357,8 @@ const Chat: React.FC<Props> = ({
|
|
|
340
357
|
properties: { isDocumentAttachment: true },
|
|
341
358
|
type: 'document',
|
|
342
359
|
});
|
|
360
|
+
|
|
361
|
+
attachmentIndex++;
|
|
343
362
|
}
|
|
344
363
|
|
|
345
364
|
return attachments;
|
|
@@ -422,6 +441,7 @@ const Chat: React.FC<Props> = ({
|
|
|
422
441
|
setAttachmentsMenuOpen={setAttachmentsMenuOpen}
|
|
423
442
|
onTextareaFocus={onTextareaFocus}
|
|
424
443
|
onTextareaBlur={onTextareaBlur}
|
|
444
|
+
onTextareaExpanded={onTextareaExpanded}
|
|
425
445
|
startListening={startListening}
|
|
426
446
|
stopListening={stopListening}
|
|
427
447
|
stopAudio={stopAudio}
|