react-mention-input 1.0.9 → 1.0.10
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/README.md +140 -38
- package/dist/MentionInput.css +21 -11
- package/dist/MentionInput.d.ts +4 -0
- package/dist/MentionInput.js +28 -6
- package/dist/ShowMessageCard.css +40 -0
- package/dist/ShowMessageCard.d.ts +18 -0
- package/dist/ShowMessageCard.js +14 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/package.json +1 -1
- package/src/MentionInput.css +21 -11
- package/src/MentionInput.tsx +71 -15
- package/src/ShowMessageCard.css +40 -0
- package/src/ShowMessageCard.tsx +56 -0
- package/src/index.ts +1 -0
package/README.md
CHANGED
|
@@ -1,79 +1,181 @@
|
|
|
1
1
|
|
|
2
2
|
# react-mention-input
|
|
3
3
|
|
|
4
|
-
A React component
|
|
4
|
+
A React component library that provides two main components:
|
|
5
|
+
|
|
6
|
+
1. **MentionInput** - An input field with @mention functionality.
|
|
7
|
+
2. **ShowMessageCard** - A card component for displaying user messages with name, date, and image.
|
|
5
8
|
|
|
6
9
|
## Installation
|
|
7
10
|
|
|
8
|
-
|
|
11
|
+
Install the package using npm or yarn:
|
|
9
12
|
|
|
10
13
|
```bash
|
|
11
14
|
npm install react-mention-input
|
|
12
15
|
```
|
|
16
|
+
or
|
|
17
|
+
```bash
|
|
18
|
+
yarn add react-mention-input
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Components
|
|
22
|
+
|
|
23
|
+
### 1. MentionInput
|
|
24
|
+
|
|
25
|
+
A customizable input component with @mention functionality.
|
|
13
26
|
|
|
14
|
-
|
|
27
|
+
#### Props
|
|
15
28
|
|
|
16
|
-
|
|
29
|
+
| Prop Name | Type | Description |
|
|
30
|
+
|-------------------------|-----------------------------------|-------------|
|
|
31
|
+
| `users` | `User[]` | Array of user objects to display in suggestions. |
|
|
32
|
+
| `placeholder` | `string` | Placeholder text for the input. |
|
|
33
|
+
| `containerClassName` | `string` | Custom class name for the container. |
|
|
34
|
+
| `inputContainerClassName` | `string` | Custom class name for the input container. |
|
|
35
|
+
| `inputClassName` | `string` | Custom class name for the input field. |
|
|
36
|
+
| `sendBtnClassName` | `string` | Custom class name for the send button. |
|
|
37
|
+
| `suggestionListClassName` | `string` | Custom class name for the suggestion list. |
|
|
38
|
+
| `suggestionItemClassName` | `string` | Custom class name for each suggestion item. |
|
|
39
|
+
| `sendButtonIcon` | `ReactNode` | Custom icon for the send button (MUI icon or image path). |
|
|
40
|
+
| `onSendMessage` | `(message: string) => void` | Callback function triggered on sending a message. |
|
|
41
|
+
|
|
42
|
+
#### Example Usage
|
|
17
43
|
|
|
18
44
|
```tsx
|
|
19
45
|
import React from 'react';
|
|
20
|
-
import
|
|
46
|
+
import MentionInput from 'react-mention-input';
|
|
21
47
|
|
|
22
48
|
const users = [
|
|
23
|
-
{ id: 1, name: 'John
|
|
24
|
-
{ id: 2, name: '
|
|
25
|
-
{ id: 3, name: 'Kevin Carter' },
|
|
26
|
-
// Add more users as needed
|
|
49
|
+
{ id: 1, name: 'John Doe' },
|
|
50
|
+
{ id: 2, name: 'Jane Smith' }
|
|
27
51
|
];
|
|
28
52
|
|
|
29
53
|
function App() {
|
|
54
|
+
const handleSendMessage = (message: string) => {
|
|
55
|
+
console.log('Message sent:', message);
|
|
56
|
+
};
|
|
57
|
+
|
|
30
58
|
return (
|
|
31
|
-
<
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
59
|
+
<MentionInput
|
|
60
|
+
users={users}
|
|
61
|
+
placeholder="Type @ to mention someone..."
|
|
62
|
+
sendButtonIcon={<SendIcon />} // Optional MUI icon or image path
|
|
63
|
+
onSendMessage={handleSendMessage}
|
|
64
|
+
/>
|
|
35
65
|
);
|
|
36
66
|
}
|
|
37
67
|
|
|
38
68
|
export default App;
|
|
39
69
|
```
|
|
40
70
|
|
|
41
|
-
|
|
71
|
+
### 2. ShowMessageCard
|
|
42
72
|
|
|
43
|
-
|
|
44
|
-
|---------------|----------------|----------|-----------------------------------------------------------|
|
|
45
|
-
| `users` | `User[]` | Yes | An array of user objects to display as suggestions. |
|
|
46
|
-
| `placeholder` | `string` | No | A placeholder for the input field. Defaults to an empty string. |
|
|
73
|
+
A customizable card component for displaying messages with user details.
|
|
47
74
|
|
|
48
|
-
|
|
75
|
+
#### Props
|
|
49
76
|
|
|
50
|
-
|
|
77
|
+
| Prop Name | Type | Description |
|
|
78
|
+
|------------------|---------------------|-------------|
|
|
79
|
+
| `data` | `MessageCardProps[]`| Array of message card objects to display. |
|
|
80
|
+
| `cardClassName` | `string` | Custom class name for the card. |
|
|
81
|
+
| `cardStyle` | `CSSProperties` | Custom inline style for the card. |
|
|
82
|
+
| `imgClassName` | `string` | Custom class name for the image. |
|
|
83
|
+
| `imgStyle` | `CSSProperties` | Custom inline style for the image. |
|
|
51
84
|
|
|
52
|
-
|
|
53
|
-
|
|
85
|
+
**`MessageCardProps` Interface**:
|
|
86
|
+
```typescript
|
|
87
|
+
interface MessageCardProps {
|
|
54
88
|
id: number;
|
|
55
89
|
name: string;
|
|
90
|
+
date: string;
|
|
91
|
+
comment: string;
|
|
92
|
+
imgSrc: string;
|
|
56
93
|
}
|
|
57
94
|
```
|
|
58
95
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
- **Real-time user suggestions**: Shows a dropdown of user suggestions as the user types `@` followed by letters.
|
|
62
|
-
- **Customizable placeholder**: Set a custom placeholder for the input field.
|
|
63
|
-
- **Easy integration**: Simple to use in any React project.
|
|
64
|
-
|
|
65
|
-
## Styling
|
|
66
|
-
|
|
67
|
-
The component includes basic inline styles for the input and suggestion list. You can customize it further with your own CSS as needed.
|
|
68
|
-
|
|
69
|
-
## License
|
|
96
|
+
#### Example Usage
|
|
70
97
|
|
|
71
|
-
|
|
98
|
+
```tsx
|
|
99
|
+
import React from 'react';
|
|
100
|
+
import ShowMessageCard from 'react-mention-input';
|
|
101
|
+
|
|
102
|
+
const messageData = [
|
|
103
|
+
{
|
|
104
|
+
id: 1,
|
|
105
|
+
name: 'John Doe',
|
|
106
|
+
date: '19-11-24',
|
|
107
|
+
comment: 'This is a comment.',
|
|
108
|
+
imgSrc: 'path/to/image.jpg'
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
id: 2,
|
|
112
|
+
name: 'Jane Smith',
|
|
113
|
+
date: '19-11-24',
|
|
114
|
+
comment: 'Another comment.',
|
|
115
|
+
imgSrc: 'path/to/image2.jpg'
|
|
116
|
+
}
|
|
117
|
+
];
|
|
72
118
|
|
|
73
|
-
|
|
119
|
+
function App() {
|
|
120
|
+
return (
|
|
121
|
+
<ShowMessageCard
|
|
122
|
+
data={messageData}
|
|
123
|
+
cardClassName="custom-card"
|
|
124
|
+
cardStyle={{ border: '1px solid #ddd' }}
|
|
125
|
+
imgClassName="custom-img"
|
|
126
|
+
imgStyle={{ borderRadius: '50%' }}
|
|
127
|
+
/>
|
|
128
|
+
);
|
|
129
|
+
}
|
|
74
130
|
|
|
75
|
-
|
|
131
|
+
export default App;
|
|
132
|
+
```
|
|
76
133
|
|
|
77
|
-
|
|
134
|
+
## Package Configuration
|
|
135
|
+
|
|
136
|
+
Ensure that your `package.json` has the following structure:
|
|
137
|
+
|
|
138
|
+
```json
|
|
139
|
+
{
|
|
140
|
+
"name": "react-mention-input",
|
|
141
|
+
"version": "1.0.9",
|
|
142
|
+
"main": "dist/index.js",
|
|
143
|
+
"types": "dist/index.d.ts",
|
|
144
|
+
"scripts": {
|
|
145
|
+
"test": "echo "Error: no test specified" && exit 1",
|
|
146
|
+
"build": "tsc && npm run copy-css",
|
|
147
|
+
"copy-css": "copyfiles -u 1 src/**/*.css dist"
|
|
148
|
+
},
|
|
149
|
+
"keywords": [
|
|
150
|
+
"mention",
|
|
151
|
+
"input",
|
|
152
|
+
"autocomplete",
|
|
153
|
+
"user suggestions",
|
|
154
|
+
"react",
|
|
155
|
+
"typescript"
|
|
156
|
+
],
|
|
157
|
+
"author": "Your Name",
|
|
158
|
+
"license": "ISC",
|
|
159
|
+
"description": "A React component for input with @mention functionality.",
|
|
160
|
+
"repository": {
|
|
161
|
+
"type": "git",
|
|
162
|
+
"url": "https://github.com/yourusername/react-mention-input.git"
|
|
163
|
+
},
|
|
164
|
+
"devDependencies": {
|
|
165
|
+
"@types/node": "^22.9.0",
|
|
166
|
+
"@types/react": "^18.3.12",
|
|
167
|
+
"@types/react-dom": "^18.3.1",
|
|
168
|
+
"copyfiles": "^2.4.1",
|
|
169
|
+
"csstype": "^3.1.3",
|
|
170
|
+
"sass": "^1.81.0",
|
|
171
|
+
"typescript": "^5.6.3"
|
|
172
|
+
},
|
|
173
|
+
"peerDependencies": {
|
|
174
|
+
"react": "^17.0.0 || ^18.0.0",
|
|
175
|
+
"react-dom": "^17.0.0 || ^18.0.0"
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
```
|
|
78
179
|
|
|
79
|
-
|
|
180
|
+
### License
|
|
181
|
+
This project is licensed under the ISC License.
|
package/dist/MentionInput.css
CHANGED
|
@@ -4,26 +4,37 @@
|
|
|
4
4
|
align-items: center;
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
-
.mention-input
|
|
8
|
-
width: 100%;
|
|
9
|
-
padding: 12px 16px;
|
|
7
|
+
.mention-input-container{
|
|
10
8
|
border: 1px solid #ccc;
|
|
11
9
|
border-radius: 8px;
|
|
12
|
-
outline: none;
|
|
13
|
-
font-size: 16px;
|
|
14
10
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
15
11
|
transition: border 0.2s, box-shadow 0.2s;
|
|
12
|
+
width: 100%;
|
|
13
|
+
padding: 12px 16px;
|
|
14
|
+
position: relative;
|
|
15
|
+
display: flex;
|
|
16
|
+
align-items: center;
|
|
17
|
+
|
|
18
|
+
}
|
|
19
|
+
.mention-input {
|
|
20
|
+
border: none;
|
|
21
|
+
outline: none;
|
|
22
|
+
font-size: 16px;
|
|
23
|
+
flex: 1;
|
|
24
|
+
|
|
16
25
|
}
|
|
17
26
|
.mention-input:focus {
|
|
18
|
-
border:
|
|
27
|
+
border: none;
|
|
28
|
+
outline: none;
|
|
19
29
|
}
|
|
20
30
|
|
|
21
31
|
.send-button {
|
|
22
|
-
padding:
|
|
23
|
-
border:
|
|
32
|
+
padding: 4px 10x;
|
|
33
|
+
border: 1px solid #ccc;
|
|
34
|
+
border-radius: 8px;
|
|
24
35
|
background-color: #007BFF;
|
|
25
36
|
color: #fff;
|
|
26
|
-
|
|
37
|
+
|
|
27
38
|
cursor: pointer;
|
|
28
39
|
font-size: 18px;
|
|
29
40
|
display: flex;
|
|
@@ -54,8 +65,7 @@
|
|
|
54
65
|
border-bottom: 1px solid #ddd;
|
|
55
66
|
transition: background-color 0.2s;
|
|
56
67
|
}
|
|
68
|
+
|
|
57
69
|
.suggestion-item:hover {
|
|
58
70
|
background-color: #f5f5f5;
|
|
59
71
|
}
|
|
60
|
-
|
|
61
|
-
|
package/dist/MentionInput.d.ts
CHANGED
|
@@ -8,7 +8,11 @@ interface MentionInputProps {
|
|
|
8
8
|
users: User[];
|
|
9
9
|
placeholder?: string;
|
|
10
10
|
containerClassName?: string;
|
|
11
|
+
inputContainerClassName?: string;
|
|
11
12
|
inputClassName?: string;
|
|
13
|
+
sendBtnClassName?: string;
|
|
14
|
+
suggestionListClassName?: string;
|
|
15
|
+
suggestionItemClassName?: string;
|
|
12
16
|
sendButtonIcon?: ReactNode;
|
|
13
17
|
onSendMessage?: (message: string) => void;
|
|
14
18
|
}
|
package/dist/MentionInput.js
CHANGED
|
@@ -1,10 +1,31 @@
|
|
|
1
1
|
import React, { useState } from 'react';
|
|
2
|
-
import './MentionInput.css'; // Import the
|
|
2
|
+
import './MentionInput.css'; // Import the SCSS file
|
|
3
3
|
var MentionInput = function (_a) {
|
|
4
|
-
var users = _a.users, placeholder = _a.placeholder, containerClassName = _a.containerClassName, inputClassName = _a.inputClassName, sendButtonIcon = _a.sendButtonIcon, onSendMessage = _a.onSendMessage;
|
|
4
|
+
var users = _a.users, placeholder = _a.placeholder, containerClassName = _a.containerClassName, inputContainerClassName = _a.inputContainerClassName, inputClassName = _a.inputClassName, sendBtnClassName = _a.sendBtnClassName, suggestionListClassName = _a.suggestionListClassName, suggestionItemClassName = _a.suggestionItemClassName, sendButtonIcon = _a.sendButtonIcon, onSendMessage = _a.onSendMessage;
|
|
5
5
|
var _b = useState(''), inputValue = _b[0], setInputValue = _b[1];
|
|
6
|
+
var _c = useState([]), suggestions = _c[0], setSuggestions = _c[1];
|
|
7
|
+
var _d = useState(false), showSuggestions = _d[0], setShowSuggestions = _d[1];
|
|
6
8
|
var handleInputChange = function (e) {
|
|
7
|
-
|
|
9
|
+
var value = e.target.value;
|
|
10
|
+
setInputValue(value);
|
|
11
|
+
var mentionMatch = value.match(/@(\w*)$/);
|
|
12
|
+
if (mentionMatch) {
|
|
13
|
+
var query_1 = mentionMatch[1].toLowerCase();
|
|
14
|
+
var filteredUsers = users.filter(function (user) {
|
|
15
|
+
return user.name.toLowerCase().startsWith(query_1);
|
|
16
|
+
});
|
|
17
|
+
setSuggestions(filteredUsers);
|
|
18
|
+
setShowSuggestions(true);
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
setShowSuggestions(false);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
var handleSuggestionClick = function (user) {
|
|
25
|
+
var mentionIndex = inputValue.lastIndexOf('@');
|
|
26
|
+
var newValue = "".concat(inputValue.substring(0, mentionIndex + 1)).concat(user.name, " ");
|
|
27
|
+
setInputValue(newValue);
|
|
28
|
+
setShowSuggestions(false);
|
|
8
29
|
};
|
|
9
30
|
var handleSendMessage = function () {
|
|
10
31
|
if (inputValue.trim() && onSendMessage) {
|
|
@@ -19,8 +40,9 @@ var MentionInput = function (_a) {
|
|
|
19
40
|
}
|
|
20
41
|
};
|
|
21
42
|
return (React.createElement("div", { className: "mention-container ".concat(containerClassName || '') },
|
|
22
|
-
React.createElement("div", { className: "input-
|
|
23
|
-
React.createElement("input", { type: "text", value: inputValue, onChange: handleInputChange, onKeyPress: handleKeyPress, placeholder: placeholder || 'Type
|
|
24
|
-
React.createElement("button", { onClick: handleSendMessage, className: "send-button" }, sendButtonIcon ? sendButtonIcon : '➤')))
|
|
43
|
+
React.createElement("div", { className: "mention-input-container ".concat(inputContainerClassName || '') },
|
|
44
|
+
React.createElement("input", { type: "text", value: inputValue, onChange: handleInputChange, onKeyPress: handleKeyPress, placeholder: placeholder || 'Type a message...', className: "mention-input ".concat(inputClassName || '') }),
|
|
45
|
+
React.createElement("button", { onClick: handleSendMessage, className: "send-button ".concat(sendBtnClassName || '') }, sendButtonIcon ? (typeof sendButtonIcon === 'string' ? (React.createElement("img", { src: sendButtonIcon, alt: "Send Icon", style: { width: '20px', height: '20px' } })) : (sendButtonIcon)) : ('➤'))),
|
|
46
|
+
showSuggestions && (React.createElement("ul", { className: "suggestion-list ".concat(suggestionListClassName || '') }, suggestions.map(function (user) { return (React.createElement("li", { key: user.id, onClick: function () { return handleSuggestionClick(user); }, className: "suggestion-item ".concat(suggestionItemClassName || '') }, user.name)); })))));
|
|
25
47
|
};
|
|
26
48
|
export default MentionInput;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
.message-card {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-direction: column;
|
|
4
|
+
border: 1px solid #ccc;
|
|
5
|
+
border-radius: 8px;
|
|
6
|
+
padding: 16px;
|
|
7
|
+
background-color: #fff;
|
|
8
|
+
transition: box-shadow 0.2s;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.message-card:hover {
|
|
12
|
+
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.message-card-img {
|
|
16
|
+
width: 48px;
|
|
17
|
+
height: 48px;
|
|
18
|
+
border-radius: 50%;
|
|
19
|
+
margin-right: 16px;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.message-card-info {
|
|
23
|
+
display: flex;
|
|
24
|
+
flex-direction: column;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.message-card-name {
|
|
28
|
+
font-size: 18px;
|
|
29
|
+
font-weight: bold;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.message-card-date {
|
|
33
|
+
font-size: 14px;
|
|
34
|
+
color: #888;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.message-card-comment {
|
|
38
|
+
font-size: 16px;
|
|
39
|
+
}
|
|
40
|
+
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import React, { CSSProperties } from 'react';
|
|
2
|
+
import './ShowMessageCard.css';
|
|
3
|
+
interface MessageCardProps {
|
|
4
|
+
id: number;
|
|
5
|
+
name: string;
|
|
6
|
+
date: string;
|
|
7
|
+
comment: string;
|
|
8
|
+
imgSrc: string;
|
|
9
|
+
}
|
|
10
|
+
interface ShowMessageCardProps {
|
|
11
|
+
data: MessageCardProps[];
|
|
12
|
+
cardClassName?: string;
|
|
13
|
+
cardStyle?: CSSProperties;
|
|
14
|
+
imgClassName?: string;
|
|
15
|
+
imgStyle?: CSSProperties;
|
|
16
|
+
}
|
|
17
|
+
declare const ShowMessageCard: React.FC<ShowMessageCardProps>;
|
|
18
|
+
export default ShowMessageCard;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import './ShowMessageCard.css'; // Import the CSS file
|
|
3
|
+
var ShowMessageCard = function (_a) {
|
|
4
|
+
var data = _a.data, cardClassName = _a.cardClassName, cardStyle = _a.cardStyle, imgClassName = _a.imgClassName, imgStyle = _a.imgStyle;
|
|
5
|
+
return (React.createElement("div", { className: "message-card-container" }, data.map(function (item) { return (React.createElement("div", { key: item.id, className: "message-card ".concat(cardClassName || ''), style: cardStyle },
|
|
6
|
+
React.createElement("div", { className: "message-card-header" },
|
|
7
|
+
React.createElement("img", { src: item.imgSrc || 'default-image.png', alt: item.name, className: "message-card-img ".concat(imgClassName || ''), style: imgStyle }),
|
|
8
|
+
React.createElement("div", { className: "message-card-info" },
|
|
9
|
+
React.createElement("h3", { className: "message-card-name" }, item.name),
|
|
10
|
+
React.createElement("p", { className: "message-card-date" }, item.date))),
|
|
11
|
+
React.createElement("div", { className: "message-card-body" },
|
|
12
|
+
React.createElement("p", { className: "message-card-comment" }, item.comment)))); })));
|
|
13
|
+
};
|
|
14
|
+
export default ShowMessageCard;
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/package.json
CHANGED
package/src/MentionInput.css
CHANGED
|
@@ -4,26 +4,37 @@
|
|
|
4
4
|
align-items: center;
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
-
.mention-input
|
|
8
|
-
width: 100%;
|
|
9
|
-
padding: 12px 16px;
|
|
7
|
+
.mention-input-container{
|
|
10
8
|
border: 1px solid #ccc;
|
|
11
9
|
border-radius: 8px;
|
|
12
|
-
outline: none;
|
|
13
|
-
font-size: 16px;
|
|
14
10
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
15
11
|
transition: border 0.2s, box-shadow 0.2s;
|
|
12
|
+
width: 100%;
|
|
13
|
+
padding: 12px 16px;
|
|
14
|
+
position: relative;
|
|
15
|
+
display: flex;
|
|
16
|
+
align-items: center;
|
|
17
|
+
|
|
18
|
+
}
|
|
19
|
+
.mention-input {
|
|
20
|
+
border: none;
|
|
21
|
+
outline: none;
|
|
22
|
+
font-size: 16px;
|
|
23
|
+
flex: 1;
|
|
24
|
+
|
|
16
25
|
}
|
|
17
26
|
.mention-input:focus {
|
|
18
|
-
border:
|
|
27
|
+
border: none;
|
|
28
|
+
outline: none;
|
|
19
29
|
}
|
|
20
30
|
|
|
21
31
|
.send-button {
|
|
22
|
-
padding:
|
|
23
|
-
border:
|
|
32
|
+
padding: 4px 10x;
|
|
33
|
+
border: 1px solid #ccc;
|
|
34
|
+
border-radius: 8px;
|
|
24
35
|
background-color: #007BFF;
|
|
25
36
|
color: #fff;
|
|
26
|
-
|
|
37
|
+
|
|
27
38
|
cursor: pointer;
|
|
28
39
|
font-size: 18px;
|
|
29
40
|
display: flex;
|
|
@@ -54,8 +65,7 @@
|
|
|
54
65
|
border-bottom: 1px solid #ddd;
|
|
55
66
|
transition: background-color 0.2s;
|
|
56
67
|
}
|
|
68
|
+
|
|
57
69
|
.suggestion-item:hover {
|
|
58
70
|
background-color: #f5f5f5;
|
|
59
71
|
}
|
|
60
|
-
|
|
61
|
-
|
package/src/MentionInput.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useState, ChangeEvent, KeyboardEvent, ReactNode } from 'react';
|
|
2
|
-
import './MentionInput.css'; // Import the
|
|
2
|
+
import './MentionInput.css'; // Import the SCSS file
|
|
3
3
|
|
|
4
4
|
interface User {
|
|
5
5
|
id: number;
|
|
@@ -10,8 +10,12 @@ interface MentionInputProps {
|
|
|
10
10
|
users: User[];
|
|
11
11
|
placeholder?: string;
|
|
12
12
|
containerClassName?: string;
|
|
13
|
+
inputContainerClassName?: string;
|
|
13
14
|
inputClassName?: string;
|
|
14
|
-
|
|
15
|
+
sendBtnClassName?: string;
|
|
16
|
+
suggestionListClassName?: string;
|
|
17
|
+
suggestionItemClassName?: string;
|
|
18
|
+
sendButtonIcon?: ReactNode; // New prop for button icon (MUI icon or image path)
|
|
15
19
|
onSendMessage?: (message: string) => void;
|
|
16
20
|
}
|
|
17
21
|
|
|
@@ -19,14 +23,40 @@ const MentionInput: React.FC<MentionInputProps> = ({
|
|
|
19
23
|
users,
|
|
20
24
|
placeholder,
|
|
21
25
|
containerClassName,
|
|
26
|
+
inputContainerClassName,
|
|
22
27
|
inputClassName,
|
|
28
|
+
sendBtnClassName,
|
|
29
|
+
suggestionListClassName,
|
|
30
|
+
suggestionItemClassName,
|
|
23
31
|
sendButtonIcon,
|
|
24
32
|
onSendMessage,
|
|
25
33
|
}) => {
|
|
26
34
|
const [inputValue, setInputValue] = useState<string>('');
|
|
35
|
+
const [suggestions, setSuggestions] = useState<User[]>([]);
|
|
36
|
+
const [showSuggestions, setShowSuggestions] = useState<boolean>(false);
|
|
27
37
|
|
|
28
38
|
const handleInputChange = (e: ChangeEvent<HTMLInputElement>) => {
|
|
29
|
-
|
|
39
|
+
const value = e.target.value;
|
|
40
|
+
setInputValue(value);
|
|
41
|
+
|
|
42
|
+
const mentionMatch = value.match(/@(\w*)$/);
|
|
43
|
+
if (mentionMatch) {
|
|
44
|
+
const query = mentionMatch[1].toLowerCase();
|
|
45
|
+
const filteredUsers = users.filter((user) =>
|
|
46
|
+
user.name.toLowerCase().startsWith(query)
|
|
47
|
+
);
|
|
48
|
+
setSuggestions(filteredUsers);
|
|
49
|
+
setShowSuggestions(true);
|
|
50
|
+
} else {
|
|
51
|
+
setShowSuggestions(false);
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const handleSuggestionClick = (user: User) => {
|
|
56
|
+
const mentionIndex = inputValue.lastIndexOf('@');
|
|
57
|
+
const newValue = `${inputValue.substring(0, mentionIndex + 1)}${user.name} `;
|
|
58
|
+
setInputValue(newValue);
|
|
59
|
+
setShowSuggestions(false);
|
|
30
60
|
};
|
|
31
61
|
|
|
32
62
|
const handleSendMessage = () => {
|
|
@@ -45,19 +75,45 @@ const MentionInput: React.FC<MentionInputProps> = ({
|
|
|
45
75
|
|
|
46
76
|
return (
|
|
47
77
|
<div className={`mention-container ${containerClassName || ''}`}>
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
78
|
+
|
|
79
|
+
<div className={`mention-input-container ${inputContainerClassName || ''}`}>
|
|
80
|
+
<input
|
|
81
|
+
type="text"
|
|
82
|
+
value={inputValue}
|
|
83
|
+
onChange={handleInputChange}
|
|
84
|
+
onKeyPress={handleKeyPress}
|
|
85
|
+
placeholder={placeholder || 'Type a message...'}
|
|
86
|
+
className={`mention-input ${inputClassName || ''}`}
|
|
87
|
+
/>
|
|
88
|
+
<button
|
|
89
|
+
onClick={handleSendMessage}
|
|
90
|
+
className={`send-button ${sendBtnClassName || ''}`}
|
|
91
|
+
>
|
|
92
|
+
{sendButtonIcon ? (
|
|
93
|
+
typeof sendButtonIcon === 'string' ? (
|
|
94
|
+
<img src={sendButtonIcon} alt="Send Icon" style={{ width: '20px', height: '20px' }} />
|
|
95
|
+
) : (
|
|
96
|
+
sendButtonIcon
|
|
97
|
+
)
|
|
98
|
+
) : (
|
|
99
|
+
'➤'
|
|
100
|
+
)}
|
|
101
|
+
</button>
|
|
102
|
+
|
|
60
103
|
</div>
|
|
104
|
+
{showSuggestions && (
|
|
105
|
+
<ul className={`suggestion-list ${suggestionListClassName || ''}`}>
|
|
106
|
+
{suggestions.map((user) => (
|
|
107
|
+
<li
|
|
108
|
+
key={user.id}
|
|
109
|
+
onClick={() => handleSuggestionClick(user)}
|
|
110
|
+
className={`suggestion-item ${suggestionItemClassName || ''}`}
|
|
111
|
+
>
|
|
112
|
+
{user.name}
|
|
113
|
+
</li>
|
|
114
|
+
))}
|
|
115
|
+
</ul>
|
|
116
|
+
)}
|
|
61
117
|
</div>
|
|
62
118
|
);
|
|
63
119
|
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
.message-card {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-direction: column;
|
|
4
|
+
border: 1px solid #ccc;
|
|
5
|
+
border-radius: 8px;
|
|
6
|
+
padding: 16px;
|
|
7
|
+
background-color: #fff;
|
|
8
|
+
transition: box-shadow 0.2s;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.message-card:hover {
|
|
12
|
+
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.message-card-img {
|
|
16
|
+
width: 48px;
|
|
17
|
+
height: 48px;
|
|
18
|
+
border-radius: 50%;
|
|
19
|
+
margin-right: 16px;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.message-card-info {
|
|
23
|
+
display: flex;
|
|
24
|
+
flex-direction: column;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.message-card-name {
|
|
28
|
+
font-size: 18px;
|
|
29
|
+
font-weight: bold;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.message-card-date {
|
|
33
|
+
font-size: 14px;
|
|
34
|
+
color: #888;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.message-card-comment {
|
|
38
|
+
font-size: 16px;
|
|
39
|
+
}
|
|
40
|
+
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import React, { CSSProperties } from 'react';
|
|
2
|
+
import './ShowMessageCard.css'; // Import the CSS file
|
|
3
|
+
|
|
4
|
+
interface MessageCardProps {
|
|
5
|
+
id: number;
|
|
6
|
+
name: string;
|
|
7
|
+
date: string;
|
|
8
|
+
comment: string;
|
|
9
|
+
imgSrc: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
interface ShowMessageCardProps {
|
|
13
|
+
data: MessageCardProps[];
|
|
14
|
+
cardClassName?: string; // Custom class for card styling
|
|
15
|
+
cardStyle?: CSSProperties; // Custom inline style for card
|
|
16
|
+
imgClassName?: string; // Custom class for image styling
|
|
17
|
+
imgStyle?: CSSProperties; // Custom inline style for image
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const ShowMessageCard: React.FC<ShowMessageCardProps> = ({
|
|
21
|
+
data,
|
|
22
|
+
cardClassName,
|
|
23
|
+
cardStyle,
|
|
24
|
+
imgClassName,
|
|
25
|
+
imgStyle
|
|
26
|
+
}) => {
|
|
27
|
+
return (
|
|
28
|
+
<div className="message-card-container">
|
|
29
|
+
{data.map((item) => (
|
|
30
|
+
<div
|
|
31
|
+
key={item.id}
|
|
32
|
+
className={`message-card ${cardClassName || ''}`}
|
|
33
|
+
style={cardStyle}
|
|
34
|
+
>
|
|
35
|
+
<div className="message-card-header">
|
|
36
|
+
<img
|
|
37
|
+
src={item.imgSrc || 'default-image.png'}
|
|
38
|
+
alt={item.name}
|
|
39
|
+
className={`message-card-img ${imgClassName || ''}`}
|
|
40
|
+
style={imgStyle}
|
|
41
|
+
/>
|
|
42
|
+
<div className="message-card-info">
|
|
43
|
+
<h3 className="message-card-name">{item.name}</h3>
|
|
44
|
+
<p className="message-card-date">{item.date}</p>
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
<div className="message-card-body">
|
|
48
|
+
<p className="message-card-comment">{item.comment}</p>
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
))}
|
|
52
|
+
</div>
|
|
53
|
+
);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export default ShowMessageCard;
|
package/src/index.ts
CHANGED