react-mention-input 1.1.28 → 1.1.29

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.
@@ -55,22 +55,46 @@ export var useProtectedImage = function (_a) {
55
55
  var url = _a.url, isProtected = _a.isProtected, getAuthHeaders = _a.getAuthHeaders;
56
56
  var _b = useState(null), blobUrl = _b[0], setBlobUrl = _b[1];
57
57
  var blobUrlRef = useRef(null);
58
+ var blobUrlForUrlRef = useRef(null); // Track which URL the blob URL corresponds to
59
+ var previousUrlRef = useRef(null);
60
+ var isProtectedRef = useRef(isProtected);
61
+ var getAuthHeadersRef = useRef(getAuthHeaders);
62
+ // Update refs when props change (but don't trigger re-fetch)
58
63
  useEffect(function () {
59
- // Cleanup previous blob URL
60
- if (blobUrlRef.current) {
61
- URL.revokeObjectURL(blobUrlRef.current);
62
- blobUrlRef.current = null;
64
+ isProtectedRef.current = isProtected;
65
+ getAuthHeadersRef.current = getAuthHeaders;
66
+ }, [isProtected, getAuthHeaders]);
67
+ useEffect(function () {
68
+ // If URL hasn't changed, don't do anything
69
+ if (url === previousUrlRef.current) {
70
+ return;
63
71
  }
64
- setBlobUrl(null);
72
+ // Store previous URL and blob URL for later cleanup
73
+ var oldUrl = previousUrlRef.current;
74
+ var oldBlobUrl = blobUrlRef.current;
75
+ previousUrlRef.current = url;
65
76
  if (!url) {
77
+ // If URL is null, clean up old blob URL and clear state
78
+ if (oldBlobUrl) {
79
+ URL.revokeObjectURL(oldBlobUrl);
80
+ blobUrlRef.current = null;
81
+ blobUrlForUrlRef.current = null;
82
+ }
83
+ setBlobUrl(null);
66
84
  return;
67
85
  }
68
86
  // Check if URL is protected
69
- var shouldUseAuth = typeof isProtected === 'boolean'
70
- ? isProtected
71
- : isProtected ? isProtected(url) : false;
72
- // If not protected, don't fetch - will use original URL
73
- if (!shouldUseAuth || !getAuthHeaders) {
87
+ var shouldUseAuth = typeof isProtectedRef.current === 'boolean'
88
+ ? isProtectedRef.current
89
+ : isProtectedRef.current ? isProtectedRef.current(url) : false;
90
+ // If not protected, clean up old blob URL and use original URL
91
+ if (!shouldUseAuth || !getAuthHeadersRef.current) {
92
+ if (oldBlobUrl) {
93
+ URL.revokeObjectURL(oldBlobUrl);
94
+ blobUrlRef.current = null;
95
+ blobUrlForUrlRef.current = null;
96
+ }
97
+ setBlobUrl(null);
74
98
  return;
75
99
  }
76
100
  // Fetch protected image with auth headers
@@ -80,7 +104,7 @@ export var useProtectedImage = function (_a) {
80
104
  switch (_a.label) {
81
105
  case 0:
82
106
  _a.trys.push([0, 4, , 5]);
83
- return [4 /*yield*/, Promise.resolve(getAuthHeaders())];
107
+ return [4 /*yield*/, Promise.resolve(getAuthHeadersRef.current())];
84
108
  case 1:
85
109
  headers = _a.sent();
86
110
  return [4 /*yield*/, fetch(url, {
@@ -96,34 +120,50 @@ export var useProtectedImage = function (_a) {
96
120
  case 3:
97
121
  blob = _a.sent();
98
122
  newBlobUrl = URL.createObjectURL(blob);
99
- blobUrlRef.current = newBlobUrl;
100
- setBlobUrl(newBlobUrl);
123
+ // Only update if URL hasn't changed during fetch
124
+ if (previousUrlRef.current === url) {
125
+ // Revoke old blob URL now that new one is ready
126
+ if (oldBlobUrl && oldUrl !== url) {
127
+ URL.revokeObjectURL(oldBlobUrl);
128
+ }
129
+ blobUrlRef.current = newBlobUrl;
130
+ blobUrlForUrlRef.current = url;
131
+ setBlobUrl(newBlobUrl);
132
+ }
133
+ else {
134
+ // URL changed during fetch, revoke this blob URL
135
+ URL.revokeObjectURL(newBlobUrl);
136
+ }
101
137
  return [3 /*break*/, 5];
102
138
  case 4:
103
139
  error_1 = _a.sent();
104
140
  console.error('Error fetching protected image:', error_1);
105
- // On error, fallback to original URL (might show broken image, but won't crash)
106
- setBlobUrl(null);
141
+ // On error, only clear if URL hasn't changed
142
+ if (previousUrlRef.current === url) {
143
+ setBlobUrl(null);
144
+ }
107
145
  return [3 /*break*/, 5];
108
146
  case 5: return [2 /*return*/];
109
147
  }
110
148
  });
111
149
  }); };
112
150
  fetchProtectedImage();
113
- // Cleanup function
151
+ // Cleanup function - revoke blob URL on unmount
114
152
  return function () {
153
+ // On unmount, clean up the current blob URL
115
154
  if (blobUrlRef.current) {
116
155
  URL.revokeObjectURL(blobUrlRef.current);
117
156
  blobUrlRef.current = null;
157
+ blobUrlForUrlRef.current = null;
118
158
  }
119
159
  };
120
- }, [url, isProtected, getAuthHeaders]);
160
+ }, [url]); // Only depend on url, not isProtected or getAuthHeaders
121
161
  // Return blob URL if available, otherwise return original URL (or null)
122
162
  if (!url) {
123
163
  return null;
124
164
  }
125
- var isUrlProtected = typeof isProtected === 'boolean'
126
- ? isProtected
127
- : isProtected ? isProtected(url) : false;
165
+ var isUrlProtected = typeof isProtectedRef.current === 'boolean'
166
+ ? isProtectedRef.current
167
+ : isProtectedRef.current ? isProtectedRef.current(url) : false;
128
168
  return blobUrl || (!isUrlProtected ? url : null);
129
169
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-mention-input",
3
- "version": "1.1.28",
3
+ "version": "1.1.29",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "scripts": {
@@ -25,7 +25,7 @@
25
25
  "description": "A React component for input with @mention functionality.",
26
26
  "repository": {
27
27
  "type": "git",
28
- "url": "https://github.com/yourusername/react-mention-input.git"
28
+ "url": "git+https://github.com/yourusername/react-mention-input.git"
29
29
  },
30
30
  "devDependencies": {
31
31
  "@types/node": "^22.9.0",
@@ -18,33 +18,59 @@ export const useProtectedImage = ({
18
18
  }: UseProtectedImageOptions): string | null => {
19
19
  const [blobUrl, setBlobUrl] = useState<string | null>(null);
20
20
  const blobUrlRef = useRef<string | null>(null);
21
+ const blobUrlForUrlRef = useRef<string | null>(null); // Track which URL the blob URL corresponds to
22
+ const previousUrlRef = useRef<string | null>(null);
23
+ const isProtectedRef = useRef(isProtected);
24
+ const getAuthHeadersRef = useRef(getAuthHeaders);
21
25
 
26
+ // Update refs when props change (but don't trigger re-fetch)
22
27
  useEffect(() => {
23
- // Cleanup previous blob URL
24
- if (blobUrlRef.current) {
25
- URL.revokeObjectURL(blobUrlRef.current);
26
- blobUrlRef.current = null;
28
+ isProtectedRef.current = isProtected;
29
+ getAuthHeadersRef.current = getAuthHeaders;
30
+ }, [isProtected, getAuthHeaders]);
31
+
32
+ useEffect(() => {
33
+ // If URL hasn't changed, don't do anything
34
+ if (url === previousUrlRef.current) {
35
+ return;
27
36
  }
28
- setBlobUrl(null);
37
+
38
+ // Store previous URL and blob URL for later cleanup
39
+ const oldUrl = previousUrlRef.current;
40
+ const oldBlobUrl = blobUrlRef.current;
41
+ previousUrlRef.current = url;
29
42
 
30
43
  if (!url) {
44
+ // If URL is null, clean up old blob URL and clear state
45
+ if (oldBlobUrl) {
46
+ URL.revokeObjectURL(oldBlobUrl);
47
+ blobUrlRef.current = null;
48
+ blobUrlForUrlRef.current = null;
49
+ }
50
+ setBlobUrl(null);
31
51
  return;
32
52
  }
33
53
 
34
54
  // Check if URL is protected
35
- const shouldUseAuth = typeof isProtected === 'boolean'
36
- ? isProtected
37
- : isProtected ? isProtected(url) : false;
55
+ const shouldUseAuth = typeof isProtectedRef.current === 'boolean'
56
+ ? isProtectedRef.current
57
+ : isProtectedRef.current ? isProtectedRef.current(url) : false;
38
58
 
39
- // If not protected, don't fetch - will use original URL
40
- if (!shouldUseAuth || !getAuthHeaders) {
59
+ // If not protected, clean up old blob URL and use original URL
60
+ if (!shouldUseAuth || !getAuthHeadersRef.current) {
61
+ if (oldBlobUrl) {
62
+ URL.revokeObjectURL(oldBlobUrl);
63
+ blobUrlRef.current = null;
64
+ blobUrlForUrlRef.current = null;
65
+ }
66
+ setBlobUrl(null);
41
67
  return;
42
68
  }
43
69
 
44
70
  // Fetch protected image with auth headers
45
71
  const fetchProtectedImage = async () => {
46
72
  try {
47
- const headers = await Promise.resolve(getAuthHeaders());
73
+ const headers = await Promise.resolve(getAuthHeadersRef.current!());
48
74
  const response = await fetch(url, {
49
75
  method: 'GET',
50
76
  headers: {
@@ -58,34 +84,50 @@ export const useProtectedImage = ({
58
84
 
59
85
  const blob = await response.blob();
60
86
  const newBlobUrl = URL.createObjectURL(blob);
61
- blobUrlRef.current = newBlobUrl;
62
- setBlobUrl(newBlobUrl);
87
+
88
+ // Only update if URL hasn't changed during fetch
89
+ if (previousUrlRef.current === url) {
90
+ // Revoke old blob URL now that new one is ready
91
+ if (oldBlobUrl && oldUrl !== url) {
92
+ URL.revokeObjectURL(oldBlobUrl);
93
+ }
94
+ blobUrlRef.current = newBlobUrl;
95
+ blobUrlForUrlRef.current = url;
96
+ setBlobUrl(newBlobUrl);
97
+ } else {
98
+ // URL changed during fetch, revoke this blob URL
99
+ URL.revokeObjectURL(newBlobUrl);
100
+ }
63
101
  } catch (error) {
64
102
  console.error('Error fetching protected image:', error);
65
- // On error, fallback to original URL (might show broken image, but won't crash)
66
- setBlobUrl(null);
103
+ // On error, only clear if URL hasn't changed
104
+ if (previousUrlRef.current === url) {
105
+ setBlobUrl(null);
106
+ }
67
107
  }
68
108
  };
69
109
 
70
110
  fetchProtectedImage();
71
111
 
72
- // Cleanup function
112
+ // Cleanup function - revoke blob URL on unmount
73
113
  return () => {
114
+ // On unmount, clean up the current blob URL
74
115
  if (blobUrlRef.current) {
75
116
  URL.revokeObjectURL(blobUrlRef.current);
76
117
  blobUrlRef.current = null;
118
+ blobUrlForUrlRef.current = null;
77
119
  }
78
120
  };
79
- }, [url, isProtected, getAuthHeaders]);
121
+ }, [url]); // Only depend on url, not isProtected or getAuthHeaders
80
122
 
81
123
  // Return blob URL if available, otherwise return original URL (or null)
82
124
  if (!url) {
83
125
  return null;
84
126
  }
85
127
 
86
- const isUrlProtected = typeof isProtected === 'boolean'
87
- ? isProtected
88
- : isProtected ? isProtected(url) : false;
128
+ const isUrlProtected = typeof isProtectedRef.current === 'boolean'
129
+ ? isProtectedRef.current
130
+ : isProtectedRef.current ? isProtectedRef.current(url) : false;
89
131
  return blobUrl || (!isUrlProtected ? url : null);
90
132
  };
91
133
 
package/demo.tsx DELETED
@@ -1,167 +0,0 @@
1
- import React, { useState } from 'react';
2
- import { MentionInput, ShowMessageCard } from './src';
3
-
4
- const Demo: React.FC = () => {
5
- const [messages, setMessages] = useState<any[]>([
6
- {
7
- id: 1,
8
- name: 'John Doe',
9
- date: '14/07/2025 04:15 PM',
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
- objectName: '26may_item001',
12
- revision: 'A',
13
- object_type_icon: '📄',
14
- relatedObject: 'test_jeet_july2334 (A)',
15
- },
16
- {
17
- id: 2,
18
- name: 'Mike Johnson',
19
- date: '14/07/2025 04:15 PM',
20
- comment: 'Revision A completed successfully. Ready for next phase. <span class="hashtag-highlight">#milestone</span>',
21
- objectName: '26may_item001',
22
- revision: 'A',
23
- object_type_icon: '📋',
24
- relatedObject: 'test_jeet_july2334 (A)',
25
- }
26
- ]);
27
-
28
- // Sample users for mentions
29
- const users = [
30
- { id: 1, name: 'John Doe' },
31
- { id: 2, name: 'Jane Smith' },
32
- { id: 3, name: 'Mike Johnson' },
33
- { id: 4, name: 'Sarah Wilson' },
34
- ];
35
-
36
- const handleSendMessage = (messageData: {
37
- messageText: string;
38
- messageHTML: string;
39
- userSelectListWithIds: { id: number; name: string }[];
40
- userSelectListName: string[];
41
- tags: string[];
42
- images?: File[];
43
- imageUrl?: string | null;
44
- }) => {
45
- console.log('Message Data:', messageData);
46
- console.log('Extracted Tags:', messageData.tags);
47
-
48
- // Create a new message for display
49
- const newMessage = {
50
- id: Date.now(),
51
- name: 'You',
52
- date: new Date().toLocaleTimeString(),
53
- comment: messageData.messageHTML,
54
- imageUrl: messageData.imageUrl,
55
- tags: messageData.tags,
56
- mentions: messageData.userSelectListName,
57
- objectName: 'new_item001', // You can customize this or make it dynamic
58
- revision: 'A', // You can customize this or make it dynamic
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
61
- };
62
-
63
- setMessages([...messages, newMessage]);
64
- };
65
-
66
- return (
67
- <div style={{ maxWidth: '600px', margin: '20px auto', padding: '20px' }}>
68
- <h1>React Mention Input with Hashtag Support</h1>
69
-
70
- <div style={{ marginBottom: '20px' }}>
71
- <h3>Features:</h3>
72
- <ul>
73
- <li>Type <strong>@</strong> to mention users (e.g., @John Doe)</li>
74
- <li>Type <strong>#</strong> to create hashtags (e.g., #urgent #review #milestone)</li>
75
- <li>Links are automatically detected and highlighted</li>
76
- <li>Hashtags are extracted and returned in the tags array</li>
77
- <li><strong>Custom Object Chip</strong> rendering with objectChipRender prop</li>
78
- <li><strong>Object Type Icons</strong> for visual identification</li>
79
- </ul>
80
- </div>
81
-
82
- <div style={{ marginBottom: '20px' }}>
83
- <MentionInput
84
- users={users}
85
- placeholder="Type @ to mention and inform someone"
86
- onSendMessage={handleSendMessage}
87
- suggestionPosition="bottom"
88
- />
89
- </div>
90
-
91
- <div>
92
- <h3>Messages (Default Object Chip):</h3>
93
- <ShowMessageCard data={messages} />
94
- </div>
95
-
96
- <div style={{ marginTop: '30px' }}>
97
- <h3>Messages (Custom Object Chip):</h3>
98
- <ShowMessageCard
99
- data={messages}
100
- objectChipRender={({ objectName, revision, objectTypeIcon, item }) => (
101
- <div style={{
102
- backgroundColor: '#007bff',
103
- color: 'white',
104
- padding: '6px 12px',
105
- borderRadius: '20px',
106
- fontSize: '12px',
107
- fontWeight: '600',
108
- boxShadow: '0 2px 4px rgba(0,123,255,0.3)',
109
- display: 'flex',
110
- alignItems: 'center',
111
- gap: '4px'
112
- }}>
113
- {objectTypeIcon && <span>{objectTypeIcon}</span>}
114
- {objectName && <span>{objectName}</span>}
115
- {revision && <span style={{ opacity: 0.8 }}> v{revision}</span>}
116
- </div>
117
- )}
118
- />
119
- </div>
120
-
121
- <div style={{ marginTop: '20px', padding: '15px', backgroundColor: '#f5f5f5', borderRadius: '8px' }}>
122
- <h4>Example Usage:</h4>
123
- <p>Try typing these examples:</p>
124
- <ul>
125
- <li>"Project update complete. Ready for @John Doe review #milestone #completed"</li>
126
- <li>"Need urgent help with deployment @Jane Smith @Mike Johnson #urgent #deployment #help"</li>
127
- <li>"Meeting scheduled for tomorrow #meeting #planning"</li>
128
- </ul>
129
-
130
- <h4 style={{ marginTop: '20px' }}>objectChipRender Example:</h4>
131
- <pre style={{ backgroundColor: '#2d3748', color: '#e2e8f0', padding: '12px', borderRadius: '6px', fontSize: '12px', overflow: 'auto' }}>
132
- {`<ShowMessageCard
133
- data={messages}
134
- objectChipRender={({ objectName, revision, objectTypeIcon, item }) => (
135
- <div style={{
136
- backgroundColor: '#007bff',
137
- color: 'white',
138
- padding: '6px 12px',
139
- borderRadius: '20px',
140
- display: 'flex',
141
- alignItems: 'center',
142
- gap: '4px'
143
- }}>
144
- {objectTypeIcon && <span>{objectTypeIcon}</span>}
145
- {objectName} v{revision}
146
- </div>
147
- )}
148
- />`}
149
- </pre>
150
-
151
- <h4 style={{ marginTop: '20px' }}>Data Structure with Icon:</h4>
152
- <pre style={{ backgroundColor: '#2d3748', color: '#e2e8f0', padding: '12px', borderRadius: '6px', fontSize: '12px', overflow: 'auto' }}>
153
- {`const messageData = {
154
- name: 'John Doe',
155
- objectName: '26may_item001',
156
- revision: 'A',
157
- object_type_icon: '📄', // Document icon
158
- relatedObject: 'test_jeet_july2334 (A)', // Related object
159
- comment: 'Message content...'
160
- };`}
161
- </pre>
162
- </div>
163
- </div>
164
- );
165
- };
166
-
167
- export default Demo;
@@ -1,38 +0,0 @@
1
- import React, { ReactNode } from "react";
2
- import "./MentionInput.css";
3
- interface User {
4
- id: number;
5
- name: string;
6
- }
7
- interface MentionInputProps {
8
- users: User[];
9
- placeholder?: string;
10
- containerClassName?: string;
11
- inputContainerClassName?: string;
12
- inputClassName?: string;
13
- sendBtnClassName?: string;
14
- suggestionListClassName?: string;
15
- suggestionItemClassName?: string;
16
- attachedImageContainerClassName?: string;
17
- attachedImageContainerStyle?: React.CSSProperties;
18
- imgClassName?: string;
19
- imgStyle?: React.CSSProperties;
20
- sendButtonIcon?: ReactNode;
21
- attachmentButtonIcon?: ReactNode;
22
- onSendMessage?: (obj: {
23
- messageText: string;
24
- messageHTML: string;
25
- userSelectListWithIds: {
26
- id: number;
27
- name: string;
28
- }[];
29
- userSelectListName: string[];
30
- tags: string[];
31
- images?: File[];
32
- imageUrl?: string | null;
33
- }) => void;
34
- suggestionPosition?: 'top' | 'bottom' | 'left' | 'right';
35
- onImageUpload?: (file: File) => Promise<string>;
36
- }
37
- declare const MentionInput: React.FC<MentionInputProps>;
38
- export default MentionInput;
@@ -1,376 +0,0 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- var __generator = (this && this.__generator) || function (thisArg, body) {
11
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
12
- return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
13
- function verb(n) { return function (v) { return step([n, v]); }; }
14
- function step(op) {
15
- if (f) throw new TypeError("Generator is already executing.");
16
- while (g && (g = 0, op[0] && (_ = 0)), _) try {
17
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
18
- if (y = 0, t) op = [op[0] & 2, t.value];
19
- switch (op[0]) {
20
- case 0: case 1: t = op; break;
21
- case 4: _.label++; return { value: op[1], done: false };
22
- case 5: _.label++; y = op[1]; op = [0]; continue;
23
- case 7: op = _.ops.pop(); _.trys.pop(); continue;
24
- default:
25
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
26
- if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
27
- if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
28
- if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
29
- if (t[2]) _.ops.pop();
30
- _.trys.pop(); continue;
31
- }
32
- op = body.call(thisArg, _);
33
- } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
34
- if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
35
- }
36
- };
37
- import React, { useState, useRef } from "react";
38
- import ReactDOM from "react-dom";
39
- import "./MentionInput.css";
40
- var MentionInput = function (_a) {
41
- var _b;
42
- var users = _a.users, _c = _a.placeholder, placeholder = _c === void 0 ? "Type a message... (or drag & drop an image)" : _c, containerClassName = _a.containerClassName, inputContainerClassName = _a.inputContainerClassName, inputClassName = _a.inputClassName, sendBtnClassName = _a.sendBtnClassName, suggestionListClassName = _a.suggestionListClassName, suggestionItemClassName = _a.suggestionItemClassName, imgClassName = _a.imgClassName, imgStyle = _a.imgStyle, attachedImageContainerClassName = _a.attachedImageContainerClassName, attachedImageContainerStyle = _a.attachedImageContainerStyle, sendButtonIcon = _a.sendButtonIcon, attachmentButtonIcon = _a.attachmentButtonIcon, onSendMessage = _a.onSendMessage, _d = _a.suggestionPosition, suggestionPosition = _d === void 0 ? 'bottom' : _d, onImageUpload = _a.onImageUpload;
43
- var _e = useState(""), inputValue = _e[0], setInputValue = _e[1]; // Plain text
44
- var _f = useState([]), suggestions = _f[0], setSuggestions = _f[1];
45
- var _g = useState(false), showSuggestions = _g[0], setShowSuggestions = _g[1];
46
- var _h = useState(null), selectedImage = _h[0], setSelectedImage = _h[1];
47
- var _j = useState(null), imageUrl = _j[0], setImageUrl = _j[1];
48
- var _k = useState(false), isUploading = _k[0], setIsUploading = _k[1];
49
- var _l = useState(false), isDraggingOver = _l[0], setIsDraggingOver = _l[1];
50
- var inputRef = useRef(null);
51
- var suggestionListRef = useRef(null);
52
- var caretOffsetRef = useRef(0);
53
- var userSelectListRef = useRef([]); // Only unique names
54
- var userSelectListWithIdsRef = useRef([]); // Unique IDs with names
55
- var tagsListRef = useRef([]); // Store hashtags
56
- var fileInputRef = useRef(null);
57
- var highlightMentionsAndLinks = function (text) {
58
- // Regular expression for detecting links
59
- var linkRegex = /(https?:\/\/[^\s]+)/g;
60
- // Regular expression for detecting hashtags
61
- var hashtagRegex = /#[\w]+/g;
62
- // Highlight links
63
- var highlightedText = text.replace(linkRegex, '<a href="$1" target="_blank" rel="noopener noreferrer" class="link-highlight">$1</a>');
64
- // Highlight hashtags
65
- highlightedText = highlightedText.replace(hashtagRegex, function (match) {
66
- return "<span class=\"hashtag-highlight\">".concat(match, "</span>");
67
- });
68
- // Highlight mentions manually based on `userSelectListRef`
69
- userSelectListRef === null || userSelectListRef === void 0 ? void 0 : userSelectListRef.current.forEach(function (userName) {
70
- var mentionPattern = new RegExp("@".concat(userName, "(\\s|$)"), "g");
71
- highlightedText = highlightedText.replace(mentionPattern, function (match) {
72
- return "<span class=\"mention-highlight\">".concat(match.trim(), "</span>&nbsp;");
73
- });
74
- });
75
- return highlightedText;
76
- };
77
- var restoreCaretPosition = function (node, caretOffset) {
78
- var range = document.createRange();
79
- var sel = window.getSelection();
80
- var charCount = 0;
81
- var findCaret = function (currentNode) {
82
- var _a;
83
- for (var _i = 0, _b = Array.from(currentNode.childNodes); _i < _b.length; _i++) {
84
- var child = _b[_i];
85
- if (child.nodeType === Node.TEXT_NODE) {
86
- var textLength = ((_a = child.textContent) === null || _a === void 0 ? void 0 : _a.length) || 0;
87
- if (charCount + textLength >= caretOffset) {
88
- range.setStart(child, caretOffset - charCount);
89
- range.collapse(true);
90
- return true;
91
- }
92
- else {
93
- charCount += textLength;
94
- }
95
- }
96
- else if (child.nodeType === Node.ELEMENT_NODE) {
97
- if (findCaret(child))
98
- return true;
99
- }
100
- }
101
- return false;
102
- };
103
- findCaret(node);
104
- if (sel) {
105
- sel.removeAllRanges();
106
- sel.addRange(range);
107
- }
108
- };
109
- var handleInputChange = function () {
110
- if (!inputRef.current)
111
- return;
112
- // Store current selection before modifications
113
- var selection = window.getSelection();
114
- var range = selection === null || selection === void 0 ? void 0 : selection.getRangeAt(0);
115
- var newCaretOffset = 0;
116
- if (range && inputRef.current.contains(range.startContainer)) {
117
- var preCaretRange = range.cloneRange();
118
- preCaretRange.selectNodeContents(inputRef.current);
119
- preCaretRange.setEnd(range.startContainer, range.startOffset);
120
- newCaretOffset = preCaretRange.toString().length;
121
- }
122
- caretOffsetRef.current = newCaretOffset;
123
- var plainText = inputRef.current.innerText;
124
- setInputValue(plainText);
125
- // Process for mention suggestions
126
- var mentionMatch = plainText.slice(0, newCaretOffset).match(/@(\S*)$/);
127
- if (mentionMatch) {
128
- var query_1 = mentionMatch[1].toLowerCase();
129
- var filteredUsers = query_1 === "" ? users : users.filter(function (user) {
130
- return user.name.toLowerCase().includes(query_1);
131
- });
132
- setSuggestions(filteredUsers);
133
- setShowSuggestions(filteredUsers.length > 0);
134
- }
135
- else {
136
- setShowSuggestions(false);
137
- }
138
- // Extract and store hashtags
139
- var hashtagMatches = plainText.match(/#[\w]+/g);
140
- if (hashtagMatches) {
141
- var uniqueTags = Array.from(new Set(hashtagMatches));
142
- tagsListRef.current = uniqueTags;
143
- }
144
- else {
145
- tagsListRef.current = [];
146
- }
147
- // Only apply highlighting if we have mentions, hashtags, or links to highlight
148
- if (userSelectListRef.current.length > 0 || plainText.match(/(https?:\/\/[^\s]+)/g) || plainText.match(/#[\w]+/g)) {
149
- var currentHTML = inputRef.current.innerHTML;
150
- var htmlWithHighlights = highlightMentionsAndLinks(plainText);
151
- // Only update if the highlighted HTML is different to avoid cursor jumping
152
- if (currentHTML !== htmlWithHighlights) {
153
- inputRef.current.innerHTML = htmlWithHighlights;
154
- // Restore cursor position after changing innerHTML
155
- restoreCaretPosition(inputRef.current, newCaretOffset);
156
- }
157
- }
158
- };
159
- var renderSuggestions = function () {
160
- if (!showSuggestions || !inputRef.current)
161
- return null;
162
- var getInitials = function (name) {
163
- var nameParts = name.split(" ");
164
- var initials = nameParts
165
- .map(function (part) { var _a; return ((_a = part[0]) === null || _a === void 0 ? void 0 : _a.toUpperCase()) || ""; })
166
- .slice(0, 2)
167
- .join("");
168
- return initials;
169
- };
170
- var inputRect = inputRef.current.getBoundingClientRect();
171
- var styles = {
172
- position: 'absolute',
173
- zIndex: 1000,
174
- };
175
- // Use suggestionPosition prop to adjust tooltip position
176
- switch (suggestionPosition) {
177
- case 'top':
178
- styles.left = "".concat(inputRect.left, "px");
179
- styles.top = "".concat(inputRect.top - 150, "px");
180
- break;
181
- case 'bottom':
182
- styles.left = "".concat(inputRect.left, "px");
183
- styles.top = "".concat(inputRect.bottom, "px");
184
- break;
185
- case 'left':
186
- styles.left = "".concat(inputRect.left - 150, "px");
187
- styles.top = "".concat(inputRect.top, "px");
188
- break;
189
- case 'right':
190
- styles.left = "".concat(inputRect.right, "px");
191
- styles.top = "".concat(inputRect.top, "px");
192
- break;
193
- default:
194
- break;
195
- }
196
- return ReactDOM.createPortal(React.createElement("div", { className: "suggestion-container ".concat(suggestionListClassName || ''), style: styles },
197
- React.createElement("ul", { className: "suggestion-list", ref: suggestionListRef }, suggestions.map(function (user) { return (React.createElement("li", { key: user.id, onClick: function () { return handleSuggestionClick(user); }, className: "suggestion-item ".concat(suggestionItemClassName || ''), role: "option", tabIndex: 0, "aria-selected": "false" },
198
- React.createElement("div", { className: "user-icon" }, getInitials(user === null || user === void 0 ? void 0 : user.name)),
199
- React.createElement("span", { className: "user-name" }, user.name))); }))), window.document.body);
200
- };
201
- var handleSuggestionClick = function (user) {
202
- if (!inputRef.current)
203
- return;
204
- var plainText = inputValue;
205
- var caretOffset = caretOffsetRef.current;
206
- var mentionMatch = plainText.slice(0, caretOffset).match(/@(\S*)$/);
207
- if (!userSelectListRef.current.includes(user.name)) {
208
- userSelectListRef.current.push(user.name);
209
- }
210
- // Check if the ID is already stored
211
- var isIdExists = userSelectListWithIdsRef.current.some(function (item) { return item.id === user.id; });
212
- if (!isIdExists) {
213
- userSelectListWithIdsRef.current.push(user);
214
- }
215
- if (!mentionMatch)
216
- return;
217
- var mentionIndex = plainText.slice(0, caretOffset).lastIndexOf("@");
218
- // Append space after the mention
219
- var newValue = plainText.substring(0, mentionIndex + 1) + user.name + " " + plainText.substring(caretOffset);
220
- setInputValue(newValue);
221
- inputRef.current.innerText = newValue;
222
- // Highlight mentions and links with &nbsp;
223
- var htmlWithHighlights = highlightMentionsAndLinks(newValue);
224
- // Set highlighted content
225
- inputRef.current.innerHTML = htmlWithHighlights;
226
- setShowSuggestions(false);
227
- // Adjust caret position after adding the mention and space
228
- var mentionEnd = mentionIndex + user.name.length + 1;
229
- restoreCaretPosition(inputRef.current, mentionEnd + 1); // +1 for the space
230
- };
231
- var handleImageSelect = function (event) { return __awaiter(void 0, void 0, void 0, function () {
232
- var files, file;
233
- return __generator(this, function (_a) {
234
- switch (_a.label) {
235
- case 0:
236
- files = Array.from(event.target.files || []);
237
- if (!(files.length > 0)) return [3 /*break*/, 2];
238
- file = files[0];
239
- if (!file.type.startsWith('image/')) return [3 /*break*/, 2];
240
- return [4 /*yield*/, uploadImage(file)];
241
- case 1:
242
- _a.sent();
243
- _a.label = 2;
244
- case 2: return [2 /*return*/];
245
- }
246
- });
247
- }); };
248
- var handleDragOver = function (e) {
249
- e.preventDefault();
250
- e.stopPropagation();
251
- // Only set dragging if files are being dragged
252
- if (e.dataTransfer.types.includes('Files')) {
253
- setIsDraggingOver(true);
254
- }
255
- };
256
- var handleDragLeave = function (e) {
257
- e.preventDefault();
258
- e.stopPropagation();
259
- // Check if we're leaving the container, not just moving between children
260
- var rect = e.currentTarget.getBoundingClientRect();
261
- var x = e.clientX;
262
- var y = e.clientY;
263
- if (x <= rect.left ||
264
- x >= rect.right ||
265
- y <= rect.top ||
266
- y >= rect.bottom) {
267
- setIsDraggingOver(false);
268
- }
269
- };
270
- var handleDrop = function (e) { return __awaiter(void 0, void 0, void 0, function () {
271
- var files, imageFiles;
272
- return __generator(this, function (_a) {
273
- switch (_a.label) {
274
- case 0:
275
- e.preventDefault();
276
- e.stopPropagation();
277
- setIsDraggingOver(false);
278
- files = Array.from(e.dataTransfer.files);
279
- if (!(files.length > 0)) return [3 /*break*/, 2];
280
- imageFiles = files.filter(function (file) { return file.type.startsWith('image/'); });
281
- if (!(imageFiles.length > 0)) return [3 /*break*/, 2];
282
- return [4 /*yield*/, uploadImage(imageFiles[0])];
283
- case 1:
284
- _a.sent();
285
- _a.label = 2;
286
- case 2: return [2 /*return*/];
287
- }
288
- });
289
- }); };
290
- var uploadImage = function (file) { return __awaiter(void 0, void 0, void 0, function () {
291
- var url, error_1;
292
- return __generator(this, function (_a) {
293
- switch (_a.label) {
294
- case 0:
295
- if (!onImageUpload) {
296
- // If no upload function provided, store the file directly
297
- setSelectedImage(file);
298
- setImageUrl(URL.createObjectURL(file));
299
- return [2 /*return*/];
300
- }
301
- _a.label = 1;
302
- case 1:
303
- _a.trys.push([1, 3, 4, 5]);
304
- setIsUploading(true);
305
- return [4 /*yield*/, onImageUpload(file)];
306
- case 2:
307
- url = _a.sent();
308
- setSelectedImage(file);
309
- setImageUrl(url);
310
- return [3 /*break*/, 5];
311
- case 3:
312
- error_1 = _a.sent();
313
- console.error('Error uploading image:', error_1);
314
- return [3 /*break*/, 5];
315
- case 4:
316
- setIsUploading(false);
317
- return [7 /*endfinally*/];
318
- case 5: return [2 /*return*/];
319
- }
320
- });
321
- }); };
322
- var removeImage = function () {
323
- setSelectedImage(null);
324
- setImageUrl(null);
325
- };
326
- var handleSendMessage = function () {
327
- if (inputRef.current) {
328
- var messageText = inputRef.current.innerText.trim();
329
- var messageHTML = inputRef.current.innerHTML.trim();
330
- if ((messageText || selectedImage) && onSendMessage) {
331
- onSendMessage({
332
- messageText: messageText,
333
- messageHTML: messageHTML,
334
- userSelectListWithIds: userSelectListWithIdsRef.current,
335
- userSelectListName: userSelectListRef.current,
336
- tags: tagsListRef.current,
337
- images: selectedImage ? [selectedImage] : [],
338
- imageUrl: imageUrl
339
- });
340
- setInputValue("");
341
- setShowSuggestions(false);
342
- inputRef.current.innerText = "";
343
- setSelectedImage(null);
344
- setImageUrl(null);
345
- userSelectListRef.current = [];
346
- userSelectListWithIdsRef.current = [];
347
- tagsListRef.current = [];
348
- }
349
- }
350
- };
351
- var handleKeyDown = function (event) {
352
- if (event.key === "Enter" && !event.shiftKey) {
353
- event.preventDefault(); // Prevent newline in content-editable
354
- handleSendMessage(); // Trigger the same function as the Send button
355
- }
356
- };
357
- return (React.createElement("div", { className: "mention-container ".concat(containerClassName || "") },
358
- imageUrl && selectedImage && (React.createElement("div", { className: "image-preview-card ".concat(attachedImageContainerClassName || ""), style: attachedImageContainerStyle },
359
- React.createElement("img", { src: imageUrl, alt: "Preview", className: imgClassName || "", style: imgStyle }),
360
- React.createElement("button", { onClick: removeImage, className: "remove-image-btn", "aria-label": "Remove image" }, "\u00D7"))),
361
- React.createElement("div", { className: "mention-input-container ".concat(inputContainerClassName || "", " ").concat(isDraggingOver ? 'dragging-over' : ''), onDragOver: handleDragOver, onDragLeave: handleDragLeave, onDragEnd: function () { return setIsDraggingOver(false); }, onDrop: handleDrop },
362
- isDraggingOver && (React.createElement("div", { className: "drag-overlay" },
363
- React.createElement("div", { className: "drag-message" },
364
- React.createElement("span", null, "Drop to upload")))),
365
- React.createElement("button", { onClick: function () { var _a; return (_a = fileInputRef.current) === null || _a === void 0 ? void 0 : _a.click(); }, className: "attachment-button", type: "button", "aria-label": "Attach image" },
366
- React.createElement("span", { className: "attachment-icon" }, attachmentButtonIcon || "📷")),
367
- React.createElement("div", { className: "mention-input-wrapper" },
368
- (!inputValue || !inputRef.current || ((_b = inputRef.current) === null || _b === void 0 ? void 0 : _b.innerText.trim()) === "") && (React.createElement("span", { className: "placeholder" }, placeholder)),
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 || "➤"),
371
- React.createElement("input", { type: "file", ref: fileInputRef, accept: "image/*", onChange: handleImageSelect, style: { display: 'none' } }),
372
- isUploading && (React.createElement("div", { className: "upload-loading" },
373
- React.createElement("span", null, "Uploading...")))),
374
- renderSuggestions()));
375
- };
376
- export default MentionInput;
@@ -1,41 +0,0 @@
1
- import React, { CSSProperties, ReactNode } from "react";
2
- import "./ShowMessageCard.css";
3
- interface MessageCardProps {
4
- [key: string]: any;
5
- }
6
- interface ShowMessageCardProps {
7
- data: MessageCardProps[];
8
- nameKey?: string;
9
- dateKey?: string;
10
- commentKey?: string;
11
- imgSrcKey?: string;
12
- imageUrlKey?: string;
13
- objectNameKey?: string;
14
- containerClassName?: string;
15
- containerStyle?: CSSProperties;
16
- cardClassName?: string;
17
- cardStyle?: CSSProperties;
18
- headerClassName?: string;
19
- headerStyle?: CSSProperties;
20
- imgClassName?: string;
21
- imgStyle?: CSSProperties;
22
- infoClassName?: string;
23
- infoStyle?: CSSProperties;
24
- nameClassName?: string;
25
- nameStyle?: CSSProperties;
26
- dateClassName?: string;
27
- dateStyle?: CSSProperties;
28
- bodyClassName?: string;
29
- bodyStyle?: CSSProperties;
30
- commentClassName?: string;
31
- commentStyle?: CSSProperties;
32
- attachedImageClassName?: string;
33
- attachedImageStyle?: CSSProperties;
34
- attachedImageContainerClassName?: string;
35
- attachedImageContainerStyle?: CSSProperties;
36
- objectNameClassName?: string;
37
- objectNameStyle?: CSSProperties;
38
- renderItem?: (element: MessageCardProps) => ReactNode;
39
- }
40
- export declare const ShowMessageCard: React.FC<ShowMessageCardProps>;
41
- export {};
@@ -1,72 +0,0 @@
1
- var __assign = (this && this.__assign) || function () {
2
- __assign = Object.assign || function(t) {
3
- for (var s, i = 1, n = arguments.length; i < n; i++) {
4
- s = arguments[i];
5
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
6
- t[p] = s[p];
7
- }
8
- return t;
9
- };
10
- return __assign.apply(this, arguments);
11
- };
12
- import React, { useState } from "react";
13
- import "./ShowMessageCard.css";
14
- export var ShowMessageCard = function (_a) {
15
- var data = _a.data, _b = _a.nameKey, nameKey = _b === void 0 ? "name" : _b, _c = _a.dateKey, dateKey = _c === void 0 ? "date" : _c, _d = _a.commentKey, commentKey = _d === void 0 ? "comment" : _d, _e = _a.imgSrcKey, imgSrcKey = _e === void 0 ? "imgSrc" : _e, _f = _a.imageUrlKey, imageUrlKey = _f === void 0 ? "imageUrl" : _f, // Default key for attached image
16
- _g = _a.objectNameKey, // Default key for attached image
17
- objectNameKey = _g === void 0 ? "objectName" : _g, // Default key for object identifier
18
- 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, renderItem = _a.renderItem;
19
- console.log(data, "data==");
20
- // State to manage initials for images that fail to load
21
- var _h = useState({}), initialsState = _h[0], setInitialsState = _h[1];
22
- // Handle image load failure
23
- var handleImageError = function (id) {
24
- setInitialsState(function (prevState) {
25
- var _a;
26
- return (__assign(__assign({}, prevState), (_a = {}, _a[id] = true, _a)));
27
- });
28
- };
29
- // Helper function to generate initials from the name
30
- var getInitials = function (name) {
31
- var nameParts = name.split(" ");
32
- var initials = nameParts
33
- .map(function (part) { var _a; return ((_a = part[0]) === null || _a === void 0 ? void 0 : _a.toUpperCase()) || ""; }) // Take the first letter of each part
34
- .slice(0, 2) // Limit to 2 letters
35
- .join("");
36
- return initials;
37
- };
38
- // Helper function to extract hashtags and mentions from text
39
- var extractTagsAndMentions = function (text) {
40
- var plainText = text.replace(/<[^>]*>/g, ''); // Remove HTML tags to get plain text
41
- var hashtags = plainText.match(/#[\w]+/g) || [];
42
- var mentions = plainText.match(/@[\w\s-]+/g) || [];
43
- return {
44
- hashtags: Array.from(new Set(hashtags)), // Remove duplicates
45
- mentions: Array.from(new Set(mentions.map(function (mention) { return mention.trim(); }))) // Remove duplicates and trim
46
- };
47
- };
48
- return (React.createElement("div", { className: "message-card-container ".concat(containerClassName || ""), style: containerStyle }, data.map(function (item, index) {
49
- if (renderItem !== undefined) {
50
- // Use custom render function if provided
51
- return (React.createElement(React.Fragment, { key: item.id || index }, renderItem(item)));
52
- }
53
- var showInitials = initialsState[item.id || index] || !item[imgSrcKey]; // Decide whether to show initials
54
- // Extract tags and mentions from the comment
55
- var _a = extractTagsAndMentions(item[commentKey] || ''), hashtags = _a.hashtags, mentions = _a.mentions;
56
- return (React.createElement("div", { key: item.id || index, className: "message-card ".concat(cardClassName || ""), style: cardStyle },
57
- React.createElement("div", { className: "message-card-header ".concat(headerClassName || ""), style: headerStyle },
58
- React.createElement("div", { className: "message-card-header-left" },
59
- 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); } })),
60
- React.createElement("div", { className: "message-card-info ".concat(infoClassName || ""), style: infoStyle },
61
- React.createElement("h3", { className: "message-card-name ".concat(nameClassName || ""), style: nameStyle }, item[nameKey]),
62
- React.createElement("p", { className: "message-card-date ".concat(dateClassName || ""), style: dateStyle }, item[dateKey]))),
63
- item[objectNameKey] && (React.createElement("div", { className: "message-card-item-name ".concat(objectNameClassName || ""), style: objectNameStyle }, item[objectNameKey]))),
64
- React.createElement("div", { className: "message-card-body ".concat(bodyClassName || ""), style: bodyStyle },
65
- React.createElement("p", { className: "message-card-comment ".concat(commentClassName || ""), style: commentStyle, dangerouslySetInnerHTML: { __html: item[commentKey] } }),
66
- (item === null || item === void 0 ? void 0 : item[imageUrlKey]) && (React.createElement("div", { className: "message-card-attached-image-container ".concat(attachedImageContainerClassName || ""), style: attachedImageContainerStyle },
67
- React.createElement("img", { src: item[imageUrlKey], alt: "Attached", className: "message-card-attached-image ".concat(attachedImageClassName || ""), style: attachedImageStyle }))),
68
- (hashtags.length > 0 || mentions.length > 0) && (React.createElement("div", { className: "message-card-tags" },
69
- hashtags.map(function (tag, tagIndex) { return (React.createElement("span", { key: "hashtag-".concat(tagIndex), className: "tag-chip hashtag-chip" }, tag)); }),
70
- mentions.map(function (mention, mentionIndex) { return (React.createElement("span", { key: "mention-".concat(mentionIndex), className: "tag-chip mention-chip" }, mention)); }))))));
71
- })));
72
- };
@@ -1,2 +0,0 @@
1
- export { default as MentionInput } from './MentionInput';
2
- export { ShowMessageCard } from './ShowMessageCard';
package/dist/src/index.js DELETED
@@ -1,2 +0,0 @@
1
- export { default as MentionInput } from './MentionInput';
2
- export { ShowMessageCard } from './ShowMessageCard';
package/index.html DELETED
@@ -1,12 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
- <title>React Mention Input Demo</title>
7
- </head>
8
- <body>
9
- <div id="root"></div>
10
- <script type="module" src="/main.tsx"></script>
11
- </body>
12
- </html>
package/main.tsx DELETED
@@ -1,9 +0,0 @@
1
- import React from 'react'
2
- import ReactDOM from 'react-dom/client'
3
- import Demo from './demo'
4
-
5
- ReactDOM.createRoot(document.getElementById('root')!).render(
6
- <React.StrictMode>
7
- <Demo />
8
- </React.StrictMode>,
9
- )
package/tsconfig.json DELETED
@@ -1,28 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES5",
4
- "sourceMap": false,
5
- "module": "ESNext",
6
- "moduleResolution": "bundler",
7
- "jsx": "react",
8
- "lib": ["dom", "es6"],
9
- "declaration": true,
10
- "outDir": "./dist",
11
- "strict": true,
12
- "esModuleInterop": true,
13
- "allowSyntheticDefaultImports": true,
14
- "skipLibCheck": true
15
- },
16
- "include": [
17
- "src/**/*"
18
- ],
19
- "exclude": [
20
- "node_modules",
21
- "dist",
22
- "demo.tsx",
23
- "main.tsx",
24
- "vite.config.ts",
25
- "**/*.test.*",
26
- "**/*.spec.*"
27
- ]
28
- }
package/vite.config.ts DELETED
@@ -1,10 +0,0 @@
1
- import { defineConfig } from 'vite'
2
- import react from '@vitejs/plugin-react'
3
-
4
- export default defineConfig({
5
- plugins: [react()],
6
- server: {
7
- port: 3000,
8
- open: true
9
- }
10
- })