@memori.ai/memori-react 8.18.2 → 8.19.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.
Files changed (48) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +2 -0
  3. package/dist/components/Chat/Chat.d.ts +2 -0
  4. package/dist/components/Chat/Chat.js +2 -2
  5. package/dist/components/Chat/Chat.js.map +1 -1
  6. package/dist/components/ChatInputs/ChatInputs.d.ts +2 -0
  7. package/dist/components/ChatInputs/ChatInputs.js +5 -3
  8. package/dist/components/ChatInputs/ChatInputs.js.map +1 -1
  9. package/dist/components/ChatTextArea/ChatTextArea.css +19 -1
  10. package/dist/components/ChatTextArea/ChatTextArea.d.ts +1 -0
  11. package/dist/components/ChatTextArea/ChatTextArea.js +46 -27
  12. package/dist/components/ChatTextArea/ChatTextArea.js.map +1 -1
  13. package/dist/components/MemoriWidget/MemoriWidget.d.ts +3 -1
  14. package/dist/components/MemoriWidget/MemoriWidget.js +3 -1
  15. package/dist/components/MemoriWidget/MemoriWidget.js.map +1 -1
  16. package/dist/index.d.ts +2 -0
  17. package/dist/index.js +4 -2
  18. package/dist/index.js.map +1 -1
  19. package/dist/version.d.ts +1 -1
  20. package/dist/version.js +1 -1
  21. package/esm/components/Chat/Chat.d.ts +2 -0
  22. package/esm/components/Chat/Chat.js +2 -2
  23. package/esm/components/Chat/Chat.js.map +1 -1
  24. package/esm/components/ChatInputs/ChatInputs.d.ts +2 -0
  25. package/esm/components/ChatInputs/ChatInputs.js +5 -3
  26. package/esm/components/ChatInputs/ChatInputs.js.map +1 -1
  27. package/esm/components/ChatTextArea/ChatTextArea.css +19 -1
  28. package/esm/components/ChatTextArea/ChatTextArea.d.ts +1 -0
  29. package/esm/components/ChatTextArea/ChatTextArea.js +47 -28
  30. package/esm/components/ChatTextArea/ChatTextArea.js.map +1 -1
  31. package/esm/components/MemoriWidget/MemoriWidget.d.ts +3 -1
  32. package/esm/components/MemoriWidget/MemoriWidget.js +3 -1
  33. package/esm/components/MemoriWidget/MemoriWidget.js.map +1 -1
  34. package/esm/index.d.ts +2 -0
  35. package/esm/index.js +4 -2
  36. package/esm/index.js.map +1 -1
  37. package/esm/version.d.ts +1 -1
  38. package/esm/version.js +1 -1
  39. package/package.json +1 -1
  40. package/src/components/Chat/Chat.tsx +8 -0
  41. package/src/components/ChatInputs/ChatInputs.tsx +9 -1
  42. package/src/components/ChatTextArea/ChatTextArea.css +19 -1
  43. package/src/components/ChatTextArea/ChatTextArea.tsx +38 -7
  44. package/src/components/MemoriWidget/MemoriWidget.tsx +8 -0
  45. package/src/components/layouts/layouts.stories.tsx +1 -0
  46. package/src/index.stories.tsx +15 -0
  47. package/src/index.tsx +11 -1
  48. package/src/version.ts +1 -1
@@ -15,6 +15,8 @@ export interface Props {
15
15
  onFocus?: (e: React.FocusEvent) => void;
16
16
  onBlur?: (e: React.FocusEvent) => void;
17
17
  onExpandedChange?: (expanded: boolean) => void;
18
+ /** When set, shows a character counter (e.g. "0 / 500") above the textarea and enforces the max length. */
19
+ maxTextareaCharacters?: number;
18
20
  }
19
21
 
20
22
  const ChatTextArea: React.FC<Props> = ({
@@ -26,6 +28,7 @@ const ChatTextArea: React.FC<Props> = ({
26
28
  onFocus,
27
29
  onBlur,
28
30
  onExpandedChange,
31
+ maxTextareaCharacters,
29
32
  }) => {
30
33
  const { t } = useTranslation();
31
34
  const textareaRef = useRef<HTMLTextAreaElement>(null);
@@ -78,22 +81,48 @@ const ChatTextArea: React.FC<Props> = ({
78
81
  }
79
82
  }, [value]);
80
83
 
84
+ const displayValue =
85
+ maxTextareaCharacters != null
86
+ ? value.slice(0, maxTextareaCharacters)
87
+ : value;
88
+
89
+ // Keep parent state in sync when value exceeds limit (e.g. paste or prop change)
90
+ useEffect(() => {
91
+ if (
92
+ maxTextareaCharacters != null &&
93
+ value.length > maxTextareaCharacters
94
+ ) {
95
+ onChange(value.slice(0, maxTextareaCharacters));
96
+ }
97
+ }, [maxTextareaCharacters, value, onChange]);
98
+
81
99
  return (
82
100
  <div
83
101
  data-testid="chat-textarea"
84
102
  className={cx('memori-chat-textarea', {
85
103
  'memori-chat-textarea--disabled': disabled,
104
+ 'memori-chat-textarea--with-counter': maxTextareaCharacters != null,
86
105
  })}
87
106
  >
107
+ {maxTextareaCharacters != null && (
108
+ <div className="memori-chat-textarea--counter" aria-live="polite">
109
+ {displayValue.length} / {maxTextareaCharacters}
110
+ </div>
111
+ )}
88
112
  <div ref={innerRef} className="memori-chat-textarea--inner">
89
113
  <textarea
90
114
  ref={textareaRef}
91
115
  className="memori-chat-textarea--input"
92
116
  disabled={disabled}
93
- value={value}
117
+ value={displayValue}
94
118
  placeholder={t('placeholder', 'Ask a question') || 'Ask a question'}
95
119
  onChange={e => {
96
- onChange(e.target.value);
120
+ const next = e.target.value;
121
+ if (maxTextareaCharacters != null) {
122
+ onChange(next.slice(0, maxTextareaCharacters));
123
+ } else {
124
+ onChange(next);
125
+ }
97
126
  }}
98
127
  onKeyDownCapture={e => {
99
128
  // On mobile/tablet only: Enter creates a new line instead of sending.
@@ -106,10 +135,12 @@ const ChatTextArea: React.FC<Props> = ({
106
135
  e.preventDefault();
107
136
 
108
137
  const el = textareaRef.current;
109
- const start = el?.selectionStart ?? value.length;
110
- const end = el?.selectionEnd ?? value.length;
111
- const nextValue = `${value.slice(0, start)}\n${value.slice(end)}`;
112
-
138
+ const start = el?.selectionStart ?? displayValue.length;
139
+ const end = el?.selectionEnd ?? displayValue.length;
140
+ let nextValue = `${displayValue.slice(0, start)}\n${displayValue.slice(end)}`;
141
+ if (maxTextareaCharacters != null) {
142
+ nextValue = nextValue.slice(0, maxTextareaCharacters);
143
+ }
113
144
  onChange(nextValue);
114
145
 
115
146
  // Restore caret right after the inserted newline
@@ -130,7 +161,7 @@ const ChatTextArea: React.FC<Props> = ({
130
161
  onPaste={onPaste}
131
162
  onFocus={onFocus}
132
163
  onBlur={onBlur}
133
- maxLength={100000}
164
+ maxLength={maxTextareaCharacters ?? 100000}
134
165
  />
135
166
  </div>
136
167
  </div>
@@ -435,6 +435,10 @@ export interface Props {
435
435
  __WEBCOMPONENT__?: boolean;
436
436
  /** Override total document payload and per-document content limit (character count). Default from constants. */
437
437
  maxTotalMessagePayload?: number;
438
+ /** When true, pasted text is not added as a document attachment (normal paste only). Default false. */
439
+ disablePastedText?: boolean;
440
+ /** Max characters in chat textarea; shows counter and disables paste-as-attachment when set. */
441
+ maxTextareaCharacters?: number;
438
442
  }
439
443
 
440
444
  const MemoriWidget = ({
@@ -491,6 +495,8 @@ const MemoriWidget = ({
491
495
  applyVarsToRoot = false,
492
496
  showFunctionCache = false,
493
497
  maxTotalMessagePayload,
498
+ disablePastedText = false,
499
+ maxTextareaCharacters,
494
500
  }: Props) => {
495
501
  const { t, i18n } = useTranslation();
496
502
 
@@ -3025,6 +3031,8 @@ const MemoriWidget = ({
3025
3031
  experts,
3026
3032
  useMathFormatting: applyMathFormatting,
3027
3033
  maxTotalMessagePayload,
3034
+ disablePastedText,
3035
+ maxTextareaCharacters,
3028
3036
  };
3029
3037
 
3030
3038
  const integrationBackground =
@@ -167,6 +167,7 @@ WebsiteAssistant3.args = {
167
167
  showOnlyLastMessages: false,
168
168
  showTranslationOriginal: false,
169
169
  showCopyButton: false,
170
+ disablePastedText: true,
170
171
  };
171
172
 
172
173
 
@@ -101,6 +101,21 @@ WithUploadWithMaxTotalMessagePayload.args = {
101
101
  maxTotalMessagePayload: 300000,
102
102
  };
103
103
 
104
+ export const WithMaxTextareaCharacters = Template.bind({});
105
+ WithMaxTextareaCharacters.args = {
106
+ ownerUserName: 'nzambello',
107
+ memoriName: 'Nicola',
108
+ tenantID: 'www.aisuru.com',
109
+ engineURL: 'https://engine.memori.ai',
110
+ apiURL: 'https://backend.memori.ai',
111
+ baseURL: 'https://www.aisuru.com',
112
+ uiLang: 'IT',
113
+ spokenLang: 'IT',
114
+ enableAudio: true,
115
+ showUpload: true,
116
+ maxTextareaCharacters: 500,
117
+ };
118
+
104
119
  export const WithPrivateAgent = Template.bind({});
105
120
  WithPrivateAgent.args = {
106
121
  memoriName: 'Test Private',
package/src/index.tsx CHANGED
@@ -48,7 +48,7 @@ export interface Props {
48
48
  __WEBCOMPONENT__?: boolean;
49
49
  showClear?: boolean;
50
50
  showOnlyLastMessages?: boolean;
51
- showTypingText?: boolean;
51
+ showTypingText?: boolean;
52
52
  showLogin?: boolean;
53
53
  showUpload?: boolean;
54
54
  showReasoning?: boolean;
@@ -77,6 +77,10 @@ export interface Props {
77
77
  applyVarsToRoot?: boolean;
78
78
  /** Override total document payload and per-document content limit (character count). Default from constants (200000). */
79
79
  maxTotalMessagePayload?: number;
80
+ /** When true, pasted text is not added as a document attachment (normal paste only). Default false. */
81
+ disablePastedText?: boolean;
82
+ /** Max characters allowed in the chat textarea. When set, shows a counter (e.g. "0 / 500") and disables paste-as-attachment by default. */
83
+ maxTextareaCharacters?: number;
80
84
  }
81
85
 
82
86
  const getPreferredLanguages = () => {
@@ -156,6 +160,8 @@ const Memori: React.FC<Props> = ({
156
160
  applyVarsToRoot = false,
157
161
  __WEBCOMPONENT__ = false,
158
162
  maxTotalMessagePayload,
163
+ disablePastedText = false,
164
+ maxTextareaCharacters,
159
165
  }) => {
160
166
  const [memori, setMemori] = useState<IMemori>();
161
167
  const [tenant, setTenant] = useState<Tenant>();
@@ -469,6 +475,8 @@ const Memori: React.FC<Props> = ({
469
475
  userAvatar={userAvatar}
470
476
  applyVarsToRoot={applyVarsToRoot}
471
477
  maxTotalMessagePayload={maxTotalMessagePayload}
478
+ disablePastedText={disablePastedText ?? (maxTextareaCharacters != null)}
479
+ maxTextareaCharacters={maxTextareaCharacters}
472
480
  disableTextEnteredEvents={disableTextEnteredEvents}
473
481
  // From layout, from client if allowed
474
482
  {...clientAttributes}
@@ -570,5 +578,7 @@ Memori.propTypes = {
570
578
  autoStart: PropTypes.bool,
571
579
  applyVarsToRoot: PropTypes.bool,
572
580
  maxTotalMessagePayload: PropTypes.number,
581
+ disablePastedText: PropTypes.bool,
582
+ maxTextareaCharacters: PropTypes.number,
573
583
  };
574
584
  export default Memori;
package/src/version.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  // This file is auto-generated. Do not edit manually.
2
- export const version = '8.18.2';
2
+ export const version = '8.19.0';