@memori.ai/memori-react 9.0.0-alpha.20 → 9.0.0-alpha.21

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 (159) hide show
  1. package/CHANGELOG.md +438 -1
  2. package/dist/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/fullbodyAvatar.js +1 -1
  3. package/dist/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/fullbodyAvatar.js.map +1 -1
  4. package/dist/components/Avatar/AvatarView/AvatarComponent/constants.d.ts +2 -2
  5. package/dist/components/Avatar/AvatarView/AvatarComponent/constants.js +6 -6
  6. package/dist/components/Avatar/AvatarView/AvatarComponent/constants.js.map +1 -1
  7. package/dist/components/ChatInputs/ChatInputs.js +1 -1
  8. package/dist/components/ChatInputs/ChatInputs.js.map +1 -1
  9. package/dist/components/ContentPreviewModal/ContentPreviewModal.css +6 -22
  10. package/dist/components/FilePreview/FilePreview.css +41 -20
  11. package/dist/components/FilePreview/FilePreview.d.ts +2 -1
  12. package/dist/components/FilePreview/FilePreview.js +6 -2
  13. package/dist/components/FilePreview/FilePreview.js.map +1 -1
  14. package/dist/components/KnownFacts/KnownFacts.js +2 -2
  15. package/dist/components/KnownFacts/KnownFacts.js.map +1 -1
  16. package/dist/components/MemoriArtifactSystem/components/ArtifactActions/ArtifactActions.js +1 -1
  17. package/dist/components/MemoriArtifactSystem/components/ArtifactActions/ArtifactActions.js.map +1 -1
  18. package/dist/components/MemoriArtifactSystem/components/ArtifactActions/components/CopyButtonWithDropdown.js +14 -12
  19. package/dist/components/MemoriArtifactSystem/components/ArtifactActions/components/CopyButtonWithDropdown.js.map +1 -1
  20. package/dist/components/MemoriArtifactSystem/components/ArtifactActions/styles.css +1 -106
  21. package/dist/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.css +8 -9
  22. package/dist/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.js +1 -0
  23. package/dist/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.js.map +1 -1
  24. package/dist/components/MemoriArtifactSystem/components/ArtifactDrawer/components/TabSwitch.css +7 -0
  25. package/dist/components/MemoriArtifactSystem/components/ArtifactHandler/ArtifactHandler.js +210 -62
  26. package/dist/components/MemoriArtifactSystem/components/ArtifactHandler/ArtifactHandler.js.map +1 -1
  27. package/dist/components/MemoriArtifactSystem/context/ArtifactContext.d.ts +3 -1
  28. package/dist/components/MemoriArtifactSystem/context/ArtifactContext.js +65 -1
  29. package/dist/components/MemoriArtifactSystem/context/ArtifactContext.js.map +1 -1
  30. package/dist/components/MemoriArtifactSystem/types/artifact.types.d.ts +11 -0
  31. package/dist/components/MemoriArtifactSystem/utils/ArtifactAPI.js +18 -13
  32. package/dist/components/MemoriArtifactSystem/utils/ArtifactAPI.js.map +1 -1
  33. package/dist/components/MemoriArtifactSystem/utils/applyEdits.d.ts +8 -0
  34. package/dist/components/MemoriArtifactSystem/utils/applyEdits.js +117 -0
  35. package/dist/components/MemoriArtifactSystem/utils/applyEdits.js.map +1 -0
  36. package/dist/components/MemoriWidget/MemoriWidget.css +59 -0
  37. package/dist/components/Snippet/Snippet.css +6 -36
  38. package/dist/components/Snippet/Snippet.js +3 -1
  39. package/dist/components/Snippet/Snippet.js.map +1 -1
  40. package/dist/components/StartPanel/StartPanel.css +106 -0
  41. package/dist/components/StartPanel/StartPanel.js +1 -1
  42. package/dist/components/StartPanel/StartPanel.js.map +1 -1
  43. package/dist/components/UploadButton/UploadButton.css +0 -19
  44. package/dist/components/UploadButton/UploadButton.js +1 -3
  45. package/dist/components/UploadButton/UploadButton.js.map +1 -1
  46. package/dist/components/UploadButton/UploadImages/UploadImages.js +1 -1
  47. package/dist/components/UploadButton/UploadImages/UploadImages.js.map +1 -1
  48. package/dist/components/layouts/chat.css +2 -0
  49. package/dist/components/layouts/zoomed-full-body.css +1 -0
  50. package/dist/helpers/message.js +3 -0
  51. package/dist/helpers/message.js.map +1 -1
  52. package/dist/locales/de.json +3 -0
  53. package/dist/locales/en.json +3 -0
  54. package/dist/locales/es.json +3 -0
  55. package/dist/locales/fr.json +3 -0
  56. package/dist/locales/it.json +3 -0
  57. package/dist/styles.css +1 -1
  58. package/dist/version.d.ts +1 -1
  59. package/dist/version.js +1 -1
  60. package/esm/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/fullbodyAvatar.js +2 -2
  61. package/esm/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/fullbodyAvatar.js.map +1 -1
  62. package/esm/components/Avatar/AvatarView/AvatarComponent/constants.d.ts +2 -2
  63. package/esm/components/Avatar/AvatarView/AvatarComponent/constants.js +4 -5
  64. package/esm/components/Avatar/AvatarView/AvatarComponent/constants.js.map +1 -1
  65. package/esm/components/ChatInputs/ChatInputs.js +1 -1
  66. package/esm/components/ChatInputs/ChatInputs.js.map +1 -1
  67. package/esm/components/ContentPreviewModal/ContentPreviewModal.css +6 -22
  68. package/esm/components/FilePreview/FilePreview.css +41 -20
  69. package/esm/components/FilePreview/FilePreview.d.ts +2 -1
  70. package/esm/components/FilePreview/FilePreview.js +7 -3
  71. package/esm/components/FilePreview/FilePreview.js.map +1 -1
  72. package/esm/components/KnownFacts/KnownFacts.js +2 -2
  73. package/esm/components/KnownFacts/KnownFacts.js.map +1 -1
  74. package/esm/components/MemoriArtifactSystem/components/ArtifactActions/ArtifactActions.js +1 -1
  75. package/esm/components/MemoriArtifactSystem/components/ArtifactActions/ArtifactActions.js.map +1 -1
  76. package/esm/components/MemoriArtifactSystem/components/ArtifactActions/components/CopyButtonWithDropdown.js +15 -13
  77. package/esm/components/MemoriArtifactSystem/components/ArtifactActions/components/CopyButtonWithDropdown.js.map +1 -1
  78. package/esm/components/MemoriArtifactSystem/components/ArtifactActions/styles.css +1 -106
  79. package/esm/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.css +8 -9
  80. package/esm/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.js +1 -0
  81. package/esm/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.js.map +1 -1
  82. package/esm/components/MemoriArtifactSystem/components/ArtifactDrawer/components/TabSwitch.css +7 -0
  83. package/esm/components/MemoriArtifactSystem/components/ArtifactHandler/ArtifactHandler.js +211 -63
  84. package/esm/components/MemoriArtifactSystem/components/ArtifactHandler/ArtifactHandler.js.map +1 -1
  85. package/esm/components/MemoriArtifactSystem/context/ArtifactContext.d.ts +3 -1
  86. package/esm/components/MemoriArtifactSystem/context/ArtifactContext.js +66 -2
  87. package/esm/components/MemoriArtifactSystem/context/ArtifactContext.js.map +1 -1
  88. package/esm/components/MemoriArtifactSystem/types/artifact.types.d.ts +11 -0
  89. package/esm/components/MemoriArtifactSystem/utils/ArtifactAPI.js +18 -13
  90. package/esm/components/MemoriArtifactSystem/utils/ArtifactAPI.js.map +1 -1
  91. package/esm/components/MemoriArtifactSystem/utils/applyEdits.d.ts +8 -0
  92. package/esm/components/MemoriArtifactSystem/utils/applyEdits.js +112 -0
  93. package/esm/components/MemoriArtifactSystem/utils/applyEdits.js.map +1 -0
  94. package/esm/components/MemoriWidget/MemoriWidget.css +59 -0
  95. package/esm/components/Snippet/Snippet.css +6 -36
  96. package/esm/components/Snippet/Snippet.js +4 -2
  97. package/esm/components/Snippet/Snippet.js.map +1 -1
  98. package/esm/components/StartPanel/StartPanel.css +106 -0
  99. package/esm/components/StartPanel/StartPanel.js +2 -2
  100. package/esm/components/StartPanel/StartPanel.js.map +1 -1
  101. package/esm/components/UploadButton/UploadButton.css +0 -19
  102. package/esm/components/UploadButton/UploadButton.js +1 -3
  103. package/esm/components/UploadButton/UploadButton.js.map +1 -1
  104. package/esm/components/UploadButton/UploadImages/UploadImages.js +1 -1
  105. package/esm/components/UploadButton/UploadImages/UploadImages.js.map +1 -1
  106. package/esm/components/layouts/chat.css +2 -0
  107. package/esm/components/layouts/zoomed-full-body.css +1 -0
  108. package/esm/helpers/message.js +3 -0
  109. package/esm/helpers/message.js.map +1 -1
  110. package/esm/locales/de.json +3 -0
  111. package/esm/locales/en.json +3 -0
  112. package/esm/locales/es.json +3 -0
  113. package/esm/locales/fr.json +3 -0
  114. package/esm/locales/it.json +3 -0
  115. package/esm/styles.css +1 -1
  116. package/esm/version.d.ts +1 -1
  117. package/esm/version.js +1 -1
  118. package/package.json +1 -1
  119. package/src/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/fullbodyAvatar.tsx +2 -2
  120. package/src/components/Avatar/AvatarView/AvatarComponent/constants.test.ts +19 -0
  121. package/src/components/Avatar/AvatarView/AvatarComponent/constants.ts +9 -6
  122. package/src/components/ChatInputs/ChatInputs.tsx +1 -0
  123. package/src/components/ContentPreviewModal/ContentPreviewModal.css +6 -22
  124. package/src/components/FilePreview/FilePreview.css +41 -20
  125. package/src/components/FilePreview/FilePreview.tsx +14 -0
  126. package/src/components/FilePreview/__snapshots__/FilePreview.test.tsx.snap +14 -0
  127. package/src/components/KnownFacts/KnownFacts.tsx +0 -2
  128. package/src/components/MediaWidget/MediaPreviewModal.test.tsx +2 -3
  129. package/src/components/MemoriArtifactSystem/components/ArtifactActions/ArtifactActions.tsx +19 -33
  130. package/src/components/MemoriArtifactSystem/components/ArtifactActions/components/CopyButtonWithDropdown.tsx +44 -45
  131. package/src/components/MemoriArtifactSystem/components/ArtifactActions/styles.css +1 -106
  132. package/src/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.css +8 -9
  133. package/src/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.tsx +24 -20
  134. package/src/components/MemoriArtifactSystem/components/ArtifactDrawer/components/TabSwitch.css +7 -0
  135. package/src/components/MemoriArtifactSystem/components/ArtifactHandler/ArtifactHandler.tsx +357 -148
  136. package/src/components/MemoriArtifactSystem/context/ArtifactContext.tsx +111 -9
  137. package/src/components/MemoriArtifactSystem/types/artifact.types.ts +20 -1
  138. package/src/components/MemoriArtifactSystem/utils/ArtifactAPI.test.tsx +1 -0
  139. package/src/components/MemoriArtifactSystem/utils/ArtifactAPI.tsx +19 -13
  140. package/src/components/MemoriArtifactSystem/utils/applyEdits.test.ts +85 -0
  141. package/src/components/MemoriArtifactSystem/utils/applyEdits.ts +173 -0
  142. package/src/components/MemoriWidget/MemoriWidget.css +59 -0
  143. package/src/components/Snippet/Snippet.css +6 -36
  144. package/src/components/Snippet/Snippet.tsx +6 -7
  145. package/src/components/StartPanel/StartPanel.css +106 -0
  146. package/src/components/StartPanel/StartPanel.stories.tsx +20 -0
  147. package/src/components/StartPanel/StartPanel.tsx +8 -0
  148. package/src/components/UploadButton/UploadButton.css +0 -19
  149. package/src/components/UploadButton/UploadButton.tsx +0 -11
  150. package/src/components/UploadButton/UploadImages/UploadImages.tsx +1 -1
  151. package/src/components/layouts/chat.css +2 -0
  152. package/src/components/layouts/zoomed-full-body.css +1 -0
  153. package/src/helpers/message.ts +15 -0
  154. package/src/locales/de.json +3 -0
  155. package/src/locales/en.json +3 -0
  156. package/src/locales/es.json +3 -0
  157. package/src/locales/fr.json +3 -0
  158. package/src/locales/it.json +3 -0
  159. package/src/version.ts +1 -1
package/esm/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const version = "9.0.0-alpha.20";
1
+ export declare const version = "9.0.0-alpha.21";
package/esm/version.js CHANGED
@@ -1,2 +1,2 @@
1
- export const version = '9.0.0-alpha.20';
1
+ export const version = '9.0.0-alpha.21';
2
2
  //# sourceMappingURL=version.js.map
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "9.0.0-alpha.20",
2
+ "version": "9.0.0-alpha.21",
3
3
  "name": "@memori.ai/memori-react",
4
4
  "author": "Memori Srl",
5
5
  "main": "dist/index.js",
@@ -9,7 +9,7 @@ import {
9
9
  ANIMATION_URLS,
10
10
  AVATAR_POSITION,
11
11
  AVATAR_ROTATION,
12
- MALE_EXCLUDED_ANIMATIONS,
12
+ isMaleExcludedAnimation,
13
13
  SCALE_LERP_FACTOR,
14
14
  } from '../../constants';
15
15
  import DynamicShadow from '../../Shadow/DynamicShadow';
@@ -74,7 +74,7 @@ export function FullbodyAvatar({
74
74
 
75
75
  if (sex !== 'MALE') return clips;
76
76
 
77
- return clips.filter(clip => !MALE_EXCLUDED_ANIMATIONS.has(clip.name));
77
+ return clips.filter(clip => !isMaleExcludedAnimation(clip.name));
78
78
  }, [baseAnimations, additionalAnimations, needsAdditionalAnimations, sex]);
79
79
 
80
80
  // Create animation actions from the merged animations
@@ -0,0 +1,19 @@
1
+ import { isMaleExcludedAnimation } from './constants';
2
+
3
+ describe('isMaleExcludedAnimation', () => {
4
+ it('excludes the unnumbered Idle clip and its Blender duplicate', () => {
5
+ expect(isMaleExcludedAnimation('Idle')).toBe(true);
6
+ expect(isMaleExcludedAnimation('Idle_Armature.003')).toBe(true);
7
+ });
8
+
9
+ it('keeps numbered idle variants in the rotation', () => {
10
+ expect(isMaleExcludedAnimation('Idle1')).toBe(false);
11
+ expect(isMaleExcludedAnimation('Idle2')).toBe(false);
12
+ expect(isMaleExcludedAnimation('Idle3')).toBe(false);
13
+ expect(isMaleExcludedAnimation('Idle4')).toBe(false);
14
+ expect(isMaleExcludedAnimation('Idle5')).toBe(false);
15
+ expect(isMaleExcludedAnimation('Idle 1_Armature.003')).toBe(false);
16
+ expect(isMaleExcludedAnimation('Idle 2_Armature.003')).toBe(false);
17
+ expect(isMaleExcludedAnimation('Idle 3_Armature.003')).toBe(false);
18
+ });
19
+ });
@@ -113,11 +113,14 @@ export const ANIMATION_URLS = {
113
113
  'https://assets.memori.ai/api/v2/asset/2adc934b-24b2-45bd-94ad-ffec58d3cb32.glb',
114
114
  };
115
115
 
116
- /** Idle clips excluded from the male animation pack. */
117
- export const MALE_EXCLUDED_ANIMATIONS = new Set([
118
- 'Idle',
119
- 'Idle2'
120
- ]);
116
+ /**
117
+ * Unnumbered Idle clips excluded from the male animation pack.
118
+ * Matches `Idle` and Blender duplicates like `Idle_Armature.003`,
119
+ * but not numbered variants (`Idle1`, `Idle3`, `Idle 1_Armature.003`, ...).
120
+ */
121
+ export function isMaleExcludedAnimation(clipName: string): boolean {
122
+ return /^Idle(?!\d| \d)/.test(clipName);
123
+ }
121
124
 
122
125
  // Blink configuration
123
126
  export const BLINK_CONFIG = {
@@ -138,4 +141,4 @@ export const DEFAULT_CONFIG: AnimationConfig = {
138
141
  export const EMOTION_SMOOTHING = 0.3;
139
142
  export const VISEME_SMOOTHING = 0.5;
140
143
  /** Multiplier applied to emotion morph target values before clamping (1 = raw mapping). */
141
- export const EMOTION_INTENSITY = 2.5;
144
+ export const EMOTION_INTENSITY = 1.5;
@@ -374,6 +374,7 @@ ${text}
374
374
  removeFile={removeFile}
375
375
  showAnonymousRetentionNotice={!authToken}
376
376
  uploadingCount={uploadingCount}
377
+ maxDocumentsPerMessage={maxDocumentsPerMessage}
377
378
  />
378
379
  </div>
379
380
  )}
@@ -32,12 +32,18 @@
32
32
  }
33
33
 
34
34
  .memori-modal__viewport.memori-content-preview-modal .memori-modal__title {
35
+ overflow: hidden;
36
+ min-width: 0;
37
+ max-width: 100%;
35
38
  padding: 1rem 1.25rem 0.75rem;
39
+ padding-right: calc(var(--memori-icon-button-size, 40px) + 1.5rem);
36
40
  border-bottom: 1px solid var(--memori-content-preview-border, rgba(0, 0, 0, 0.06));
37
41
  color: var(--memori-text-color);
38
42
  font-size: var(--memori-text-size-base);
39
43
  font-weight: var(--memori-text-weight-semibold);
40
44
  letter-spacing: -0.01em;
45
+ text-overflow: ellipsis;
46
+ white-space: nowrap;
41
47
  }
42
48
 
43
49
  .memori-modal__viewport.memori-content-preview-modal .memori-modal__close {
@@ -45,28 +51,6 @@
45
51
  right: 0.75rem;
46
52
  }
47
53
 
48
- .memori-modal__viewport.memori-content-preview-modal .memori-modal__close button {
49
- border-radius: var(--memori-radius-box);
50
- background: var(--memori-content-preview-close-bg, rgba(0, 0, 0, 0.05));
51
- color: var(--memori-text-color, #111827);
52
- transition: background 0.2s ease, transform 0.15s ease;
53
- }
54
-
55
- .memori-modal__viewport.memori-content-preview-modal .memori-modal__close button svg {
56
- color: currentColor;
57
- }
58
-
59
- .memori-modal__viewport.memori-content-preview-modal .memori-modal__close button:hover {
60
- background: var(--memori-content-preview-close-hover, rgba(0, 0, 0, 0.1));
61
- transform: scale(1.05);
62
- }
63
-
64
- [data-theme='dark'] .memori-modal__viewport.memori-content-preview-modal .memori-modal__close button,
65
- .memori-widget[data-theme='dark'] .memori-modal__viewport.memori-content-preview-modal .memori-modal__close button {
66
- background: color-mix(in srgb, var(--memori-main-background, #111) 85%, white);
67
- color: var(--memori-text-color, #fff);
68
- }
69
-
70
54
  .memori-content-preview-modal--body--image {
71
55
  display: flex;
72
56
  align-items: center;
@@ -1,6 +1,7 @@
1
1
  /* Updated FilePreview Styles */
2
2
 
3
3
  .memori--preview-container {
4
+ position: relative;
4
5
  z-index: 10;
5
6
  overflow: hidden;
6
7
  width: 100%;
@@ -12,6 +13,46 @@
12
13
  transition: all 0.3s ease;
13
14
  }
14
15
 
16
+ .memori--preview-list {
17
+ display: flex;
18
+ width: 100%;
19
+ min-width: 0;
20
+ max-width: 100%;
21
+ box-sizing: border-box;
22
+ flex-direction: row;
23
+ flex-wrap: nowrap;
24
+ padding: 0.875rem;
25
+ padding-bottom: 0.625rem;
26
+ gap: 8px;
27
+ -webkit-overflow-scrolling: touch;
28
+ overflow-x: auto;
29
+ overflow-y: hidden;
30
+ overscroll-behavior-x: contain;
31
+ scrollbar-color: hsla(var(--border-300) / 35%) transparent;
32
+ scrollbar-width: thin;
33
+ touch-action: pan-x;
34
+ }
35
+
36
+ .memori--document-count {
37
+ position: absolute;
38
+ z-index: 5;
39
+ top: 8px;
40
+ right: 8px;
41
+ padding: calc(var(--memori-spacing-xs) / 4) calc(var(--memori-spacing-xs) + 2px);
42
+ border-radius: var(--memori-radius-box);
43
+ color: var(--memori-text-color);
44
+ font-size: 12px;
45
+ font-weight: bold;
46
+ }
47
+
48
+ .memori--document-count-full {
49
+ background-color: #fa5252;
50
+ }
51
+
52
+ .memori--preview-container:has(.memori--document-count) .memori--preview-list {
53
+ padding-right: 2.75rem;
54
+ }
55
+
15
56
  .memori--preview-container.slide-down {
16
57
  animation: slide-down 0.3s ease;
17
58
  }
@@ -106,26 +147,6 @@
106
147
  margin: calc(var(--memori-spacing-sm) + var(--memori-spacing-xs)) 0;
107
148
  }
108
149
 
109
- .memori--preview-list {
110
- display: flex;
111
- width: 100%;
112
- min-width: 0;
113
- max-width: 100%;
114
- box-sizing: border-box;
115
- flex-direction: row;
116
- flex-wrap: nowrap;
117
- padding: 0.875rem;
118
- padding-bottom: 0.625rem;
119
- gap: 8px;
120
- -webkit-overflow-scrolling: touch;
121
- overflow-x: auto;
122
- overflow-y: hidden;
123
- overscroll-behavior-x: contain;
124
- scrollbar-color: hsla(var(--border-300) / 35%) transparent;
125
- scrollbar-width: thin;
126
- touch-action: pan-x;
127
- }
128
-
129
150
  .memori--preview-item {
130
151
  position: relative;
131
152
  display: flex;
@@ -11,6 +11,8 @@ import {
11
11
  } from '../../helpers/utils';
12
12
  import { getDocumentBadgeLabel } from '../MediaWidget/MediaItemWidget.utils';
13
13
  import { useTranslation } from 'react-i18next';
14
+ import cx from 'classnames';
15
+ import { maxDocumentsPerMessage as defaultMaxDocumentsPerMessage } from '../../helpers/constants';
14
16
 
15
17
  type FilePreviewProps = {
16
18
  previewFiles: any;
@@ -18,6 +20,7 @@ type FilePreviewProps = {
18
20
  allowRemove?: boolean;
19
21
  showAnonymousRetentionNotice?: boolean;
20
22
  uploadingCount?: number;
23
+ maxDocumentsPerMessage?: number;
21
24
  };
22
25
 
23
26
  const FilePreview = ({
@@ -26,6 +29,7 @@ const FilePreview = ({
26
29
  allowRemove = true,
27
30
  showAnonymousRetentionNotice = false,
28
31
  uploadingCount = 0,
32
+ maxDocumentsPerMessage = defaultMaxDocumentsPerMessage,
29
33
  }: FilePreviewProps) => {
30
34
  const { t } = useTranslation();
31
35
  const [selectedFile, setSelectedFile] = useState<{
@@ -152,6 +156,16 @@ const FilePreview = ({
152
156
  <>
153
157
  {(previewFiles.length > 0 || uploadingCount > 0) && (
154
158
  <div className="memori--preview-container">
159
+ {previewFiles.length > 0 && (
160
+ <div
161
+ className={cx('memori--document-count', {
162
+ 'memori--document-count-full':
163
+ previewFiles.length >= maxDocumentsPerMessage,
164
+ })}
165
+ >
166
+ {previewFiles.length}/{maxDocumentsPerMessage}
167
+ </div>
168
+ )}
155
169
  {showAnonymousRetentionNotice && (
156
170
  <small
157
171
  style={{
@@ -7,6 +7,13 @@ exports[`renders FilePreview with one file 1`] = `
7
7
  <div
8
8
  class="memori--preview-container"
9
9
  >
10
+ <div
11
+ class="memori--document-count"
12
+ >
13
+ 1
14
+ /
15
+ 10
16
+ </div>
10
17
  <div
11
18
  class="memori--preview-list"
12
19
  >
@@ -95,6 +102,13 @@ exports[`renders FilePreview with two files 1`] = `
95
102
  <div
96
103
  class="memori--preview-container"
97
104
  >
105
+ <div
106
+ class="memori--document-count"
107
+ >
108
+ 2
109
+ /
110
+ 10
111
+ </div>
98
112
  <div
99
113
  class="memori--preview-list"
100
114
  >
@@ -213,7 +213,6 @@ const KnownFacts = ({
213
213
  <>
214
214
  <Button
215
215
  variant="ghost"
216
- danger
217
216
  onClick={() => {
218
217
  setBulkDeleteModalVisible(false);
219
218
  setBulkDeleteIds([]);
@@ -341,7 +340,6 @@ const KnownFacts = ({
341
340
  <>
342
341
  <Button
343
342
  variant="ghost"
344
- danger
345
343
  onClick={() => {
346
344
  setDeleteModalVisibleFor(undefined);
347
345
  }}
@@ -259,9 +259,8 @@ describe('MediaPreviewModal', () => {
259
259
  render(
260
260
  <MediaPreviewModal medium={medium} onClose={onClose} />
261
261
  );
262
- const closeWrapper = document.querySelector('.memori-modal__close');
263
- expect(closeWrapper).toBeInTheDocument();
264
- const closeButton = closeWrapper?.querySelector('button');
262
+ const closeButton = document.querySelector('.memori-modal__close');
263
+ expect(closeButton).toBeInTheDocument();
265
264
  if (closeButton) {
266
265
  fireEvent.click(closeButton);
267
266
  expect(onClose).toHaveBeenCalled();
@@ -4,16 +4,12 @@
4
4
  * Following the project's component patterns and design system
5
5
  */
6
6
 
7
- import React, { useState, useCallback } from 'react';
7
+ import React, { useCallback } from 'react';
8
8
  import { useTranslation } from 'react-i18next';
9
- import cx from 'classnames';
10
9
  import { Button, Dropdown } from '@memori.ai/ui';
11
10
  import { ArtifactData } from '../../types/artifact.types';
12
11
  import {
13
- Download,
14
12
  Link as LinkIcon,
15
- Maximize,
16
- Minimize,
17
13
  Printer,
18
14
  MoreVertical,
19
15
  } from 'lucide-react';
@@ -186,7 +182,7 @@ const ArtifactActions: React.FC<{
186
182
  loading={loading}
187
183
  className="memori-artifact-action-btn"
188
184
  />
189
- {isMobile && (
185
+ {isMobile && (
190
186
  <Dropdown className="memori-copy-menu-wrapper">
191
187
  <Dropdown.Trigger
192
188
  showChevron={false}
@@ -202,33 +198,23 @@ const ArtifactActions: React.FC<{
202
198
  </Button>
203
199
  )}
204
200
  />
205
- <Dropdown.Menu className="memori-copy-dropdown" style={{ minWidth: '200px' }}>
206
- <div className="memori-copy-dropdown-list">
207
- <Button
208
- onClick={handlePrint}
209
- disabled={loading}
210
- className="memori-artifact-action-btn memori-artifact-action-btn--print"
211
- variant="ghost"
212
- icon={<Printer className="memori-artifact-action-icon" />}
213
- title={t('artifact.print') || 'Print'}
214
- >
215
- <span className="memori-artifact-action-text">
216
- {t('artifact.print') || 'Print'}
217
- </span>
218
- </Button>
219
- <Button
220
- onClick={handleOpenExternal}
221
- disabled={loading}
222
- className="memori-artifact-action-btn memori-artifact-action-btn--external"
223
- variant="ghost"
224
- icon={<LinkIcon className="memori-artifact-action-icon" />}
225
- title={t('artifact.external') || 'External'}
226
- >
227
- <span className="memori-artifact-action-text">
228
- {t('artifact.external') || 'External'}
229
- </span>
230
- </Button>
231
- </div>
201
+ <Dropdown.Menu placement="bottom" align="end" sideOffset={8}>
202
+ <Dropdown.Item
203
+ onClick={handlePrint}
204
+ disabled={loading}
205
+ icon={<Printer />}
206
+ label={t('artifact.print') || 'Print'}
207
+ >
208
+ {t('artifact.print') || 'Print'}
209
+ </Dropdown.Item>
210
+ <Dropdown.Item
211
+ onClick={handleOpenExternal}
212
+ disabled={loading}
213
+ icon={<LinkIcon />}
214
+ label={t('artifact.external') || 'External'}
215
+ >
216
+ {t('artifact.external') || 'External'}
217
+ </Dropdown.Item>
232
218
  </Dropdown.Menu>
233
219
  </Dropdown>
234
220
  )}
@@ -1,14 +1,13 @@
1
1
  /**
2
2
  * CopyButtonWithDropdown - Main component with dropdown menu
3
- * Similar to Claude's copy system with format-specific options using headless-ui
3
+ * Similar to Claude's copy system with format-specific options
4
4
  */
5
5
  /* eslint-disable react/prop-types -- props validated by CopyButtonWithDropdownProps (TypeScript) */
6
6
 
7
- import React, { useRef, useEffect, useCallback } from 'react';
7
+ import React, { useCallback } from 'react';
8
8
  import cx from 'classnames';
9
9
  import { CopyButtonWithDropdownProps, CopyFormat } from '../types';
10
10
  import { useCopyArtifact } from '../hooks/useCopyArtifact';
11
- import CopyMenuItem from './CopyMenuItem';
12
11
  import { Button, Dropdown } from '@memori.ai/ui';
13
12
  import {
14
13
  Copy,
@@ -22,8 +21,20 @@ import {
22
21
  import { useTranslation } from 'react-i18next';
23
22
  import { marked } from 'marked';
24
23
  import DOMPurify from 'dompurify';
25
- import { ArtifactData } from '../../../types/artifact.types';
26
24
 
25
+ const getCopyActionIcon = (action: CopyFormat['action']) => {
26
+ switch (action) {
27
+ case 'pdf':
28
+ case 'download':
29
+ return <Download />;
30
+ case 'print':
31
+ return <Printer />;
32
+ case 'link':
33
+ return <LinkIcon />;
34
+ default:
35
+ return <Copy />;
36
+ }
37
+ };
27
38
 
28
39
  const CopyButtonWithDropdown: React.FC<CopyButtonWithDropdownProps> = ({
29
40
  artifact,
@@ -412,47 +423,35 @@ const CopyButtonWithDropdown: React.FC<CopyButtonWithDropdownProps> = ({
412
423
  </Button>
413
424
  )}
414
425
  />
415
- <Dropdown.Menu className="memori-copy-dropdown">
416
- <div className="memori-copy-dropdown-content">
417
- <div className="memori-copy-dropdown-list">
418
- {formats.map(format => (
419
- <Dropdown.Item key={format.id}>
420
- <CopyMenuItem
421
- format={format}
422
- onClick={handleFormatSelect}
423
- loading={copyState.loading}
424
- active={false}
425
- />
426
- </Dropdown.Item>
427
- ))}
428
- <Dropdown.Item>
429
- <CopyMenuItem
430
- format={{
431
- id: 'external',
432
- label: t('artifact.external') || 'External',
433
- action: 'link',
434
- mimeType: artifact.mimeType,
435
- }}
436
- onClick={handleOpenExternal}
437
- loading={copyState.loading}
438
- active={false}
439
- />
440
- </Dropdown.Item>
441
- <Dropdown.Item>
442
- <CopyMenuItem
443
- format={{
444
- id: 'print',
445
- label: t('artifact.print') || 'Print',
446
- action: 'print',
447
- mimeType: artifact.mimeType,
448
- }}
449
- onClick={handlePrint}
450
- loading={copyState.loading}
451
- active={false}
452
- />
453
- </Dropdown.Item>
454
- </div>
455
- </div>
426
+ <Dropdown.Menu placement="bottom" align="end" sideOffset={8}>
427
+ {formats.map(format => (
428
+ <Dropdown.Item
429
+ key={format.id}
430
+ onClick={() => handleFormatSelect(format)}
431
+ disabled={copyState.loading}
432
+ icon={getCopyActionIcon(format.action)}
433
+ label={format.label}
434
+ >
435
+ {format.label}
436
+ </Dropdown.Item>
437
+ ))}
438
+ <Dropdown.Separator />
439
+ <Dropdown.Item
440
+ onClick={handleOpenExternal}
441
+ disabled={copyState.loading}
442
+ icon={getCopyActionIcon('link')}
443
+ label={t('artifact.external') || 'External'}
444
+ >
445
+ {t('artifact.external') || 'External'}
446
+ </Dropdown.Item>
447
+ <Dropdown.Item
448
+ onClick={handlePrint}
449
+ disabled={copyState.loading}
450
+ icon={getCopyActionIcon('print')}
451
+ label={t('artifact.print') || 'Print'}
452
+ >
453
+ {t('artifact.print') || 'Print'}
454
+ </Dropdown.Item>
456
455
  </Dropdown.Menu>
457
456
  </Dropdown>
458
457
  )}
@@ -175,7 +175,7 @@
175
175
  /* Copy Menu Wrapper */
176
176
  .memori-copy-menu-wrapper {
177
177
  position: relative;
178
- z-index: 10001;
178
+ z-index: 10;
179
179
  display: inline-block;
180
180
  }
181
181
 
@@ -183,96 +183,6 @@
183
183
  gap: var(--memori-spacing-sm);
184
184
  }
185
185
 
186
- /* Copy Dropdown */
187
- .memori-copy-dropdown {
188
- position: absolute;
189
- z-index: 10001;
190
- top: 100%;
191
- right: 0;
192
- /* left: 0; */
193
- overflow: hidden;
194
- min-width: 280px;
195
- max-width: 320px;
196
- border: 1px solid var(--memori-copy-border);
197
- border: var(--memori-border) solid var(--memori-border-color);
198
- border-radius: 0.5rem;
199
- margin-top: var(--memori-spacing-xs);
200
- background: var(--memori-secondary-background);
201
- box-shadow: var(--memori-copy-shadow);
202
- }
203
-
204
- /* Responsive positioning */
205
- @media (max-width: 640px) {
206
- .memori-copy-dropdown {
207
- right: 0;
208
- left: auto;
209
- min-width: 260px;
210
- max-width: calc(100vw - var(--memori-spacing-xl));
211
- }
212
- }
213
-
214
- /* Headless UI Transition Classes */
215
- .memori-copy-dropdown-enter {
216
- transition: all 0.15s ease-out;
217
- }
218
-
219
- .memori-copy-dropdown-enter-from {
220
- opacity: 0;
221
- transform: translateY(-8px) scale(0.95);
222
- }
223
-
224
- .memori-copy-dropdown-enter-to {
225
- opacity: 1;
226
- transform: translateY(0) scale(1);
227
- }
228
-
229
- .memori-copy-dropdown-leave {
230
- transition: all 0.1s ease-in;
231
- }
232
-
233
- .memori-copy-dropdown-leave-from {
234
- opacity: 1;
235
- transform: translateY(0) scale(1);
236
- }
237
-
238
- .memori-copy-dropdown-leave-to {
239
- opacity: 0;
240
- transform: translateY(-8px) scale(0.95);
241
- }
242
-
243
- .memori-copy-dropdown-content {
244
- padding: var(--memori-spacing-sm) 0;
245
- }
246
-
247
- .memori-copy-dropdown-header {
248
- padding: var(--memori-spacing-sm) var(--memori-spacing-md) var(--memori-spacing-xs);
249
- border-bottom: 1px solid var(--memori-copy-border);
250
- margin-bottom: var(--memori-spacing-xs);
251
- }
252
-
253
- .memori-copy-dropdown-title {
254
- color: var(--memori-text-color);
255
- font-size: 0.75rem;
256
- font-weight: var(--memori-text-weight-semibold);
257
- letter-spacing: 0.05em;
258
- text-transform: uppercase;
259
- }
260
-
261
- .memori-copy-dropdown-list {
262
- max-height: 300px;
263
- overflow-y: auto;
264
- }
265
-
266
- .memori-copy-dropdown-empty {
267
- padding: var(--memori-spacing-md);
268
- text-align: center;
269
- }
270
-
271
- .memori-copy-dropdown-empty-text {
272
- color: var(--memori-text-color);
273
- font-size: var(--memori-text-size-small);
274
- }
275
-
276
186
  /* Copy Menu Item */
277
187
  .memori-copy-menu-item {
278
188
  position: relative;
@@ -441,11 +351,6 @@
441
351
 
442
352
  /* Responsive Design */
443
353
  @media (max-width: 640px) {
444
- .memori-copy-dropdown {
445
- min-width: 260px;
446
- max-width: calc(100vw - var(--memori-spacing-xl));
447
- }
448
-
449
354
  .memori-copy-toast {
450
355
  right: var(--memori-spacing-md);
451
356
  left: var(--memori-spacing-md);
@@ -468,7 +373,6 @@
468
373
  /* Print Media Queries */
469
374
  @media print {
470
375
  .memori-copy-button-wrapper,
471
- .memori-copy-dropdown,
472
376
  .memori-copy-toast {
473
377
  display: none !important;
474
378
  }
@@ -480,10 +384,6 @@
480
384
  border-width: 2px;
481
385
  }
482
386
 
483
- .memori-copy-dropdown {
484
- border-width: 2px;
485
- }
486
-
487
387
  .memori-copy-menu-item:hover:not(:disabled) {
488
388
  background: var(--memori-copy-surface-pressed);
489
389
  color: var(--memori-text-color);
@@ -494,7 +394,6 @@
494
394
  @media (prefers-reduced-motion: reduce) {
495
395
  .memori-copy-button,
496
396
  .memori-copy-menu-item,
497
- .memori-copy-dropdown,
498
397
  .memori-copy-toast {
499
398
  transition: none;
500
399
  }
@@ -504,10 +403,6 @@
504
403
  animation: none;
505
404
  }
506
405
 
507
- .memori-copy-dropdown {
508
- animation: none;
509
- }
510
-
511
406
  .memori-copy-toast {
512
407
  animation: none;
513
408
  }