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 +7 -3
- package/dist/MentionInput.css +6 -6
- package/dist/MentionInput.js +1 -1
- package/dist/ShowMessageCard.css +55 -21
- package/dist/ShowMessageCard.d.ts +1 -0
- package/dist/ShowMessageCard.js +42 -14
- package/package.json +1 -1
- package/src/MentionInput.css +6 -6
- package/src/MentionInput.tsx +1 -1
- package/src/ShowMessageCard.css +55 -21
- package/src/ShowMessageCard.tsx +80 -48
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: '
|
|
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: '
|
|
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
|
|
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>
|
package/dist/MentionInput.css
CHANGED
|
@@ -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:
|
|
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:
|
|
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: #
|
|
115
|
+
background-color: #23488C;
|
|
116
116
|
color: white;
|
|
117
117
|
border: none;
|
|
118
118
|
cursor: pointer;
|
|
119
|
-
font-size:
|
|
119
|
+
font-size: 24px;
|
|
120
120
|
transition: background-color 0.2s;
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
.send-button:hover {
|
|
124
|
-
background-color: #
|
|
124
|
+
background-color: #1a3a7a;
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
/* Suggestion list with proper columnar layout */
|
package/dist/MentionInput.js
CHANGED
|
@@ -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...")))),
|
package/dist/ShowMessageCard.css
CHANGED
|
@@ -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:
|
|
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:
|
|
65
|
-
height:
|
|
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:
|
|
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:
|
|
83
|
+
margin-right: 8px;
|
|
76
84
|
}
|
|
77
85
|
.message-card-info {
|
|
78
86
|
display: flex;
|
|
79
|
-
|
|
87
|
+
align-items: center;
|
|
80
88
|
}
|
|
81
89
|
|
|
82
90
|
.message-card-name {
|
|
83
91
|
margin: 0;
|
|
84
|
-
font-size:
|
|
85
|
-
font-weight:
|
|
86
|
-
line-height: 1.2;
|
|
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:
|
|
92
|
-
color: #
|
|
93
|
-
line-height: 1.2;
|
|
100
|
+
font-size: 12px;
|
|
101
|
+
color: #888888;
|
|
102
|
+
line-height: 1.2;
|
|
94
103
|
}
|
|
95
104
|
|
|
96
105
|
.message-card-body {
|
|
97
|
-
margin-top:
|
|
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:
|
|
103
|
-
line-height: 1.5;
|
|
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:
|
|
130
|
-
border-radius:
|
|
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:
|
|
140
|
-
color: #
|
|
148
|
+
background-color: rgba(255, 165, 0, 0.15);
|
|
149
|
+
color: #FF8C00;
|
|
141
150
|
}
|
|
142
151
|
|
|
143
152
|
.mention-chip {
|
|
144
|
-
background-color: #
|
|
145
|
-
color: #
|
|
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
|
}
|
package/dist/ShowMessageCard.js
CHANGED
|
@@ -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
|
|
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
|
-
|
|
45
|
-
var
|
|
46
|
-
var
|
|
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
|
|
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
|
|
77
|
-
React.createElement("
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
hashtags.
|
|
82
|
-
|
|
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
package/src/MentionInput.css
CHANGED
|
@@ -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:
|
|
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:
|
|
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: #
|
|
115
|
+
background-color: #23488C;
|
|
116
116
|
color: white;
|
|
117
117
|
border: none;
|
|
118
118
|
cursor: pointer;
|
|
119
|
-
font-size:
|
|
119
|
+
font-size: 24px;
|
|
120
120
|
transition: background-color 0.2s;
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
.send-button:hover {
|
|
124
|
-
background-color: #
|
|
124
|
+
background-color: #1a3a7a;
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
/* Suggestion list with proper columnar layout */
|
package/src/MentionInput.tsx
CHANGED
package/src/ShowMessageCard.css
CHANGED
|
@@ -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:
|
|
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:
|
|
65
|
-
height:
|
|
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:
|
|
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:
|
|
83
|
+
margin-right: 8px;
|
|
76
84
|
}
|
|
77
85
|
.message-card-info {
|
|
78
86
|
display: flex;
|
|
79
|
-
|
|
87
|
+
align-items: center;
|
|
80
88
|
}
|
|
81
89
|
|
|
82
90
|
.message-card-name {
|
|
83
91
|
margin: 0;
|
|
84
|
-
font-size:
|
|
85
|
-
font-weight:
|
|
86
|
-
line-height: 1.2;
|
|
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:
|
|
92
|
-
color: #
|
|
93
|
-
line-height: 1.2;
|
|
100
|
+
font-size: 12px;
|
|
101
|
+
color: #888888;
|
|
102
|
+
line-height: 1.2;
|
|
94
103
|
}
|
|
95
104
|
|
|
96
105
|
.message-card-body {
|
|
97
|
-
margin-top:
|
|
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:
|
|
103
|
-
line-height: 1.5;
|
|
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:
|
|
130
|
-
border-radius:
|
|
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:
|
|
140
|
-
color: #
|
|
148
|
+
background-color: rgba(255, 165, 0, 0.15);
|
|
149
|
+
color: #FF8C00;
|
|
141
150
|
}
|
|
142
151
|
|
|
143
152
|
.mention-chip {
|
|
144
|
-
background-color: #
|
|
145
|
-
color: #
|
|
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
|
}
|
package/src/ShowMessageCard.tsx
CHANGED
|
@@ -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
|
-
|
|
113
|
-
const
|
|
114
|
-
const
|
|
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
|
-
|
|
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)}
|
|
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
|
|
223
|
-
style={
|
|
239
|
+
className={`message-card ${cardClassName || ""}`}
|
|
240
|
+
style={cardStyle}
|
|
224
241
|
>
|
|
225
|
-
<
|
|
226
|
-
className={`message-card-
|
|
227
|
-
style={
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
<
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
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
|
-
|
|
260
|
-
|
|
290
|
+
</div>
|
|
291
|
+
)}
|
|
292
|
+
</div>
|
|
261
293
|
</div>
|
|
262
294
|
</div>
|
|
263
295
|
);
|