@openim/im-composer 1.0.0 → 1.0.2

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/dist/index.d.ts CHANGED
@@ -1,14 +1,16 @@
1
- import * as react from 'react';
2
- import { ReactNode } from 'react';
3
- import { DecoratorNode, NodeKey, EditorConfig, DOMExportOutput, DOMConversionMap, Spread, SerializedLexicalNode, LexicalNode, LexicalEditor } from 'lexical';
1
+ import * as React$1 from 'react';
2
+ import React__default, { MouseEventHandler, ReactNode } from 'react';
3
+ import { Editor, useEditor } from '@tiptap/react';
4
+ import * as react_jsx_runtime from 'react/jsx-runtime';
5
+ import { Editor as Editor$1 } from '@tiptap/core';
4
6
 
5
7
  /**
6
- * Attachment type for files added in plain mode
8
+ * Represents a file attachment in plain mode
7
9
  */
8
- type Attachment = {
10
+ interface Attachment {
9
11
  /** Unique identifier generated by the component */
10
12
  id: string;
11
- /** Original File object for upload/send */
13
+ /** Original File object */
12
14
  file: File;
13
15
  /** File name */
14
16
  name: string;
@@ -16,391 +18,600 @@ type Attachment = {
16
18
  size: number;
17
19
  /** MIME type */
18
20
  mime: string;
19
- /** Last modified timestamp */
21
+ /** File last modified timestamp */
20
22
  lastModified?: number;
21
- /** Preview URL (objectURL) for display */
23
+ /** Preview URL for images (objectURL) */
22
24
  previewUrl?: string;
23
- };
25
+ }
24
26
  /**
25
- * Mention info in the message
27
+ * Information about a mention in the message
26
28
  */
27
- type MentionInfo = {
28
- /** User ID of the mentioned member */
29
+ interface MentionInfo {
30
+ /** User ID */
29
31
  userId: string;
30
- /** Display name shown in the text */
32
+ /** Display name */
31
33
  display: string;
32
- /** Start index (UTF-16, inclusive) */
34
+ /** Start index in plainText (UTF-16, inclusive) */
33
35
  start: number;
34
- /** End index (UTF-16, exclusive) */
36
+ /** End index in plainText (UTF-16, exclusive) */
35
37
  end: number;
36
- };
38
+ }
39
+ /**
40
+ * Member data for mention suggestions
41
+ */
42
+ interface Member {
43
+ /** Unique user identifier */
44
+ userId: string;
45
+ /** Display name shown in the editor */
46
+ display: string;
47
+ /** Optional avatar URL */
48
+ avatarUrl?: string;
49
+ }
37
50
  /**
38
- * Quote information
51
+ * Quoted message information
39
52
  */
40
- type QuoteInfo = {
41
- /** Title (e.g., "Reply Name:") */
53
+ interface QuoteInfo {
54
+ /** Quote title, e.g., "Reply to Alice:" */
42
55
  title: string;
43
- /** Content of the quote */
56
+ /** Quoted content */
44
57
  content: string;
45
- };
58
+ }
46
59
  /**
47
- * Locale/i18n configuration for the composer
60
+ * Result from image upload handler
48
61
  */
49
- type IMComposerLocale = {
50
- /** Link dialog labels */
51
- linkDialog?: {
52
- textLabel?: string;
53
- urlLabel?: string;
54
- cancelButton?: string;
55
- insertButton?: string;
56
- saveButton?: string;
57
- };
58
- /** Toolbar button titles */
59
- toolbar?: {
60
- bold?: string;
61
- italic?: string;
62
- strikethrough?: string;
63
- code?: string;
64
- heading1?: string;
65
- heading2?: string;
66
- heading3?: string;
67
- bulletList?: string;
68
- orderedList?: string;
69
- quote?: string;
70
- codeBlock?: string;
71
- link?: string;
72
- image?: string;
73
- };
74
- };
62
+ interface UploadImageResult {
63
+ /** URL of the uploaded image */
64
+ url: string;
65
+ /** Optional alt text */
66
+ alt?: string;
67
+ }
68
+ /**
69
+ * Progress callback for image upload
70
+ */
71
+ interface UploadProgressEvent {
72
+ /** Upload progress percentage (0-100) */
73
+ progress: number;
74
+ }
75
+ /**
76
+ * Image upload function type with optional progress callback
77
+ */
78
+ type UploadImageFn = (file: File, onProgress?: (event: UploadProgressEvent) => void) => Promise<UploadImageResult>;
75
79
  /**
76
80
  * Payload for plain text mode messages
77
81
  */
78
- type PlainMessagePayload = {
82
+ interface PlainMessagePayload {
79
83
  type: 'text';
80
- /** Plain text with @mentions as @{display} */
84
+ /** Plain text with mentions as @userId */
81
85
  plainText: string;
82
- /** List of mentions with positions */
86
+ /** List of mentions with their positions */
83
87
  mentions: MentionInfo[];
84
- /** Attached files */
88
+ /** List of attached files */
85
89
  attachments: Attachment[];
86
- /** Optional quote message */
90
+ /** Quoted message (if any) */
87
91
  quote?: QuoteInfo;
88
- };
92
+ }
89
93
  /**
90
- * Payload for rich text (markdown) mode messages
94
+ * Payload for rich text mode messages (Markdown)
91
95
  */
92
- type MarkdownMessagePayload = {
96
+ interface MarkdownMessagePayload {
93
97
  type: 'markdown';
94
98
  /** Markdown content */
95
99
  markdown: string;
96
- };
100
+ }
97
101
  /**
98
102
  * Union type for all message payloads
99
103
  */
100
104
  type MessagePayload = PlainMessagePayload | MarkdownMessagePayload;
101
105
  /**
102
- * Member info for mentions
106
+ * Draft state for saving/restoring editor content
103
107
  */
104
- type Member = {
105
- /** Unique user ID */
106
- userId: string;
107
- /** Display name */
108
- display: string;
109
- /** Optional avatar URL */
110
- avatarUrl?: string;
111
- };
108
+ interface ComposerDraft {
109
+ /** Editor mode */
110
+ mode?: EditorMode;
111
+ /** Serialized editor state (JSON string from getJSON) - deprecated, use json */
112
+ editorState?: string;
113
+ /** Editor JSON content */
114
+ json?: Record<string, unknown>;
115
+ /** Attachments (plain mode only) */
116
+ attachments?: Attachment[];
117
+ /** Quick restore text for plain mode */
118
+ text?: string;
119
+ /** Quote information (plain mode only) */
120
+ quote?: QuoteInfo;
121
+ }
112
122
  /**
113
- * Composer mode
123
+ * Locale strings for internationalization
114
124
  */
115
- type ComposerMode = 'plain' | 'rich';
125
+ interface IMComposerLocale {
126
+ /** Placeholder text for plain mode */
127
+ placeholderPlain?: string;
128
+ /** Placeholder text for rich mode */
129
+ placeholderRich?: string;
130
+ /** No results found in mention list */
131
+ mentionNoResults?: string;
132
+ /** Loading text for mention list */
133
+ mentionLoading?: string;
134
+ /** Error text for mention list */
135
+ mentionError?: string;
136
+ /** Remove attachment button label */
137
+ removeAttachment?: string;
138
+ /** Remove quote button label */
139
+ removeQuote?: string;
140
+ /** Upload failed message */
141
+ uploadFailed?: string;
142
+ /** Uploading text */
143
+ uploading?: string;
144
+ /** Undo button */
145
+ undo?: string;
146
+ /** Redo button */
147
+ redo?: string;
148
+ /** Heading dropdown */
149
+ heading?: string;
150
+ /** Heading 1 */
151
+ heading1?: string;
152
+ /** Heading 2 */
153
+ heading2?: string;
154
+ /** Heading 3 */
155
+ heading3?: string;
156
+ /** Heading 4 */
157
+ heading4?: string;
158
+ /** Paragraph */
159
+ paragraph?: string;
160
+ /** List dropdown */
161
+ list?: string;
162
+ /** Bullet list */
163
+ bulletList?: string;
164
+ /** Ordered list */
165
+ orderedList?: string;
166
+ /** Task list */
167
+ taskList?: string;
168
+ /** Blockquote button */
169
+ blockquote?: string;
170
+ /** Code block button */
171
+ codeBlock?: string;
172
+ /** Bold button */
173
+ bold?: string;
174
+ /** Italic button */
175
+ italic?: string;
176
+ /** Strikethrough button */
177
+ strike?: string;
178
+ /** Inline code button */
179
+ code?: string;
180
+ /** Underline button */
181
+ underline?: string;
182
+ /** Highlight button */
183
+ highlight?: string;
184
+ /** Remove highlight */
185
+ removeHighlight?: string;
186
+ /** Link button */
187
+ link?: string;
188
+ /** Link input placeholder */
189
+ linkPlaceholder?: string;
190
+ /** Apply link */
191
+ applyLink?: string;
192
+ /** Open link */
193
+ openLink?: string;
194
+ /** Remove link */
195
+ removeLink?: string;
196
+ /** Superscript button */
197
+ superscript?: string;
198
+ /** Subscript button */
199
+ subscript?: string;
200
+ /** Align left button */
201
+ alignLeft?: string;
202
+ /** Align center button */
203
+ alignCenter?: string;
204
+ /** Align right button */
205
+ alignRight?: string;
206
+ /** Align justify button */
207
+ alignJustify?: string;
208
+ /** Insert image button */
209
+ insertImage?: string;
210
+ /** Upload image */
211
+ uploadImage?: string;
212
+ /** Click to upload */
213
+ clickToUpload?: string;
214
+ /** Or drag and drop */
215
+ orDragAndDrop?: string;
216
+ /** Maximum files */
217
+ maxFiles?: string;
218
+ /** Clear all */
219
+ clearAll?: string;
220
+ }
116
221
  /**
117
- * Result from image upload
222
+ * Default English locale
118
223
  */
119
- type UploadImageResult = {
120
- /** URL of the uploaded image (must be https) */
121
- url: string;
122
- /** Optional alt text */
123
- alt?: string;
124
- };
224
+ declare const defaultLocale: IMComposerLocale;
125
225
  /**
126
- * Image upload function type
226
+ * Send keymap configuration
127
227
  */
128
- type UploadImageFn = (file: File) => Promise<UploadImageResult>;
228
+ type SendKeymap = 'enter' | 'ctrlEnter' | 'cmdEnter';
129
229
  /**
130
- * Markdown syntax options
230
+ * Editor mode
131
231
  */
132
- type MarkdownSyntaxOptions = {
133
- heading?: boolean;
134
- bold?: boolean;
135
- italic?: boolean;
136
- strike?: boolean;
137
- codeInline?: boolean;
138
- codeBlock?: boolean;
139
- quote?: boolean;
140
- list?: boolean;
141
- link?: boolean;
142
- image?: boolean;
143
- };
232
+ type EditorMode = 'plain' | 'rich';
144
233
  /**
145
- * Keymap send key options
234
+ * Attachment limit exceeded reason
146
235
  */
147
- type SendKey = 'enter' | 'ctrlEnter' | 'cmdEnter';
236
+ type AttachmentLimitReason = 'count' | 'size' | 'mime';
148
237
  /**
149
- * Props for IMComposer component
238
+ * Main component props
150
239
  */
151
- type IMComposerProps = {
240
+ interface IMComposerProps {
152
241
  /** Controlled mode */
153
- mode?: ComposerMode;
242
+ mode?: EditorMode;
154
243
  /** Default mode for uncontrolled usage */
155
- defaultMode?: ComposerMode;
156
- /** Callback when user sends a message */
244
+ defaultMode?: EditorMode;
245
+ /** Called when user triggers send action */
157
246
  onSend?: (payload: PlainMessagePayload | MarkdownMessagePayload) => void;
158
- /** Enable @mention feature (default: true, plain mode only) */
247
+ /** Called when editor content changes */
248
+ onChange?: () => void;
249
+ /** Context menu handler */
250
+ onContextMenu?: MouseEventHandler<HTMLDivElement>;
251
+ /** Called when quote is removed */
252
+ onQuoteRemoved?: () => void;
253
+ /** Enable @mention feature */
159
254
  enableMention?: boolean;
160
- /** Async function to search members for mention */
255
+ /** Async provider for mention suggestions */
161
256
  mentionProvider?: (query: string) => Promise<Member[]>;
162
- /** Maximum number of mentions allowed (plain mode only) */
257
+ /** Maximum number of mentions allowed */
163
258
  maxMentions?: number;
164
- /** Custom render function for mention list items in dropdown */
259
+ /** Custom render function for mention list items */
165
260
  renderMentionItem?: (props: {
166
261
  member: Member;
167
262
  isSelected: boolean;
168
- }) => React.ReactNode;
169
- /** Enable file attachments (default: true, plain mode only) */
263
+ }) => ReactNode;
264
+ /** Mention list placement relative to cursor: 'top' or 'bottom' */
265
+ mentionPlacement?: 'top' | 'bottom';
266
+ /** Enable file attachments */
170
267
  enableAttachments?: boolean;
171
- /** Position of attachment preview bar (default: 'bottom') */
268
+ /** Attachment preview bar placement */
172
269
  attachmentPreviewPlacement?: 'top' | 'bottom';
173
- /** Maximum number of attachments (default: 10) */
270
+ /** Maximum number of attachments */
174
271
  maxAttachments?: number;
175
- /** Allowed MIME types (default: all) */
272
+ /** Allowed MIME types (supports wildcards like "image/*") */
176
273
  allowedMimeTypes?: string[];
177
274
  /** Maximum file size in bytes */
178
275
  maxFileSize?: number;
179
- /** Callback when attachment limit is exceeded */
180
- onAttachmentLimitExceeded?: (reason: 'count' | 'size' | 'mime', file: File) => void;
181
- /** Callback when attachments change (for external file list rendering) */
276
+ /** Called when attachment limit is exceeded */
277
+ onAttachmentLimitExceeded?: (reason: AttachmentLimitReason, file: File) => void;
278
+ /** Called when attachments change */
182
279
  onFilesChange?: (attachments: Attachment[]) => void;
183
- /** Show built-in attachment preview bar (default: true, set to false for custom UI) */
280
+ /** Show attachment preview bar */
184
281
  showAttachmentPreview?: boolean;
185
- /** Markdown syntax options */
282
+ /** Markdown options */
186
283
  markdownOptions?: {
187
- enabledSyntax?: MarkdownSyntaxOptions;
284
+ enabledSyntax?: string[];
188
285
  };
189
- /** Image upload function (required for image button in rich mode) */
286
+ /** Image upload handler with optional progress callback */
190
287
  uploadImage?: UploadImageFn;
191
288
  /** Keymap configuration */
192
289
  keymap?: {
193
- send?: SendKey;
290
+ send?: SendKeymap;
194
291
  };
195
- /** Placeholder text */
292
+ /** Placeholder text (string or per-mode object) */
196
293
  placeholder?: string | {
197
294
  plain?: string;
198
295
  rich?: string;
199
296
  };
200
297
  /** Disable the editor */
201
298
  disabled?: boolean;
202
- /** Custom class name */
299
+ /** Additional CSS class */
203
300
  className?: string;
204
- /** Mouse event handler for context menu (right click) */
205
- onContextMenu?: React.MouseEventHandler<HTMLDivElement>;
206
- /** Callback when quote is removed (plain mode) */
207
- onQuoteRemoved?: () => void;
208
- /** Callback when editor content changes */
209
- onChange?: () => void;
210
- /** Locale/i18n configuration */
301
+ /** Locale strings */
211
302
  locale?: IMComposerLocale;
212
- };
303
+ }
213
304
  /**
214
305
  * Methods exposed via ref
215
306
  */
216
- type IMComposerRef = {
307
+ interface IMComposerRef {
217
308
  /** Focus the editor */
218
309
  focus: () => void;
219
- /** Clear editor content and attachments */
310
+ /** Clear the editor content */
220
311
  clear: () => void;
221
- /** Export current payload without sending */
312
+ /** Export current content as payload. Returns null if empty or uploading */
222
313
  exportPayload: () => PlainMessagePayload | MarkdownMessagePayload | null;
223
314
  /** Import markdown content (rich mode only) */
224
315
  importMarkdown: (markdown: string) => void;
225
- /** Get current attachments (plain mode) */
316
+ /** Get current attachments */
226
317
  getAttachments: () => Attachment[];
227
- /** Set attachments (plain mode) */
318
+ /** Set attachments */
228
319
  setAttachments: (attachments: Attachment[]) => void;
229
- /** Insert a quote message (plain mode) */
230
- insertQuote: (title: string, content: string) => void;
231
- /** Add files to attachments (plain mode) */
320
+ /** Add files to attachments */
232
321
  addFiles: (files: FileList | File[]) => void;
233
- /** Remove an attachment by ID (plain mode) */
322
+ /** Remove a specific attachment by ID */
234
323
  removeAttachment: (id: string) => void;
235
- /** Clear all attachments (plain mode) */
324
+ /** Clear all attachments */
236
325
  clearAttachments: () => void;
237
- /** Insert a mention element (plain mode) */
326
+ /** Insert or replace a quote */
327
+ insertQuote: (title: string, content: string) => void;
328
+ /** Programmatically insert a mention */
238
329
  insertMention: (userId: string, display: string) => void;
239
- /** Get complete draft state (editor content + attachments + text, for saving) */
240
- getDraft: () => {
241
- editorState: string;
242
- attachments: Attachment[];
243
- text: string;
244
- };
245
- /** Set complete draft state (restore from saved draft) */
246
- setDraft: (draft: {
247
- editorState: string;
248
- attachments?: Attachment[];
249
- }) => void;
250
- /** Set editor content from plain text and optional mentions (plain mode) */
330
+ /** Get current draft state */
331
+ getDraft: () => ComposerDraft;
332
+ /** Restore from draft state */
333
+ setDraft: (draft: ComposerDraft) => void;
334
+ /** Set text content (with optional mentions for plain mode) */
251
335
  setText: (text: string, mentions?: Member[]) => void;
252
- /** Insert text at cursor position (useful for emoji insertion) */
336
+ /** Insert text at cursor */
253
337
  insertText: (text: string) => void;
254
- };
338
+ }
339
+ /**
340
+ * @internal Mention suggestion state
341
+ */
342
+ interface MentionSuggestionState {
343
+ active: boolean;
344
+ query: string;
345
+ items: Member[];
346
+ selectedIndex: number;
347
+ loading: boolean;
348
+ error: boolean;
349
+ /** Command to insert a mention (replaces @ trigger) */
350
+ command: ((member: {
351
+ userId: string;
352
+ display: string;
353
+ }) => void) | null;
354
+ }
255
355
 
256
- declare const IMComposer: react.ForwardRefExoticComponent<IMComposerProps & react.RefAttributes<IMComposerRef>>;
356
+ /**
357
+ * IM Composer component supporting plain text and rich text modes.
358
+ */
359
+ declare const IMComposer: React__default.ForwardRefExoticComponent<IMComposerProps & React__default.RefAttributes<IMComposerRef>>;
257
360
 
258
- type SerializedMentionNode = Spread<{
259
- userId: string;
260
- display: string;
261
- }, SerializedLexicalNode>;
262
- declare class MentionNode extends DecoratorNode<ReactNode> {
263
- __userId: string;
264
- __display: string;
265
- static getType(): string;
266
- static clone(node: MentionNode): MentionNode;
267
- constructor(userId: string, display: string, key?: NodeKey);
268
- createDOM(config: EditorConfig): HTMLElement;
269
- updateDOM(): boolean;
270
- exportDOM(): DOMExportOutput;
271
- static importDOM(): DOMConversionMap | null;
272
- static importJSON(serializedNode: SerializedMentionNode): MentionNode;
273
- exportJSON(): SerializedMentionNode;
274
- getUserId(): string;
275
- getDisplay(): string;
276
- getTextContent(): string;
277
- isIsolated(): boolean;
278
- isInline(): boolean;
279
- canInsertTextBefore(): boolean;
280
- canInsertTextAfter(): boolean;
281
- decorate(): ReactNode;
361
+ interface RichEditorProps {
362
+ placeholder?: string;
363
+ disabled?: boolean;
364
+ uploadImage?: UploadImageFn;
365
+ onUploadingChange?: (count: number) => void;
366
+ onSend?: () => void;
367
+ onChange?: () => void;
368
+ sendKeymap?: 'enter' | 'ctrlEnter' | 'cmdEnter';
369
+ }
370
+ interface RichEditorRef {
371
+ editor: Editor | null;
372
+ focus: () => void;
373
+ clear: () => void;
374
+ exportPayload: () => MarkdownMessagePayload | null;
375
+ importMarkdown: (markdown: string) => void;
376
+ getDraft: () => ComposerDraft;
377
+ setDraft: (draft: ComposerDraft) => void;
378
+ setText: (text: string) => void;
379
+ insertText: (text: string) => void;
380
+ isUploading: () => boolean;
282
381
  }
283
- declare function $createMentionNode(userId: string, display: string): MentionNode;
284
- declare function $isMentionNode(node: LexicalNode | null | undefined): node is MentionNode;
382
+ declare const RichEditor: React$1.ForwardRefExoticComponent<RichEditorProps & React$1.RefAttributes<RichEditorRef>>;
285
383
 
286
- type SerializedImageNode = Spread<{
287
- src: string;
288
- alt: string;
289
- width?: number;
290
- height?: number;
291
- }, SerializedLexicalNode>;
292
- declare class ImageNode extends DecoratorNode<ReactNode> {
293
- __src: string;
294
- __alt: string;
295
- __width?: number;
296
- __height?: number;
297
- static getType(): string;
298
- static clone(node: ImageNode): ImageNode;
299
- constructor(src: string, alt: string, width?: number, height?: number, key?: NodeKey);
300
- createDOM(config: EditorConfig): HTMLElement;
301
- updateDOM(): boolean;
302
- exportDOM(editor: LexicalEditor): DOMExportOutput;
303
- static importDOM(): DOMConversionMap | null;
304
- static importJSON(serializedNode: SerializedImageNode): ImageNode;
305
- exportJSON(): SerializedImageNode;
306
- getSrc(): string;
307
- getAlt(): string;
308
- getTextContent(): string;
309
- isInline(): boolean;
310
- decorate(): ReactNode;
384
+ declare function LocaleProvider({ locale, children, }: {
385
+ locale?: IMComposerLocale;
386
+ children: React.ReactNode;
387
+ }): react_jsx_runtime.JSX.Element;
388
+ declare function useLocale(): IMComposerLocale;
389
+
390
+ interface MentionListProps {
391
+ /** List of member suggestions */
392
+ items: Member[];
393
+ /** Currently selected index */
394
+ selectedIndex: number;
395
+ /** Loading state */
396
+ loading: boolean;
397
+ /** Error state */
398
+ error: boolean;
399
+ /** Called when item is clicked */
400
+ onSelect: (member: Member) => void;
401
+ /** Called when mouse enters an item */
402
+ onHover: (index: number) => void;
403
+ /** Custom render function */
404
+ renderItem?: (props: {
405
+ member: Member;
406
+ isSelected: boolean;
407
+ }) => React__default.ReactNode;
408
+ /** Locale strings */
409
+ locale?: {
410
+ noResults?: string;
411
+ loading?: string;
412
+ error?: string;
413
+ };
311
414
  }
312
- declare function $createImageNode(src: string, alt?: string, width?: number, height?: number): ImageNode;
313
- declare function $isImageNode(node: LexicalNode | null | undefined): node is ImageNode;
415
+ /**
416
+ * Mention suggestion list component.
417
+ */
418
+ declare function MentionList({ items, selectedIndex, loading, error, onSelect, onHover, renderItem, locale, }: MentionListProps): react_jsx_runtime.JSX.Element | null;
314
419
 
315
- type SerializedEmojiNode = Spread<{
316
- emoji: string;
317
- }, SerializedLexicalNode>;
318
- declare class EmojiNode extends DecoratorNode<ReactNode> {
319
- __emoji: string;
320
- static getType(): string;
321
- static clone(node: EmojiNode): EmojiNode;
322
- constructor(emoji: string, key?: NodeKey);
323
- createDOM(config: EditorConfig): HTMLElement;
324
- updateDOM(): boolean;
325
- exportDOM(): DOMExportOutput;
326
- static importDOM(): DOMConversionMap | null;
327
- static importJSON(serializedNode: SerializedEmojiNode): EmojiNode;
328
- exportJSON(): SerializedEmojiNode;
329
- getEmoji(): string;
330
- getTextContent(): string;
331
- isIsolated(): boolean;
332
- isInline(): boolean;
333
- canInsertTextBefore(): boolean;
334
- canInsertTextAfter(): boolean;
335
- decorate(): ReactNode;
420
+ interface AttachmentPreviewProps {
421
+ /** List of attachments */
422
+ attachments: Attachment[];
423
+ /** Called when remove button is clicked */
424
+ onRemove: (id: string) => void;
425
+ /** Placement position */
426
+ placement?: 'top' | 'bottom';
427
+ /** Remove button label */
428
+ removeLabel?: string;
336
429
  }
337
- declare function $createEmojiNode(emoji: string): EmojiNode;
338
- declare function $isEmojiNode(node: LexicalNode | null | undefined): node is EmojiNode;
430
+ /**
431
+ * Attachment preview bar component.
432
+ */
433
+ declare function AttachmentPreview({ attachments, onRemove, placement, removeLabel, }: AttachmentPreviewProps): react_jsx_runtime.JSX.Element | null;
339
434
 
340
- type SerializedQuoteNode = Spread<{
341
- title: string;
342
- content: string;
343
- }, SerializedLexicalNode>;
344
- declare class QuoteNode extends DecoratorNode<ReactNode> {
345
- __title: string;
346
- __content: string;
347
- static getType(): string;
348
- static clone(node: QuoteNode): QuoteNode;
349
- constructor(title: string, content: string, key?: NodeKey);
350
- createDOM(config: EditorConfig): HTMLElement;
351
- updateDOM(): boolean;
352
- exportDOM(): DOMExportOutput;
353
- static importDOM(): DOMConversionMap | null;
354
- static importJSON(serializedNode: SerializedQuoteNode): QuoteNode;
355
- exportJSON(): SerializedQuoteNode;
356
- getTitle(): string;
357
- getContent(): string;
358
- getTextContent(): string;
359
- isIsolated(): boolean;
360
- isInline(): boolean;
361
- decorate(): ReactNode;
435
+ interface QuoteBarProps {
436
+ /** Quote information */
437
+ quote: QuoteInfo;
438
+ /** Called when remove button is clicked */
439
+ onRemove: () => void;
440
+ /** Remove button label */
441
+ removeLabel?: string;
362
442
  }
363
- declare function $createQuoteNode(title: string, content: string): QuoteNode;
364
- declare function $isQuoteNode(node: LexicalNode | null | undefined): node is QuoteNode;
443
+ /**
444
+ * Quote message bar component.
445
+ */
446
+ declare function QuoteBar({ quote, onRemove, removeLabel }: QuoteBarProps): react_jsx_runtime.JSX.Element;
365
447
 
366
448
  interface UseAttachmentsOptions {
449
+ /** Maximum number of attachments */
367
450
  maxAttachments?: number;
451
+ /** Maximum file size in bytes */
368
452
  maxFileSize?: number;
453
+ /** Allowed MIME types */
369
454
  allowedMimeTypes?: string[];
370
- onLimitExceeded?: (reason: 'count' | 'size' | 'mime', file: File) => void;
455
+ /** Called when limit is exceeded */
456
+ onLimitExceeded?: (reason: AttachmentLimitReason, file: File) => void;
457
+ /** Called when attachments change */
458
+ onChange?: (attachments: Attachment[]) => void;
371
459
  }
372
- interface UseAttachmentsResult {
460
+ interface UseAttachmentsReturn {
461
+ /** Current attachments */
373
462
  attachments: Attachment[];
463
+ /** Add files to attachments */
374
464
  addFiles: (files: FileList | File[]) => void;
465
+ /** Remove attachment by ID */
375
466
  removeAttachment: (id: string) => void;
467
+ /** Clear all attachments */
376
468
  clearAttachments: () => void;
469
+ /** Set attachments directly */
377
470
  setAttachments: (attachments: Attachment[]) => void;
471
+ /** Get current attachments */
472
+ getAttachments: () => Attachment[];
378
473
  }
379
- declare function useAttachments(options?: UseAttachmentsOptions): UseAttachmentsResult;
474
+ /**
475
+ * Hook for managing file attachments with proper objectURL lifecycle.
476
+ */
477
+ declare function useAttachments(options?: UseAttachmentsOptions): UseAttachmentsReturn;
380
478
 
381
- interface UseImageUploadOptions {
382
- /** Image upload function */
383
- uploadImage?: UploadImageFn;
384
- /** Callback when upload starts */
385
- onUploadStart?: () => void;
386
- /** Callback when upload ends */
387
- onUploadEnd?: () => void;
388
- /** Callback when error occurs */
389
- onError?: (error: Error) => void;
479
+ interface UsePlainEditorOptions {
480
+ /** Placeholder text */
481
+ placeholder?: string;
482
+ /** Keymap for send */
483
+ sendKeymap?: SendKeymap;
484
+ /** Called when send is triggered */
485
+ onSend?: () => void;
486
+ /** Enable mention */
487
+ enableMention?: boolean;
488
+ /** Mention provider */
489
+ mentionProvider?: (query: string) => Promise<Member[]>;
490
+ /** Max mentions */
491
+ maxMentions?: number;
492
+ /** Called when mention state changes */
493
+ onMentionStateChange?: (state: MentionSuggestionState) => void;
494
+ /** Called when files are pasted */
495
+ onPasteFiles?: (files: File[]) => void;
496
+ /** Get current uploading state */
497
+ isUploading?: () => boolean;
498
+ /** Disabled state */
499
+ disabled?: boolean;
500
+ /** Called on content change */
501
+ onChange?: () => void;
502
+ /** Called when quote is removed */
503
+ onQuoteRemoved?: () => void;
390
504
  }
391
- interface UseImageUploadResult {
392
- /** Whether any upload is in progress */
393
- isUploading: boolean;
394
- /** Number of concurrent uploads */
395
- uploadCount: number;
396
- /** Upload image and get result */
397
- upload: (file: File) => Promise<{
398
- url: string;
399
- alt?: string;
400
- } | null>;
401
- /** Upload image and insert into editor */
402
- uploadAndInsert: (file: File, editor: LexicalEditor) => Promise<boolean>;
505
+ interface UsePlainEditorReturn {
506
+ /** Tiptap editor instance */
507
+ editor: ReturnType<typeof useEditor>;
508
+ /** Check if composing (IME) */
509
+ isComposing: () => boolean;
510
+ /** Check if mention list is open */
511
+ isMentionListOpen: () => boolean;
512
+ /** Export payload */
513
+ exportPayload: (attachments: Attachment[]) => PlainMessagePayload | null;
514
+ /** Get draft */
515
+ getDraft: (attachments: Attachment[]) => ComposerDraft;
516
+ /** Set draft */
517
+ setDraft: (draft: ComposerDraft) => void;
518
+ /** Insert mention programmatically */
519
+ insertMention: (userId: string, display: string) => void;
520
+ /** Insert quote */
521
+ insertQuote: (title: string, content: string) => void;
522
+ /** Remove quote */
523
+ removeQuote: () => void;
524
+ /** Get current quote */
525
+ getQuote: () => QuoteInfo | undefined;
526
+ /** Set text content */
527
+ setText: (text: string) => void;
528
+ /** Insert text at cursor */
529
+ insertText: (text: string) => void;
530
+ /** Clear editor */
531
+ clear: () => void;
532
+ /** Focus editor */
533
+ focus: () => void;
403
534
  }
404
- declare function useImageUpload(options?: UseImageUploadOptions): UseImageUploadResult;
535
+ /**
536
+ * Hook for managing plain text editor.
537
+ */
538
+ declare function usePlainEditor(options?: UsePlainEditorOptions): UsePlainEditorReturn;
539
+
540
+ /**
541
+ * Extract plain text and mention information from the editor.
542
+ * Mention tokens are output as @{userId} followed by a space.
543
+ *
544
+ * @param editor Tiptap editor instance
545
+ * @returns Object containing plainText and mentions array with UTF-16 indices
546
+ */
547
+ declare function extractPlainTextWithMentions(editor: Editor$1): {
548
+ plainText: string;
549
+ mentions: MentionInfo[];
550
+ };
551
+ /**
552
+ * Check if mention indices are valid and aligned with the plainText.
553
+ */
554
+ declare function validateMentionIndices(plainText: string, mentions: MentionInfo[]): boolean;
555
+ /**
556
+ * Create a mention info object with calculated indices.
557
+ */
558
+ declare function createMentionInfo(userId: string, display: string, startIndex: number): MentionInfo;
559
+
560
+ /**
561
+ * Create an Attachment object from a File.
562
+ */
563
+ declare function createAttachment(file: File): Attachment;
564
+ /**
565
+ * Revoke object URL for an attachment.
566
+ */
567
+ declare function revokeAttachmentUrl(attachment: Attachment): void;
568
+ /**
569
+ * Revoke all object URLs for a list of attachments.
570
+ */
571
+ declare function revokeAllAttachmentUrls(attachments: Attachment[]): void;
572
+ /**
573
+ * Validate a file against attachment constraints.
574
+ * Returns the reason for rejection, or null if valid.
575
+ */
576
+ declare function validateFile(file: File, currentCount: number, options: {
577
+ maxAttachments?: number;
578
+ maxFileSize?: number;
579
+ allowedMimeTypes?: string[];
580
+ }): AttachmentLimitReason | null;
581
+ /**
582
+ * Format file size for display.
583
+ */
584
+ declare function formatFileSize(bytes: number): string;
585
+
586
+ /**
587
+ * Markdown serializer for Tiptap editor content.
588
+ * Converts the editor document to Markdown string.
589
+ */
590
+ declare function editorToMarkdown(editor: Editor$1): string;
591
+ /**
592
+ * Parse Markdown to Tiptap-compatible JSON content.
593
+ * This is a simplified parser for the Markdown subset we support.
594
+ */
595
+ declare function markdownToEditorContent(markdown: string): any;
596
+
597
+ /**
598
+ * Check if a URL has an allowed protocol for links.
599
+ */
600
+ declare function isAllowedLinkProtocol(url: string): boolean;
601
+ /**
602
+ * Check if a URL has an allowed protocol for images.
603
+ */
604
+ declare function isAllowedImageProtocol(url: string): boolean;
605
+ /**
606
+ * Sanitize a URL for links.
607
+ * - Adds https:// if no protocol is present
608
+ * - Returns null if protocol is not allowed (including javascript:, vbscript:, etc.)
609
+ */
610
+ declare function sanitizeLinkUrl(url: string): string | null;
611
+ /**
612
+ * Sanitize a URL for images.
613
+ * Returns null if protocol is not allowed.
614
+ */
615
+ declare function sanitizeImageUrl(url: string): string | null;
405
616
 
406
- export { $createEmojiNode, $createImageNode, $createMentionNode, $createQuoteNode, $isEmojiNode, $isImageNode, $isMentionNode, $isQuoteNode, type Attachment, type ComposerMode, EmojiNode, IMComposer, type IMComposerLocale, type IMComposerProps, type IMComposerRef, ImageNode, type MarkdownMessagePayload, type MarkdownSyntaxOptions, type Member, type MentionInfo, MentionNode, type MessagePayload, type PlainMessagePayload, type QuoteInfo, QuoteNode, type SendKey, type UploadImageFn, type UploadImageResult, useAttachments, useImageUpload };
617
+ export { type Attachment, type AttachmentLimitReason, AttachmentPreview, type AttachmentPreviewProps, type ComposerDraft, type EditorMode, IMComposer, type IMComposerLocale, type IMComposerProps, type IMComposerRef, LocaleProvider, type MarkdownMessagePayload, type Member, type MentionInfo, MentionList, type MentionListProps, type MessagePayload, type PlainMessagePayload, QuoteBar, type QuoteBarProps, type QuoteInfo, RichEditor, type RichEditorProps, type RichEditorRef, type SendKeymap, type UploadImageFn, type UploadImageResult, type UploadProgressEvent, type UseAttachmentsOptions, type UseAttachmentsReturn, type UsePlainEditorOptions, type UsePlainEditorReturn, createAttachment, createMentionInfo, defaultLocale, editorToMarkdown, extractPlainTextWithMentions, formatFileSize, isAllowedImageProtocol, isAllowedLinkProtocol, markdownToEditorContent, revokeAllAttachmentUrls, revokeAttachmentUrl, sanitizeImageUrl, sanitizeLinkUrl, useAttachments, useLocale, usePlainEditor, validateFile, validateMentionIndices };