@openim/im-composer 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +37 -0
- package/LICENSE +21 -0
- package/README.md +308 -0
- package/dist/index.cjs +2603 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.css +518 -0
- package/dist/index.css.map +1 -0
- package/dist/index.d.cts +406 -0
- package/dist/index.d.ts +406 -0
- package/dist/index.js +2649 -0
- package/dist/index.js.map +1 -0
- package/package.json +84 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [1.0.0] - 2024-12-29
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **Dual Mode Support**: Plain text and Rich text (Markdown) modes
|
|
13
|
+
- **@Mentions**: Type `@` to search and mention users with customizable provider
|
|
14
|
+
- **Attachments**: Paste or drag files with image preview (plain mode)
|
|
15
|
+
- **Quote Messages**: Reply to messages with quote blocks (plain mode)
|
|
16
|
+
- **Emoji Support**: Full Unicode emoji with optional Twemoji integration
|
|
17
|
+
- **Draft Support**: Save and restore editor state with `getDraft()`/`setDraft()`
|
|
18
|
+
- **Rich Text Features**:
|
|
19
|
+
- Formatting toolbar (bold, italic, strikethrough, code)
|
|
20
|
+
- Headings (H1, H2, H3)
|
|
21
|
+
- Lists (bullet and ordered)
|
|
22
|
+
- Code blocks
|
|
23
|
+
- Block quotes
|
|
24
|
+
- Links with click-to-edit popup
|
|
25
|
+
- Image upload and embedding
|
|
26
|
+
- **i18n Support**: Customizable locale for all text labels
|
|
27
|
+
- **Keyboard Shortcuts**:
|
|
28
|
+
- Configurable send key (Enter / Ctrl+Enter / Cmd+Enter)
|
|
29
|
+
- Markdown shortcuts (e.g., `**bold**`, `# heading`)
|
|
30
|
+
- Link shortcut (Cmd/Ctrl + K)
|
|
31
|
+
- **Ref Methods**: Focus, clear, export, import, insert text, and more
|
|
32
|
+
- **TypeScript**: Full type definitions included
|
|
33
|
+
|
|
34
|
+
### Dependencies
|
|
35
|
+
|
|
36
|
+
- Built on [Lexical](https://lexical.dev/) editor framework
|
|
37
|
+
- Requires React 18+ or 19+
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 im-composer
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
# @openim/im-composer
|
|
2
|
+
|
|
3
|
+
A React IM composer component with dual mode (plain/rich) supporting @mentions, emoji, attachments, and markdown.
|
|
4
|
+
|
|
5
|
+
Built with [Lexical](https://lexical.dev/) editor framework.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @openim/im-composer
|
|
11
|
+
# or
|
|
12
|
+
pnpm add @openim/im-composer
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
**Note:** Requires React 18+ or React 19+ as peer dependencies.
|
|
16
|
+
|
|
17
|
+
## Quick Start
|
|
18
|
+
|
|
19
|
+
```tsx
|
|
20
|
+
import { IMComposer, IMComposerRef } from '@openim/im-composer';
|
|
21
|
+
import '@openim/im-composer/styles.css';
|
|
22
|
+
|
|
23
|
+
function Chat() {
|
|
24
|
+
const composerRef = useRef<IMComposerRef>(null);
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<IMComposer
|
|
28
|
+
ref={composerRef}
|
|
29
|
+
mode="plain"
|
|
30
|
+
placeholder="Type a message..."
|
|
31
|
+
onSend={(payload) => {
|
|
32
|
+
console.log('Sent:', payload);
|
|
33
|
+
}}
|
|
34
|
+
mentionProvider={async (query) => {
|
|
35
|
+
// Return list of users matching query
|
|
36
|
+
return [{ userId: '1', display: 'John', avatarUrl: '...' }];
|
|
37
|
+
}}
|
|
38
|
+
/>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Features
|
|
44
|
+
|
|
45
|
+
### Plain Text Mode
|
|
46
|
+
- **@Mentions** - Type `@` to search and mention users
|
|
47
|
+
- **Attachments** - Paste or drag files with preview
|
|
48
|
+
- **Quote Messages** - Reply to messages with quote blocks
|
|
49
|
+
- **Emoji** - Full Unicode emoji support
|
|
50
|
+
- **Draft Support** - Save and restore editor state
|
|
51
|
+
|
|
52
|
+
### Rich Text Mode (Markdown)
|
|
53
|
+
- **Formatting Toolbar** - Bold, italic, strikethrough, code
|
|
54
|
+
- **Headings** - H1, H2, H3
|
|
55
|
+
- **Lists** - Bullet and ordered lists
|
|
56
|
+
- **Code Blocks** - Inline code and code blocks
|
|
57
|
+
- **Block Quotes** - Quote formatting
|
|
58
|
+
- **Links** - Insert and edit links with popup
|
|
59
|
+
- **Images** - Upload and embed images
|
|
60
|
+
|
|
61
|
+
## Props
|
|
62
|
+
|
|
63
|
+
### Basic Props
|
|
64
|
+
|
|
65
|
+
| Prop | Type | Default | Description |
|
|
66
|
+
|------|------|---------|-------------|
|
|
67
|
+
| `mode` | `'plain' \| 'rich'` | - | Controlled mode |
|
|
68
|
+
| `defaultMode` | `'plain' \| 'rich'` | `'plain'` | Default mode (uncontrolled) |
|
|
69
|
+
| `onSend` | `(payload) => void` | - | Callback when user sends message |
|
|
70
|
+
| `placeholder` | `string \| { plain?: string; rich?: string }` | - | Placeholder text |
|
|
71
|
+
| `disabled` | `boolean` | `false` | Disable the editor |
|
|
72
|
+
| `className` | `string` | - | Custom class name |
|
|
73
|
+
| `onChange` | `() => void` | - | Callback on content change |
|
|
74
|
+
|
|
75
|
+
### Mention Options (Plain Mode)
|
|
76
|
+
|
|
77
|
+
| Prop | Type | Default | Description |
|
|
78
|
+
|------|------|---------|-------------|
|
|
79
|
+
| `enableMention` | `boolean` | `true` | Enable @mention feature |
|
|
80
|
+
| `mentionProvider` | `(query: string) => Promise<Member[]>` | - | Async function to search members |
|
|
81
|
+
| `maxMentions` | `number` | - | Maximum mentions allowed |
|
|
82
|
+
| `renderMentionItem` | `(props) => ReactNode` | - | Custom render for mention dropdown items |
|
|
83
|
+
|
|
84
|
+
### Attachment Options (Plain Mode)
|
|
85
|
+
|
|
86
|
+
| Prop | Type | Default | Description |
|
|
87
|
+
|------|------|---------|-------------|
|
|
88
|
+
| `enableAttachments` | `boolean` | `true` | Enable file attachments |
|
|
89
|
+
| `showAttachmentPreview` | `boolean` | `true` | Show built-in attachment preview bar |
|
|
90
|
+
| `attachmentPreviewPlacement` | `'top' \| 'bottom'` | `'bottom'` | Position of preview bar |
|
|
91
|
+
| `maxAttachments` | `number` | `10` | Maximum attachments allowed |
|
|
92
|
+
| `maxFileSize` | `number` | - | Maximum file size in bytes |
|
|
93
|
+
| `allowedMimeTypes` | `string[]` | - | Allowed MIME types |
|
|
94
|
+
| `onAttachmentLimitExceeded` | `(reason, file) => void` | - | Callback when limit exceeded |
|
|
95
|
+
| `onFilesChange` | `(attachments) => void` | - | Callback when attachments change |
|
|
96
|
+
|
|
97
|
+
### Rich Mode Options
|
|
98
|
+
|
|
99
|
+
| Prop | Type | Default | Description |
|
|
100
|
+
|------|------|---------|-------------|
|
|
101
|
+
| `uploadImage` | `(file: File) => Promise<{ url: string; alt?: string }>` | - | Image upload function |
|
|
102
|
+
| `markdownOptions.enabledSyntax` | `MarkdownSyntaxOptions` | All enabled | Enable/disable specific markdown features |
|
|
103
|
+
|
|
104
|
+
### Keymap Options
|
|
105
|
+
|
|
106
|
+
| Prop | Type | Default | Description |
|
|
107
|
+
|------|------|---------|-------------|
|
|
108
|
+
| `keymap.send` | `'enter' \| 'ctrlEnter' \| 'cmdEnter'` | `'enter'` | Key to send message |
|
|
109
|
+
|
|
110
|
+
### Other Props
|
|
111
|
+
|
|
112
|
+
| Prop | Type | Description |
|
|
113
|
+
|------|------|-------------|
|
|
114
|
+
| `onContextMenu` | `MouseEventHandler` | Right-click handler |
|
|
115
|
+
| `onQuoteRemoved` | `() => void` | Callback when quote is removed |
|
|
116
|
+
| `locale` | `IMComposerLocale` | i18n configuration |
|
|
117
|
+
|
|
118
|
+
## Ref Methods
|
|
119
|
+
|
|
120
|
+
Access via `useRef<IMComposerRef>()`:
|
|
121
|
+
|
|
122
|
+
```tsx
|
|
123
|
+
const composerRef = useRef<IMComposerRef>(null);
|
|
124
|
+
|
|
125
|
+
// Focus the editor
|
|
126
|
+
composerRef.current?.focus();
|
|
127
|
+
|
|
128
|
+
// Clear content
|
|
129
|
+
composerRef.current?.clear();
|
|
130
|
+
|
|
131
|
+
// Export payload without sending
|
|
132
|
+
const payload = composerRef.current?.exportPayload();
|
|
133
|
+
|
|
134
|
+
// Insert text at cursor
|
|
135
|
+
composerRef.current?.insertText('Hello 👋');
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### All Methods
|
|
139
|
+
|
|
140
|
+
| Method | Description |
|
|
141
|
+
|--------|-------------|
|
|
142
|
+
| `focus()` | Focus the editor |
|
|
143
|
+
| `clear()` | Clear editor content and attachments |
|
|
144
|
+
| `exportPayload()` | Export current payload without sending |
|
|
145
|
+
| `importMarkdown(markdown)` | Import markdown content (rich mode) |
|
|
146
|
+
| `getAttachments()` | Get current attachments (plain mode) |
|
|
147
|
+
| `setAttachments(attachments)` | Set attachments (plain mode) |
|
|
148
|
+
| `addFiles(files)` | Add files to attachments (plain mode) |
|
|
149
|
+
| `removeAttachment(id)` | Remove attachment by ID (plain mode) |
|
|
150
|
+
| `clearAttachments()` | Clear all attachments (plain mode) |
|
|
151
|
+
| `insertQuote(title, content)` | Insert a quote message (plain mode) |
|
|
152
|
+
| `insertMention(userId, display)` | Insert a mention (plain mode) |
|
|
153
|
+
| `getDraft()` | Get draft state for saving |
|
|
154
|
+
| `setDraft(draft)` | Restore draft state |
|
|
155
|
+
| `setText(text, mentions?)` | Set editor content from plain text |
|
|
156
|
+
| `insertText(text)` | Insert text at cursor position |
|
|
157
|
+
|
|
158
|
+
## Payload Types
|
|
159
|
+
|
|
160
|
+
### Plain Text Payload
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
type PlainMessagePayload = {
|
|
164
|
+
type: 'text';
|
|
165
|
+
plainText: string; // Text with @mentions as @{display}
|
|
166
|
+
mentions: MentionInfo[]; // Position info for each mention
|
|
167
|
+
attachments: Attachment[];
|
|
168
|
+
quote?: QuoteInfo;
|
|
169
|
+
};
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Markdown Payload
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
type MarkdownMessagePayload = {
|
|
176
|
+
type: 'markdown';
|
|
177
|
+
markdown: string; // Full markdown content
|
|
178
|
+
};
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## i18n / Localization
|
|
182
|
+
|
|
183
|
+
Customize text labels with the `locale` prop:
|
|
184
|
+
|
|
185
|
+
```tsx
|
|
186
|
+
<IMComposer
|
|
187
|
+
locale={{
|
|
188
|
+
linkDialog: {
|
|
189
|
+
textLabel: '文本',
|
|
190
|
+
urlLabel: '链接',
|
|
191
|
+
cancelButton: '取消',
|
|
192
|
+
insertButton: '插入',
|
|
193
|
+
saveButton: '保存',
|
|
194
|
+
},
|
|
195
|
+
toolbar: {
|
|
196
|
+
bold: '粗体',
|
|
197
|
+
italic: '斜体',
|
|
198
|
+
link: '插入链接',
|
|
199
|
+
image: '插入图片',
|
|
200
|
+
// ... more toolbar labels
|
|
201
|
+
},
|
|
202
|
+
}}
|
|
203
|
+
/>
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## Draft Support
|
|
207
|
+
|
|
208
|
+
Save and restore editor state for drafts:
|
|
209
|
+
|
|
210
|
+
```tsx
|
|
211
|
+
// Save draft
|
|
212
|
+
const draft = composerRef.current?.getDraft();
|
|
213
|
+
localStorage.setItem('draft', JSON.stringify(draft));
|
|
214
|
+
|
|
215
|
+
// Restore draft
|
|
216
|
+
const saved = localStorage.getItem('draft');
|
|
217
|
+
if (saved) {
|
|
218
|
+
composerRef.current?.setDraft(JSON.parse(saved));
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## Markdown Syntax Control
|
|
223
|
+
|
|
224
|
+
Enable/disable specific markdown features:
|
|
225
|
+
|
|
226
|
+
```tsx
|
|
227
|
+
<IMComposer
|
|
228
|
+
mode="rich"
|
|
229
|
+
markdownOptions={{
|
|
230
|
+
enabledSyntax: {
|
|
231
|
+
heading: true,
|
|
232
|
+
bold: true,
|
|
233
|
+
italic: true,
|
|
234
|
+
strike: true,
|
|
235
|
+
codeInline: true,
|
|
236
|
+
codeBlock: true,
|
|
237
|
+
quote: true,
|
|
238
|
+
list: true,
|
|
239
|
+
link: true,
|
|
240
|
+
image: true, // Requires uploadImage prop
|
|
241
|
+
},
|
|
242
|
+
}}
|
|
243
|
+
/>
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
## Custom Mention Item Rendering
|
|
247
|
+
|
|
248
|
+
```tsx
|
|
249
|
+
<IMComposer
|
|
250
|
+
mentionProvider={searchUsers}
|
|
251
|
+
renderMentionItem={({ member, isSelected }) => (
|
|
252
|
+
<div className={`mention-item ${isSelected ? 'selected' : ''}`}>
|
|
253
|
+
<img src={member.avatarUrl} alt="" />
|
|
254
|
+
<span>{member.display}</span>
|
|
255
|
+
</div>
|
|
256
|
+
)}
|
|
257
|
+
/>
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
## Styling
|
|
261
|
+
|
|
262
|
+
Import the default styles:
|
|
263
|
+
|
|
264
|
+
```tsx
|
|
265
|
+
import 'im-composer/styles.css';
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
Customize with CSS variables or override the classes:
|
|
269
|
+
|
|
270
|
+
```css
|
|
271
|
+
.im-composer {
|
|
272
|
+
--im-composer-border-color: #e0e0e0;
|
|
273
|
+
--im-composer-focus-color: #1890ff;
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
## Exported Types
|
|
278
|
+
|
|
279
|
+
```tsx
|
|
280
|
+
import type {
|
|
281
|
+
IMComposerProps,
|
|
282
|
+
IMComposerRef,
|
|
283
|
+
IMComposerLocale,
|
|
284
|
+
PlainMessagePayload,
|
|
285
|
+
MarkdownMessagePayload,
|
|
286
|
+
MessagePayload,
|
|
287
|
+
Member,
|
|
288
|
+
MentionInfo,
|
|
289
|
+
Attachment,
|
|
290
|
+
QuoteInfo,
|
|
291
|
+
ComposerMode,
|
|
292
|
+
UploadImageFn,
|
|
293
|
+
UploadImageResult,
|
|
294
|
+
MarkdownSyntaxOptions,
|
|
295
|
+
SendKey,
|
|
296
|
+
} from 'im-composer';
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
## License
|
|
300
|
+
|
|
301
|
+
This package is licensed under the MIT License.
|
|
302
|
+
|
|
303
|
+
## Note on Emoji Rendering
|
|
304
|
+
|
|
305
|
+
This package uses CSS font-family declarations for emoji rendering. For consistent emoji display across platforms:
|
|
306
|
+
|
|
307
|
+
1. Include an emoji font (like Twemoji) in your project
|
|
308
|
+
2. If using Twemoji graphics, ensure proper attribution per CC BY 4.0 license
|