react-mention-input 1.1.21 → 1.1.23

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/demo.tsx CHANGED
@@ -6,20 +6,22 @@ const Demo: React.FC = () => {
6
6
  {
7
7
  id: 1,
8
8
  name: 'John Doe',
9
- date: '2 hours ago',
9
+ date: '14/07/2025 04:15 PM',
10
10
  comment: 'Updated the status to Draft. Need <span class="mention-highlight">@team-leads</span> review before proceeding. <span class="hashtag-highlight">#urgent</span> <span class="hashtag-highlight">#review</span>',
11
11
  objectName: '26may_item001',
12
12
  revision: 'A',
13
13
  object_type_icon: '📄',
14
+ relatedObject: 'test_jeet_july2334 (A)',
14
15
  },
15
16
  {
16
17
  id: 2,
17
18
  name: 'Mike Johnson',
18
- date: '1 day ago',
19
+ date: '14/07/2025 04:15 PM',
19
20
  comment: 'Revision A completed successfully. Ready for next phase. <span class="hashtag-highlight">#milestone</span>',
20
21
  objectName: '26may_item001',
21
22
  revision: 'A',
22
23
  object_type_icon: '📋',
24
+ relatedObject: 'test_jeet_july2334 (A)',
23
25
  }
24
26
  ]);
25
27
 
@@ -55,6 +57,7 @@ const Demo: React.FC = () => {
55
57
  objectName: 'new_item001', // You can customize this or make it dynamic
56
58
  revision: 'A', // You can customize this or make it dynamic
57
59
  object_type_icon: '✨', // You can customize this or make it dynamic
60
+ relatedObject: 'test_jeet_july2334 (A)', // You can customize this or make it dynamic
58
61
  };
59
62
 
60
63
  setMessages([...messages, newMessage]);
@@ -79,7 +82,7 @@ const Demo: React.FC = () => {
79
82
  <div style={{ marginBottom: '20px' }}>
80
83
  <MentionInput
81
84
  users={users}
82
- placeholder="Type a message with @mentions and #hashtags..."
85
+ placeholder="Type @ to mention and inform someone"
83
86
  onSendMessage={handleSendMessage}
84
87
  suggestionPosition="bottom"
85
88
  />
@@ -152,6 +155,7 @@ const Demo: React.FC = () => {
152
155
  objectName: '26may_item001',
153
156
  revision: 'A',
154
157
  object_type_icon: '📄', // Document icon
158
+ relatedObject: 'test_jeet_july2334 (A)', // Related object
155
159
  comment: 'Message content...'
156
160
  };`}
157
161
  </pre>
@@ -1,5 +1,5 @@
1
1
  .mention-container {
2
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
2
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
3
3
  line-height: 1.5;
4
4
  color: #333;
5
5
  width: 100%;
@@ -56,7 +56,7 @@
56
56
  .placeholder {
57
57
  position: absolute;
58
58
  color: #999;
59
- font-size: 14px;
59
+ font-size: 13px;
60
60
  pointer-events: none;
61
61
  left: 0;
62
62
  top: 50%;
@@ -70,7 +70,7 @@
70
70
  .mention-input {
71
71
  outline: none;
72
72
  padding: 6px 0;
73
- font-size: 14px;
73
+ font-size: 13px;
74
74
  min-height: 24px;
75
75
  max-height: 120px;
76
76
  overflow-y: auto;
@@ -112,16 +112,16 @@
112
112
  width: 36px;
113
113
  height: 36px;
114
114
  border-radius: 50%;
115
- background-color: #1a1a1a;
115
+ background-color: #23488C;
116
116
  color: white;
117
117
  border: none;
118
118
  cursor: pointer;
119
- font-size: 14px;
119
+ font-size: 24px;
120
120
  transition: background-color 0.2s;
121
121
  }
122
122
 
123
123
  .send-button:hover {
124
- background-color: #333;
124
+ background-color: #1a3a7a;
125
125
  }
126
126
 
127
127
  /* Suggestion list with proper columnar layout */
@@ -367,7 +367,7 @@ var MentionInput = function (_a) {
367
367
  React.createElement("div", { className: "mention-input-wrapper" },
368
368
  (!inputValue || !inputRef.current || ((_b = inputRef.current) === null || _b === void 0 ? void 0 : _b.innerText.trim()) === "") && (React.createElement("span", { className: "placeholder" }, placeholder)),
369
369
  React.createElement("div", { ref: inputRef, contentEditable: true, suppressContentEditableWarning: true, className: "mention-input ".concat(inputClassName || ""), onInput: handleInputChange, onKeyDown: handleKeyDown, onFocus: function () { return document.execCommand('styleWithCSS', false, 'false'); } })),
370
- React.createElement("button", { onClick: handleSendMessage, className: "send-button ".concat(sendBtnClassName || ""), "aria-label": "Send message" }, sendButtonIcon || ""),
370
+ React.createElement("button", { onClick: handleSendMessage, className: "send-button ".concat(sendBtnClassName || ""), "aria-label": "Send message" }, sendButtonIcon || ""),
371
371
  React.createElement("input", { type: "file", ref: fileInputRef, accept: "image/*", onChange: handleImageSelect, style: { display: 'none' } }),
372
372
  isUploading && (React.createElement("div", { className: "upload-loading" },
373
373
  React.createElement("span", null, "Uploading...")))),
@@ -2,6 +2,13 @@
2
2
  display: flex;
3
3
  flex-direction: column;
4
4
  gap: 16px; /* Space between cards */
5
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
6
+ }
7
+
8
+ .message-card-wrapper {
9
+ display: flex;
10
+ flex-direction: column;
11
+ gap: 8px; /* Space between header and card */
5
12
  }
6
13
 
7
14
  .message-card {
@@ -12,6 +19,7 @@
12
19
  padding: 16px;
13
20
  background-color: #fff;
14
21
  transition: box-shadow 0.2s;
22
+ margin-left: 36px; /* Indent to align with header content */
15
23
  }
16
24
 
17
25
  .message-card:hover {
@@ -22,7 +30,7 @@
22
30
  display: flex;
23
31
  align-items: center;
24
32
  justify-content: space-between;
25
- margin-bottom: 8px; /* Space between header and body */
33
+ margin-bottom: 0; /* No margin since header is outside */
26
34
  }
27
35
 
28
36
  .message-card-header-left {
@@ -61,46 +69,47 @@
61
69
 
62
70
  .message-card-img,
63
71
  .message-card-initials {
64
- width: 48px;
65
- height: 48px;
72
+ width: 28px;
73
+ height: 28px;
66
74
  border-radius: 50%;
67
75
  display: flex;
68
76
  align-items: center;
69
77
  justify-content: center;
70
- font-size: 16px;
78
+ font-size: 12px;
71
79
  font-weight: bold;
72
80
  color: #fff;
73
81
  background-color: #007bff;
74
82
  text-transform: uppercase;
75
- margin-right: 16px;
83
+ margin-right: 8px;
76
84
  }
77
85
  .message-card-info {
78
86
  display: flex;
79
- flex-direction: column;
87
+ align-items: center;
80
88
  }
81
89
 
82
90
  .message-card-name {
83
91
  margin: 0;
84
- font-size: 18px;
85
- font-weight: bold;
86
- line-height: 1.2; /* Adjust line height for better spacing */
92
+ font-size: 14px;
93
+ font-weight: 600;
94
+ line-height: 1.2;
95
+ margin-right: 8px;
87
96
  }
88
97
 
89
98
  .message-card-date {
90
99
  margin: 0;
91
- font-size: 14px;
92
- color: #888;
93
- line-height: 1.2; /* Adjust line height for better spacing */
100
+ font-size: 12px;
101
+ color: #888888;
102
+ line-height: 1.2;
94
103
  }
95
104
 
96
105
  .message-card-body {
97
- margin-top: 8px; /* Space between header and comment */
106
+ margin-top: 0; /* No margin since body is in the card */
98
107
  }
99
108
 
100
109
  .message-card-comment {
101
110
  margin: 0;
102
- font-size: 16px;
103
- line-height: 1.5; /* Optimal line height for readability */
111
+ font-size: 13px;
112
+ line-height: 1.5;
104
113
  }
105
114
  .mention-highlight {
106
115
  background-color: #e0f7fa;
@@ -126,8 +135,8 @@
126
135
  }
127
136
 
128
137
  .tag-chip {
129
- padding: 6px 12px;
130
- border-radius: 16px;
138
+ padding: 4px 8px;
139
+ border-radius: 4px;
131
140
  font-size: 12px;
132
141
  font-weight: 500;
133
142
  border: none;
@@ -136,11 +145,36 @@
136
145
  }
137
146
 
138
147
  .hashtag-chip {
139
- background-color: #D4A574;
140
- color: #FFFFFF;
148
+ background-color: rgba(255, 165, 0, 0.15);
149
+ color: #FF8C00;
141
150
  }
142
151
 
143
152
  .mention-chip {
144
- background-color: #2684FF;
145
- color: #FFFFFF;
153
+ background-color: #E0F7FA;
154
+ color: #007BFF;
155
+ }
156
+
157
+ /* Related object styling */
158
+ .message-card-related {
159
+ display: flex;
160
+ align-items: center;
161
+ margin-top: 8px;
162
+ }
163
+
164
+ .related-label {
165
+ font-size: 13px;
166
+ color: #333;
167
+ margin-right: 8px;
168
+ }
169
+
170
+ .related-object-chip {
171
+ background-color: #f0f0f0;
172
+ color: #666;
173
+ padding: 2px 6px;
174
+ border-radius: 4px;
175
+ font-size: 12px;
176
+ height: 20px;
177
+ display: flex;
178
+ align-items: center;
179
+ border: 1px solid #ddd;
146
180
  }
@@ -13,6 +13,7 @@ interface ShowMessageCardProps {
13
13
  objectNameKey?: string;
14
14
  revisionKey?: string;
15
15
  objectTypeIconKey?: string;
16
+ relatedObjectKey?: string;
16
17
  containerClassName?: string;
17
18
  containerStyle?: CSSProperties;
18
19
  cardClassName?: string;
@@ -9,6 +9,15 @@ var __assign = (this && this.__assign) || function () {
9
9
  };
10
10
  return __assign.apply(this, arguments);
11
11
  };
12
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
13
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
14
+ if (ar || !(i in from)) {
15
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
16
+ ar[i] = from[i];
17
+ }
18
+ }
19
+ return to.concat(ar || Array.prototype.slice.call(from));
20
+ };
12
21
  import React, { useState } from "react";
13
22
  import "./ShowMessageCard.css";
14
23
  export var ShowMessageCard = function (_a) {
@@ -19,10 +28,12 @@ export var ShowMessageCard = function (_a) {
19
28
  revisionKey = _h === void 0 ? "revision" : _h, // Default key for revision
20
29
  _j = _a.objectTypeIconKey, // Default key for revision
21
30
  objectTypeIconKey = _j === void 0 ? "object_type_icon" : _j, // Default key for object type icon
31
+ _k = _a.relatedObjectKey, // Default key for object type icon
32
+ relatedObjectKey = _k === void 0 ? "relatedObject" : _k, // Default key for related object
22
33
  containerClassName = _a.containerClassName, containerStyle = _a.containerStyle, cardClassName = _a.cardClassName, cardStyle = _a.cardStyle, headerClassName = _a.headerClassName, headerStyle = _a.headerStyle, imgClassName = _a.imgClassName, imgStyle = _a.imgStyle, infoClassName = _a.infoClassName, infoStyle = _a.infoStyle, nameClassName = _a.nameClassName, nameStyle = _a.nameStyle, dateClassName = _a.dateClassName, dateStyle = _a.dateStyle, bodyClassName = _a.bodyClassName, bodyStyle = _a.bodyStyle, commentClassName = _a.commentClassName, commentStyle = _a.commentStyle, attachedImageClassName = _a.attachedImageClassName, attachedImageStyle = _a.attachedImageStyle, attachedImageContainerClassName = _a.attachedImageContainerClassName, attachedImageContainerStyle = _a.attachedImageContainerStyle, objectNameClassName = _a.objectNameClassName, objectNameStyle = _a.objectNameStyle, revisionClassName = _a.revisionClassName, revisionStyle = _a.revisionStyle, objectChipRender = _a.objectChipRender, // Custom render function for object chip
23
34
  renderItem = _a.renderItem;
24
35
  // State to manage initials for images that fail to load
25
- var _k = useState({}), initialsState = _k[0], setInitialsState = _k[1];
36
+ var _l = useState({}), initialsState = _l[0], setInitialsState = _l[1];
26
37
  // Handle image load failure
27
38
  var handleImageError = function (id) {
28
39
  setInitialsState(function (prevState) {
@@ -41,12 +52,25 @@ export var ShowMessageCard = function (_a) {
41
52
  };
42
53
  // Helper function to extract hashtags and mentions from text
43
54
  var extractTagsAndMentions = function (text) {
44
- var plainText = text.replace(/<[^>]*>/g, ''); // Remove HTML tags to get plain text
45
- var hashtags = plainText.match(/#[\w]+/g) || [];
46
- var mentions = plainText.match(/@[\w\s-]+/g) || [];
55
+ // First extract from HTML with spans
56
+ var hashtagsFromHTML = text.match(/<span[^>]*class="hashtag-highlight"[^>]*>(#[\w]+)<\/span>/g) || [];
57
+ var mentionsFromHTML = text.match(/<span[^>]*class="mention-highlight"[^>]*>(@[^<]+)<\/span>/g) || [];
58
+ // Extract the actual text content from HTML
59
+ var hashtags = hashtagsFromHTML.map(function (match) {
60
+ var textMatch = match.match(/>(#[\w]+)</);
61
+ return textMatch ? textMatch[1] : '';
62
+ }).filter(function (tag) { return tag; });
63
+ var mentions = mentionsFromHTML.map(function (match) {
64
+ var textMatch = match.match(/>(@[^<]+)</);
65
+ return textMatch ? textMatch[1].trim() : '';
66
+ }).filter(function (mention) { return mention; });
67
+ // Also check plain text for any missed items
68
+ var plainText = text.replace(/<[^>]*>/g, '');
69
+ var plainHashtags = plainText.match(/#[\w]+/g) || [];
70
+ var plainMentions = plainText.match(/@[\w\s-]+/g) || [];
47
71
  return {
48
- hashtags: Array.from(new Set(hashtags)), // Remove duplicates
49
- mentions: Array.from(new Set(mentions.map(function (mention) { return mention.trim(); }))) // Remove duplicates and trim
72
+ hashtags: Array.from(new Set(__spreadArray(__spreadArray([], hashtags, true), plainHashtags, true))), // Remove duplicates
73
+ mentions: Array.from(new Set(__spreadArray(__spreadArray([], mentions, true), plainMentions.map(function (mention) { return mention.trim(); }), true))) // Remove duplicates and trim
50
74
  };
51
75
  };
52
76
  return (React.createElement("div", { className: "message-card-container ".concat(containerClassName || ""), style: containerStyle }, data.map(function (item, index) {
@@ -57,7 +81,7 @@ export var ShowMessageCard = function (_a) {
57
81
  var showInitials = initialsState[item.id || index] || !item[imgSrcKey]; // Decide whether to show initials
58
82
  // Extract tags and mentions from the comment
59
83
  var _a = extractTagsAndMentions(item[commentKey] || ''), hashtags = _a.hashtags, mentions = _a.mentions;
60
- return (React.createElement("div", { key: item.id || index, className: "message-card ".concat(cardClassName || ""), style: cardStyle },
84
+ return (React.createElement("div", { key: item.id || index, className: "message-card-wrapper" },
61
85
  React.createElement("div", { className: "message-card-header ".concat(headerClassName || ""), style: headerStyle },
62
86
  React.createElement("div", { className: "message-card-header-left" },
63
87
  showInitials ? (React.createElement("div", { className: "message-card-initials ".concat(imgClassName || ""), style: imgStyle }, getInitials(item[nameKey]))) : (React.createElement("img", { src: item[imgSrcKey], alt: item[nameKey], className: "message-card-img ".concat(imgClassName || ""), style: imgStyle, onError: function () { return handleImageError(item.id || index); } })),
@@ -73,12 +97,16 @@ export var ShowMessageCard = function (_a) {
73
97
  item[objectTypeIconKey] && (React.createElement("span", { className: "object-type-icon", style: { marginRight: '6px' } }, item[objectTypeIconKey])),
74
98
  item[objectNameKey] && (React.createElement("span", { className: "object-name-text" }, item[objectNameKey])),
75
99
  item[revisionKey] && (React.createElement("span", { className: "revision-text ".concat(revisionClassName || ""), style: revisionStyle }, item[objectNameKey] ? " (".concat(item[revisionKey], ")") : "(".concat(item[revisionKey], ")")))))))),
76
- React.createElement("div", { className: "message-card-body ".concat(bodyClassName || ""), style: bodyStyle },
77
- React.createElement("p", { className: "message-card-comment ".concat(commentClassName || ""), style: commentStyle, dangerouslySetInnerHTML: { __html: item[commentKey] } }),
78
- (item === null || item === void 0 ? void 0 : item[imageUrlKey]) && (React.createElement("div", { className: "message-card-attached-image-container ".concat(attachedImageContainerClassName || ""), style: attachedImageContainerStyle },
79
- React.createElement("img", { src: item[imageUrlKey], alt: "Attached", className: "message-card-attached-image ".concat(attachedImageClassName || ""), style: attachedImageStyle }))),
80
- (hashtags.length > 0 || mentions.length > 0) && (React.createElement("div", { className: "message-card-tags" },
81
- hashtags.map(function (tag, tagIndex) { return (React.createElement("span", { key: "hashtag-".concat(tagIndex), className: "tag-chip hashtag-chip" }, tag)); }),
82
- mentions.map(function (mention, mentionIndex) { return (React.createElement("span", { key: "mention-".concat(mentionIndex), className: "tag-chip mention-chip" }, mention)); }))))));
100
+ React.createElement("div", { className: "message-card ".concat(cardClassName || ""), style: cardStyle },
101
+ React.createElement("div", { className: "message-card-body ".concat(bodyClassName || ""), style: bodyStyle },
102
+ React.createElement("p", { className: "message-card-comment ".concat(commentClassName || ""), style: commentStyle, dangerouslySetInnerHTML: { __html: item[commentKey] } }),
103
+ (item === null || item === void 0 ? void 0 : item[imageUrlKey]) && (React.createElement("div", { className: "message-card-attached-image-container ".concat(attachedImageContainerClassName || ""), style: attachedImageContainerStyle },
104
+ React.createElement("img", { src: item[imageUrlKey], alt: "Attached", className: "message-card-attached-image ".concat(attachedImageClassName || ""), style: attachedImageStyle }))),
105
+ (hashtags.length > 0 || mentions.length > 0) && (React.createElement("div", { className: "message-card-tags" },
106
+ hashtags.map(function (tag, tagIndex) { return (React.createElement("span", { key: "hashtag-".concat(tagIndex), className: "tag-chip hashtag-chip" }, tag)); }),
107
+ mentions.map(function (mention, mentionIndex) { return (React.createElement("span", { key: "mention-".concat(mentionIndex), className: "tag-chip mention-chip" }, mention)); }))),
108
+ item[relatedObjectKey] && (React.createElement("div", { className: "message-card-related" },
109
+ React.createElement("span", { className: "related-label" }, "Related: "),
110
+ React.createElement("span", { className: "related-object-chip" }, item[relatedObjectKey])))))));
83
111
  })));
84
112
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-mention-input",
3
- "version": "1.1.21",
3
+ "version": "1.1.23",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "scripts": {
@@ -1,5 +1,5 @@
1
1
  .mention-container {
2
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
2
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
3
3
  line-height: 1.5;
4
4
  color: #333;
5
5
  width: 100%;
@@ -56,7 +56,7 @@
56
56
  .placeholder {
57
57
  position: absolute;
58
58
  color: #999;
59
- font-size: 14px;
59
+ font-size: 13px;
60
60
  pointer-events: none;
61
61
  left: 0;
62
62
  top: 50%;
@@ -70,7 +70,7 @@
70
70
  .mention-input {
71
71
  outline: none;
72
72
  padding: 6px 0;
73
- font-size: 14px;
73
+ font-size: 13px;
74
74
  min-height: 24px;
75
75
  max-height: 120px;
76
76
  overflow-y: auto;
@@ -112,16 +112,16 @@
112
112
  width: 36px;
113
113
  height: 36px;
114
114
  border-radius: 50%;
115
- background-color: #1a1a1a;
115
+ background-color: #23488C;
116
116
  color: white;
117
117
  border: none;
118
118
  cursor: pointer;
119
- font-size: 14px;
119
+ font-size: 24px;
120
120
  transition: background-color 0.2s;
121
121
  }
122
122
 
123
123
  .send-button:hover {
124
- background-color: #333;
124
+ background-color: #1a3a7a;
125
125
  }
126
126
 
127
127
  /* Suggestion list with proper columnar layout */
@@ -478,7 +478,7 @@ const MentionInput: React.FC<MentionInputProps> = ({
478
478
  className={`send-button ${sendBtnClassName || ""}`}
479
479
  aria-label="Send message"
480
480
  >
481
- {sendButtonIcon || ""}
481
+ {sendButtonIcon || ""}
482
482
  </button>
483
483
 
484
484
  <input
@@ -2,6 +2,13 @@
2
2
  display: flex;
3
3
  flex-direction: column;
4
4
  gap: 16px; /* Space between cards */
5
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
6
+ }
7
+
8
+ .message-card-wrapper {
9
+ display: flex;
10
+ flex-direction: column;
11
+ gap: 8px; /* Space between header and card */
5
12
  }
6
13
 
7
14
  .message-card {
@@ -12,6 +19,7 @@
12
19
  padding: 16px;
13
20
  background-color: #fff;
14
21
  transition: box-shadow 0.2s;
22
+ margin-left: 36px; /* Indent to align with header content */
15
23
  }
16
24
 
17
25
  .message-card:hover {
@@ -22,7 +30,7 @@
22
30
  display: flex;
23
31
  align-items: center;
24
32
  justify-content: space-between;
25
- margin-bottom: 8px; /* Space between header and body */
33
+ margin-bottom: 0; /* No margin since header is outside */
26
34
  }
27
35
 
28
36
  .message-card-header-left {
@@ -61,46 +69,47 @@
61
69
 
62
70
  .message-card-img,
63
71
  .message-card-initials {
64
- width: 48px;
65
- height: 48px;
72
+ width: 28px;
73
+ height: 28px;
66
74
  border-radius: 50%;
67
75
  display: flex;
68
76
  align-items: center;
69
77
  justify-content: center;
70
- font-size: 16px;
78
+ font-size: 12px;
71
79
  font-weight: bold;
72
80
  color: #fff;
73
81
  background-color: #007bff;
74
82
  text-transform: uppercase;
75
- margin-right: 16px;
83
+ margin-right: 8px;
76
84
  }
77
85
  .message-card-info {
78
86
  display: flex;
79
- flex-direction: column;
87
+ align-items: center;
80
88
  }
81
89
 
82
90
  .message-card-name {
83
91
  margin: 0;
84
- font-size: 18px;
85
- font-weight: bold;
86
- line-height: 1.2; /* Adjust line height for better spacing */
92
+ font-size: 14px;
93
+ font-weight: 600;
94
+ line-height: 1.2;
95
+ margin-right: 8px;
87
96
  }
88
97
 
89
98
  .message-card-date {
90
99
  margin: 0;
91
- font-size: 14px;
92
- color: #888;
93
- line-height: 1.2; /* Adjust line height for better spacing */
100
+ font-size: 12px;
101
+ color: #888888;
102
+ line-height: 1.2;
94
103
  }
95
104
 
96
105
  .message-card-body {
97
- margin-top: 8px; /* Space between header and comment */
106
+ margin-top: 0; /* No margin since body is in the card */
98
107
  }
99
108
 
100
109
  .message-card-comment {
101
110
  margin: 0;
102
- font-size: 16px;
103
- line-height: 1.5; /* Optimal line height for readability */
111
+ font-size: 13px;
112
+ line-height: 1.5;
104
113
  }
105
114
  .mention-highlight {
106
115
  background-color: #e0f7fa;
@@ -126,8 +135,8 @@
126
135
  }
127
136
 
128
137
  .tag-chip {
129
- padding: 6px 12px;
130
- border-radius: 16px;
138
+ padding: 4px 8px;
139
+ border-radius: 4px;
131
140
  font-size: 12px;
132
141
  font-weight: 500;
133
142
  border: none;
@@ -136,11 +145,36 @@
136
145
  }
137
146
 
138
147
  .hashtag-chip {
139
- background-color: #D4A574;
140
- color: #FFFFFF;
148
+ background-color: rgba(255, 165, 0, 0.15);
149
+ color: #FF8C00;
141
150
  }
142
151
 
143
152
  .mention-chip {
144
- background-color: #2684FF;
145
- color: #FFFFFF;
153
+ background-color: #E0F7FA;
154
+ color: #007BFF;
155
+ }
156
+
157
+ /* Related object styling */
158
+ .message-card-related {
159
+ display: flex;
160
+ align-items: center;
161
+ margin-top: 8px;
162
+ }
163
+
164
+ .related-label {
165
+ font-size: 13px;
166
+ color: #333;
167
+ margin-right: 8px;
168
+ }
169
+
170
+ .related-object-chip {
171
+ background-color: #f0f0f0;
172
+ color: #666;
173
+ padding: 2px 6px;
174
+ border-radius: 4px;
175
+ font-size: 12px;
176
+ height: 20px;
177
+ display: flex;
178
+ align-items: center;
179
+ border: 1px solid #ddd;
146
180
  }
@@ -15,6 +15,7 @@ interface ShowMessageCardProps {
15
15
  objectNameKey?: string; // Custom key for object identifier (top-right)
16
16
  revisionKey?: string; // Custom key for revision (top-right)
17
17
  objectTypeIconKey?: string; // Custom key for object type icon (top-right)
18
+ relatedObjectKey?: string; // Custom key for related object (bottom-left)
18
19
  containerClassName?: string; // Class for the outermost container
19
20
  containerStyle?: CSSProperties; // Style for the outermost container
20
21
  cardClassName?: string; // Class for the card
@@ -55,6 +56,7 @@ export const ShowMessageCard: React.FC<ShowMessageCardProps> = ({
55
56
  objectNameKey = "objectName", // Default key for object identifier
56
57
  revisionKey = "revision", // Default key for revision
57
58
  objectTypeIconKey = "object_type_icon", // Default key for object type icon
59
+ relatedObjectKey = "relatedObject", // Default key for related object
58
60
  containerClassName,
59
61
  containerStyle,
60
62
  cardClassName,
@@ -109,13 +111,29 @@ export const ShowMessageCard: React.FC<ShowMessageCardProps> = ({
109
111
 
110
112
  // Helper function to extract hashtags and mentions from text
111
113
  const extractTagsAndMentions = (text: string) => {
112
- const plainText = text.replace(/<[^>]*>/g, ''); // Remove HTML tags to get plain text
113
- const hashtags = plainText.match(/#[\w]+/g) || [];
114
- const mentions = plainText.match(/@[\w\s-]+/g) || [];
114
+ // First extract from HTML with spans
115
+ const hashtagsFromHTML = text.match(/<span[^>]*class="hashtag-highlight"[^>]*>(#[\w]+)<\/span>/g) || [];
116
+ const mentionsFromHTML = text.match(/<span[^>]*class="mention-highlight"[^>]*>(@[^<]+)<\/span>/g) || [];
117
+
118
+ // Extract the actual text content from HTML
119
+ const hashtags = hashtagsFromHTML.map(match => {
120
+ const textMatch = match.match(/>(#[\w]+)</);
121
+ return textMatch ? textMatch[1] : '';
122
+ }).filter(tag => tag);
123
+
124
+ const mentions = mentionsFromHTML.map(match => {
125
+ const textMatch = match.match(/>(@[^<]+)</);
126
+ return textMatch ? textMatch[1].trim() : '';
127
+ }).filter(mention => mention);
128
+
129
+ // Also check plain text for any missed items
130
+ const plainText = text.replace(/<[^>]*>/g, '');
131
+ const plainHashtags = plainText.match(/#[\w]+/g) || [];
132
+ const plainMentions = plainText.match(/@[\w\s-]+/g) || [];
115
133
 
116
134
  return {
117
- hashtags: Array.from(new Set(hashtags)), // Remove duplicates
118
- mentions: Array.from(new Set(mentions.map(mention => mention.trim()))) // Remove duplicates and trim
135
+ hashtags: Array.from(new Set([...hashtags, ...plainHashtags])), // Remove duplicates
136
+ mentions: Array.from(new Set([...mentions, ...plainMentions.map(mention => mention.trim())])) // Remove duplicates and trim
119
137
  };
120
138
  };
121
139
 
@@ -140,11 +158,8 @@ export const ShowMessageCard: React.FC<ShowMessageCardProps> = ({
140
158
  const { hashtags, mentions } = extractTagsAndMentions(item[commentKey] || '');
141
159
 
142
160
  return (
143
- <div
144
- key={item.id || index}
145
- className={`message-card ${cardClassName || ""}`}
146
- style={cardStyle}
147
- >
161
+ <div key={item.id || index} className="message-card-wrapper">
162
+ {/* Header outside the card bubble */}
148
163
  <div
149
164
  className={`message-card-header ${headerClassName || ""}`}
150
165
  style={headerStyle}
@@ -163,7 +178,7 @@ export const ShowMessageCard: React.FC<ShowMessageCardProps> = ({
163
178
  alt={item[nameKey]}
164
179
  className={`message-card-img ${imgClassName || ""}`}
165
180
  style={imgStyle}
166
- onError={() => handleImageError(item.id || index)} // Pass card id or index
181
+ onError={() => handleImageError(item.id || index)}
167
182
  />
168
183
  )}
169
184
  <div
@@ -218,46 +233,63 @@ export const ShowMessageCard: React.FC<ShowMessageCardProps> = ({
218
233
  </>
219
234
  )}
220
235
  </div>
236
+
237
+ {/* Card bubble */}
221
238
  <div
222
- className={`message-card-body ${bodyClassName || ""}`}
223
- style={bodyStyle}
239
+ className={`message-card ${cardClassName || ""}`}
240
+ style={cardStyle}
224
241
  >
225
- <p
226
- className={`message-card-comment ${commentClassName || ""}`}
227
- style={commentStyle}
228
- dangerouslySetInnerHTML={{ __html: item[commentKey] }}
229
- ></p>
230
-
231
- {/* Display attached image if available */}
232
- {item?.[imageUrlKey] && (
233
- <div
234
- className={`message-card-attached-image-container ${attachedImageContainerClassName || ""}`}
235
- style={attachedImageContainerStyle}
236
- >
237
- <img
238
- src={item[imageUrlKey]}
239
- alt="Attached"
240
- className={`message-card-attached-image ${attachedImageClassName || ""}`}
241
- style={attachedImageStyle}
242
- />
243
- </div>
244
- )}
245
-
246
- {/* Display hashtags and mentions as chips */}
247
- {(hashtags.length > 0 || mentions.length > 0) && (
248
- <div className="message-card-tags">
249
- {hashtags.map((tag, tagIndex) => (
250
- <span key={`hashtag-${tagIndex}`} className="tag-chip hashtag-chip">
251
- {tag}
252
- </span>
253
- ))}
254
- {mentions.map((mention, mentionIndex) => (
255
- <span key={`mention-${mentionIndex}`} className="tag-chip mention-chip">
256
- {mention}
242
+ <div
243
+ className={`message-card-body ${bodyClassName || ""}`}
244
+ style={bodyStyle}
245
+ >
246
+ <p
247
+ className={`message-card-comment ${commentClassName || ""}`}
248
+ style={commentStyle}
249
+ dangerouslySetInnerHTML={{ __html: item[commentKey] }}
250
+ ></p>
251
+
252
+ {/* Display attached image if available */}
253
+ {item?.[imageUrlKey] && (
254
+ <div
255
+ className={`message-card-attached-image-container ${attachedImageContainerClassName || ""}`}
256
+ style={attachedImageContainerStyle}
257
+ >
258
+ <img
259
+ src={item[imageUrlKey]}
260
+ alt="Attached"
261
+ className={`message-card-attached-image ${attachedImageClassName || ""}`}
262
+ style={attachedImageStyle}
263
+ />
264
+ </div>
265
+ )}
266
+
267
+ {/* Display hashtags and mentions as chips */}
268
+ {(hashtags.length > 0 || mentions.length > 0) && (
269
+ <div className="message-card-tags">
270
+ {hashtags.map((tag, tagIndex) => (
271
+ <span key={`hashtag-${tagIndex}`} className="tag-chip hashtag-chip">
272
+ {tag}
273
+ </span>
274
+ ))}
275
+ {mentions.map((mention, mentionIndex) => (
276
+ <span key={`mention-${mentionIndex}`} className="tag-chip mention-chip">
277
+ {mention}
278
+ </span>
279
+ ))}
280
+ </div>
281
+ )}
282
+
283
+ {/* Display related object at bottom-left */}
284
+ {item[relatedObjectKey] && (
285
+ <div className="message-card-related">
286
+ <span className="related-label">Related: </span>
287
+ <span className="related-object-chip">
288
+ {item[relatedObjectKey]}
257
289
  </span>
258
- ))}
259
- </div>
260
- )}
290
+ </div>
291
+ )}
292
+ </div>
261
293
  </div>
262
294
  </div>
263
295
  );