@ermis-network/ermis-chat-react 1.0.6 → 1.0.7

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.
Files changed (43) hide show
  1. package/dist/index.cjs +2410 -1308
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.css +471 -16
  4. package/dist/index.css.map +1 -1
  5. package/dist/index.d.mts +145 -1
  6. package/dist/index.d.ts +145 -1
  7. package/dist/index.mjs +2339 -1241
  8. package/dist/index.mjs.map +1 -1
  9. package/package.json +2 -2
  10. package/src/components/BannedOverlay.tsx +40 -0
  11. package/src/components/ChannelActions.tsx +231 -0
  12. package/src/components/ChannelHeader.tsx +38 -2
  13. package/src/components/ChannelInfo/ChannelInfo.tsx +118 -20
  14. package/src/components/ChannelInfo/ChannelInfoTabs.tsx +10 -2
  15. package/src/components/ChannelInfo/ChannelSettingsPanel.tsx +88 -1
  16. package/src/components/ChannelInfo/EditChannelModal.tsx +4 -4
  17. package/src/components/ChannelList.tsx +460 -38
  18. package/src/components/ClosedTopicOverlay.tsx +38 -0
  19. package/src/components/MessageInput.tsx +19 -2
  20. package/src/components/MessageItem.tsx +8 -11
  21. package/src/components/MessageQuickReactions.tsx +3 -2
  22. package/src/components/MessageReactions.tsx +8 -3
  23. package/src/components/MessageRenderers.tsx +7 -9
  24. package/src/components/PendingOverlay.tsx +41 -0
  25. package/src/components/TopicModal.tsx +189 -0
  26. package/src/components/VirtualMessageList.tsx +74 -43
  27. package/src/hooks/useBannedState.ts +27 -3
  28. package/src/hooks/useChannelCapabilities.ts +7 -3
  29. package/src/hooks/useChannelData.ts +1 -1
  30. package/src/hooks/useChannelListUpdates.ts +24 -3
  31. package/src/hooks/useChannelRowUpdates.ts +6 -0
  32. package/src/hooks/useMessageActions.ts +1 -1
  33. package/src/index.ts +6 -1
  34. package/src/styles/_channel-info.css +21 -0
  35. package/src/styles/_channel-list.css +217 -6
  36. package/src/styles/_message-bubble.css +75 -9
  37. package/src/styles/_message-input.css +24 -0
  38. package/src/styles/_message-list.css +51 -6
  39. package/src/styles/_message-quick-reactions.css +5 -0
  40. package/src/styles/_message-reactions.css +7 -0
  41. package/src/styles/_topic-modal.css +154 -0
  42. package/src/styles/index.css +1 -0
  43. package/src/types.ts +157 -3
@@ -355,6 +355,30 @@
355
355
  flex-shrink: 0;
356
356
  }
357
357
 
358
+ /* ----------------------------------------------------------
359
+ Closed Topic State
360
+ ---------------------------------------------------------- */
361
+ .ermis-message-input--closed {
362
+ pointer-events: none;
363
+ }
364
+
365
+ .ermis-message-input__closed-banner {
366
+ display: flex;
367
+ align-items: center;
368
+ justify-content: center;
369
+ gap: var(--ermis-spacing-sm);
370
+ padding: var(--ermis-spacing-md) var(--ermis-spacing-lg);
371
+ color: var(--ermis-color-danger);
372
+ font-size: var(--ermis-font-size-sm);
373
+ font-weight: 500;
374
+ user-select: none;
375
+ opacity: 0.8;
376
+ }
377
+
378
+ .ermis-message-input__closed-banner svg {
379
+ flex-shrink: 0;
380
+ }
381
+
358
382
  /* ----------------------------------------------------------
359
383
  Banners
360
384
  ---------------------------------------------------------- */
@@ -275,17 +275,62 @@
275
275
  }
276
276
 
277
277
  /* ----------------------------------------------------------
278
- Blocked State (messaging channels — user-initiated block)
279
- Messages remain visible but actions are disabled.
278
+ Closed Topic State
280
279
  ---------------------------------------------------------- */
281
- .ermis-message-list--blocked .ermis-message-actions {
282
- display: none;
280
+
281
+ .ermis-message-list__closed-overlay {
282
+ display: flex;
283
+ flex-direction: column;
284
+ align-items: center;
285
+ justify-content: center;
286
+ min-height: calc(100dvh - 8rem);
287
+ gap: var(--ermis-spacing-md);
288
+ user-select: none;
283
289
  }
284
290
 
285
- .ermis-message-list--blocked .ermis-message-reactions__add-btn {
286
- display: none;
291
+ .ermis-message-list__closed-overlay-icon {
292
+ color: var(--ermis-color-danger);
293
+ opacity: 0.8;
287
294
  }
288
295
 
296
+ .ermis-message-list__closed-overlay-title {
297
+ font-size: var(--ermis-font-size-base);
298
+ font-weight: 600;
299
+ color: var(--ermis-text-primary);
300
+ }
301
+
302
+ .ermis-message-list__closed-overlay-subtitle {
303
+ font-size: var(--ermis-font-size-sm);
304
+ color: var(--ermis-text-muted);
305
+ text-align: center;
306
+ max-width: 80%;
307
+ }
308
+
309
+ .ermis-message-list__reopen-btn {
310
+ margin-top: var(--ermis-spacing-md);
311
+ padding: var(--ermis-spacing-sm) var(--ermis-spacing-xl, 24px);
312
+ border: none;
313
+ border-radius: var(--ermis-radius-md, 8px);
314
+ background-color: var(--ermis-accent);
315
+ color: #fff;
316
+ font-size: var(--ermis-font-size-sm);
317
+ font-weight: 600;
318
+ font-family: var(--ermis-font-family);
319
+ cursor: pointer;
320
+ transition: background-color var(--ermis-transition), transform var(--ermis-transition);
321
+ }
322
+
323
+ .ermis-message-list__reopen-btn:hover {
324
+ background-color: var(--ermis-accent-hover);
325
+ transform: translateY(-1px);
326
+ }
327
+
328
+ .ermis-message-list__reopen-btn:active {
329
+ transform: translateY(0);
330
+ }
331
+
332
+
333
+
289
334
  /* Unblock button inside blocked overlay */
290
335
  .ermis-message-list__unblock-btn {
291
336
  margin-top: var(--ermis-spacing-md);
@@ -37,6 +37,11 @@
37
37
  transform: translateY(0);
38
38
  }
39
39
 
40
+ .ermis-message-list__bubble-wrapper:hover .ermis-message-quick-reactions--disabled {
41
+ opacity: 0.5;
42
+ pointer-events: none;
43
+ }
44
+
40
45
  .ermis-message-quick-reactions__btn {
41
46
  display: flex;
42
47
  align-items: center;
@@ -6,6 +6,13 @@
6
6
  flex-wrap: wrap;
7
7
  gap: 4px;
8
8
  margin-bottom: 2px;
9
+ margin-top: 2px;
10
+ width: 100%;
11
+ }
12
+
13
+ .ermis-message-reactions--disabled {
14
+ opacity: 0.8;
15
+ pointer-events: none;
9
16
  }
10
17
 
11
18
  .ermis-message-reactions__item {
@@ -0,0 +1,154 @@
1
+ /* ----------------------------------------------------------
2
+ CreateTopicModal
3
+ ---------------------------------------------------------- */
4
+ .ermis-create-topic__body {
5
+ display: flex;
6
+ flex-direction: column;
7
+ gap: var(--ermis-spacing-lg);
8
+ padding: 0 var(--ermis-spacing-xs);
9
+ }
10
+
11
+ .ermis-create-topic__field {
12
+ display: flex;
13
+ flex-direction: column;
14
+ gap: var(--ermis-spacing-xs);
15
+ }
16
+
17
+ .ermis-create-topic__label {
18
+ font-size: var(--ermis-font-size-sm);
19
+ font-weight: 500;
20
+ color: var(--ermis-text-primary);
21
+ }
22
+
23
+ .ermis-create-topic__required {
24
+ color: var(--ermis-error);
25
+ }
26
+
27
+ .ermis-create-topic__input {
28
+ padding: var(--ermis-spacing-sm) var(--ermis-spacing-md);
29
+ border: 1px solid var(--ermis-border);
30
+ border-radius: var(--ermis-radius-md);
31
+ font-size: var(--ermis-font-size-base);
32
+ color: var(--ermis-text-primary);
33
+ background-color: var(--ermis-bg-primary);
34
+ transition: border-color var(--ermis-transition);
35
+ }
36
+
37
+ .ermis-create-topic__input:focus {
38
+ outline: none;
39
+ border-color: var(--ermis-accent);
40
+ }
41
+
42
+ .ermis-create-topic__live-preview {
43
+ display: flex;
44
+ align-items: center;
45
+ gap: var(--ermis-spacing-sm);
46
+ padding: var(--ermis-spacing-md);
47
+ background-color: var(--ermis-bg-secondary);
48
+ border-radius: var(--ermis-radius-md);
49
+ border: 1px dashed var(--ermis-border);
50
+ }
51
+
52
+ .ermis-create-topic__live-preview-emoji {
53
+ font-size: 20px;
54
+ }
55
+
56
+ .ermis-create-topic__live-preview-name {
57
+ font-size: var(--ermis-font-size-base);
58
+ font-weight: 600;
59
+ color: var(--ermis-text-primary);
60
+ white-space: nowrap;
61
+ overflow: hidden;
62
+ text-overflow: ellipsis;
63
+ }
64
+
65
+ .ermis-create-topic__emoji-picker {
66
+ margin-top: var(--ermis-spacing-sm);
67
+ }
68
+
69
+ .ermis-create-topic__default-icons {
70
+ display: grid;
71
+ grid-template-columns: repeat(4, 1fr);
72
+ gap: var(--ermis-spacing-sm);
73
+ }
74
+
75
+ .ermis-create-topic__default-icon {
76
+ width: 100%;
77
+ height: 40px;
78
+ display: flex;
79
+ align-items: center;
80
+ justify-content: center;
81
+ font-size: 20px;
82
+ background-color: var(--ermis-bg-secondary);
83
+ border: 1px solid var(--ermis-border);
84
+ border-radius: var(--ermis-radius-md);
85
+ cursor: pointer;
86
+ transition: all var(--ermis-transition);
87
+ }
88
+
89
+ .ermis-create-topic__default-icon:hover:not(:disabled) {
90
+ background-color: var(--ermis-bg-hover);
91
+ border-color: var(--ermis-border-hover);
92
+ }
93
+
94
+ .ermis-create-topic__default-icon--active {
95
+ border-color: var(--ermis-accent);
96
+ background-color: var(--ermis-bg-primary);
97
+ }
98
+
99
+ .ermis-create-topic__default-icon:disabled {
100
+ opacity: 0.5;
101
+ cursor: not-allowed;
102
+ }
103
+
104
+
105
+ .ermis-create-topic__error {
106
+ display: flex;
107
+ align-items: center;
108
+ gap: var(--ermis-spacing-sm);
109
+ padding: var(--ermis-spacing-sm);
110
+ border-radius: var(--ermis-radius-md);
111
+ background-color: rgba(239, 68, 68, 0.1);
112
+ color: var(--ermis-error);
113
+ font-size: var(--ermis-font-size-sm);
114
+ }
115
+
116
+ .ermis-create-topic__footer {
117
+ display: flex;
118
+ justify-content: flex-end;
119
+ gap: var(--ermis-spacing-sm);
120
+ margin-top: var(--ermis-spacing-lg);
121
+ }
122
+
123
+ .ermis-create-topic__btn {
124
+ padding: var(--ermis-spacing-sm) var(--ermis-spacing-lg);
125
+ border-radius: var(--ermis-radius-md);
126
+ font-size: var(--ermis-font-size-sm);
127
+ font-weight: 500;
128
+ cursor: pointer;
129
+ transition: all var(--ermis-transition);
130
+ border: none;
131
+ }
132
+
133
+ .ermis-create-topic__btn:disabled {
134
+ opacity: 0.5;
135
+ cursor: not-allowed;
136
+ }
137
+
138
+ .ermis-create-topic__btn--cancel {
139
+ background-color: transparent;
140
+ color: var(--ermis-text-primary);
141
+ }
142
+
143
+ .ermis-create-topic__btn--cancel:hover:not(:disabled) {
144
+ background-color: var(--ermis-bg-hover);
145
+ }
146
+
147
+ .ermis-create-topic__btn--create {
148
+ background-color: var(--ermis-accent);
149
+ color: white;
150
+ }
151
+
152
+ .ermis-create-topic__btn--create:hover:not(:disabled) {
153
+ background-color: var(--ermis-accent-hover);
154
+ }
@@ -25,3 +25,4 @@
25
25
  @import './_user-picker.css';
26
26
  @import './_create-channel-modal.css';
27
27
  @import './_call-ui.css';
28
+ @import './_topic-modal.css';
package/src/types.ts CHANGED
@@ -1,4 +1,13 @@
1
- import type { FormatMessageResponse, MessageLabel, Attachment, Channel, ChannelFilters, ChannelSort, ChannelQueryOptions, UserCallInfo } from '@ermis-network/ermis-chat-sdk';
1
+ import type {
2
+ FormatMessageResponse,
3
+ MessageLabel,
4
+ Attachment,
5
+ Channel,
6
+ ChannelFilters,
7
+ ChannelSort,
8
+ ChannelQueryOptions,
9
+ UserCallInfo,
10
+ } from '@ermis-network/ermis-chat-sdk';
2
11
  import type { ErmisChat } from '@ermis-network/ermis-chat-sdk';
3
12
 
4
13
  /* ----------------------------------------------------------
@@ -299,6 +308,48 @@ export type ChannelHeaderData = {
299
308
  /* ----------------------------------------------------------
300
309
  ChannelList types
301
310
  ---------------------------------------------------------- */
311
+ export type ChannelAction = {
312
+ id: string;
313
+ label: string;
314
+ icon?: React.ReactNode;
315
+ onClick: (channel: Channel, e: React.MouseEvent) => void;
316
+ isDanger?: boolean;
317
+ };
318
+
319
+ export type ChannelActionLabels = {
320
+ pinChannel?: string;
321
+ unpinChannel?: string;
322
+ pinTopic?: string;
323
+ unpinTopic?: string;
324
+ blockUser?: string;
325
+ unblockUser?: string;
326
+ editTopic?: string;
327
+ closeTopic?: string;
328
+ reopenTopic?: string;
329
+ createTopic?: string;
330
+ deleteChannel?: string;
331
+ leaveChannel?: string;
332
+ };
333
+
334
+ export type ChannelActionIcons = {
335
+ PinIcon?: React.ReactNode;
336
+ UnpinIcon?: React.ReactNode;
337
+ BlockIcon?: React.ReactNode;
338
+ UnblockIcon?: React.ReactNode;
339
+ EditTopicIcon?: React.ReactNode;
340
+ CloseTopicIcon?: React.ReactNode;
341
+ ReopenTopicIcon?: React.ReactNode;
342
+ CreateTopicIcon?: React.ReactNode;
343
+ DeleteChannelIcon?: React.ReactNode;
344
+ LeaveChannelIcon?: React.ReactNode;
345
+ };
346
+
347
+ export type ChannelActionsProps = {
348
+ channel: Channel;
349
+ actions: ChannelAction[];
350
+ onClose: () => void;
351
+ };
352
+
302
353
  export type ChannelItemProps = {
303
354
  channel: Channel;
304
355
  isActive: boolean;
@@ -306,6 +357,7 @@ export type ChannelItemProps = {
306
357
  unreadCount: number;
307
358
  lastMessageText: string;
308
359
  lastMessageUser: string;
360
+ lastMessageTimestamp?: Date | string | null;
309
361
  onSelect: (channel: Channel) => void;
310
362
  AvatarComponent: React.ComponentType<AvatarProps>;
311
363
  /** Whether the current user has blocked this channel (messaging only) */
@@ -316,6 +368,22 @@ export type ChannelItemProps = {
316
368
  pendingBadgeLabel?: string;
317
369
  /** Label for the blocked channel badge indicator */
318
370
  blockedBadgeLabel?: string;
371
+ isClosedTopic?: boolean;
372
+ closedTopicIcon?: React.ReactNode;
373
+ PinnedIconComponent?: React.ComponentType;
374
+ ChannelActionsComponent?: React.ComponentType<ChannelActionsProps>;
375
+ /** Handler when Create Topic action is triggered */
376
+ onAddTopic?: (channel: Channel) => void;
377
+ /** Handler when Edit Topic action is triggered */
378
+ onEditTopic?: (channel: Channel) => void;
379
+ /** Handler when Close/Reopen Topic action is triggered */
380
+ onToggleCloseTopic?: (channel: Channel, isClosed: boolean) => void;
381
+ /** Array of action IDs to hide from the actions dropdown */
382
+ hiddenActions?: string[];
383
+ /** Custom labels for default channel actions */
384
+ actionLabels?: ChannelActionLabels;
385
+ /** Custom icons for default channel actions */
386
+ actionIcons?: ChannelActionIcons;
319
387
  };
320
388
 
321
389
  export type ChannelListProps = {
@@ -325,6 +393,8 @@ export type ChannelListProps = {
325
393
  renderChannel?: (channel: Channel, isActive: boolean) => React.ReactNode;
326
394
  onChannelSelect?: (channel: Channel) => void;
327
395
  className?: string;
396
+ /** Array of action IDs to hide from the actions dropdown */
397
+ hiddenActions?: string[];
328
398
  LoadingIndicator?: React.ComponentType<{ text?: string }>;
329
399
  EmptyStateIndicator?: React.ComponentType<{ text?: string }>;
330
400
  AvatarComponent?: React.ComponentType<AvatarProps>;
@@ -342,6 +412,30 @@ export type ChannelListProps = {
342
412
  emptyStateLabel?: string;
343
413
  /** Label for the blocked channel badge hover */
344
414
  blockedBadgeLabel?: string;
415
+ /** Custom component for rendering topic group */
416
+ ChannelTopicGroupComponent?: React.ComponentType<any>;
417
+ /** Custom avatar component for general topic */
418
+ GeneralTopicAvatarComponent?: React.ComponentType<any>;
419
+ /** Custom avatar component for other topics */
420
+ TopicAvatarComponent?: React.ComponentType<any>;
421
+ /** Name for the general topic (default: "general") */
422
+ generalTopicLabel?: string;
423
+ /** Handler when Add Topic button is clicked on a team channel */
424
+ onAddTopic?: (channel: Channel) => void;
425
+ /** Optional custom emoji picker for TopicModal */
426
+ TopicEmojiPickerComponent?: React.ComponentType<any>;
427
+ closedTopicIcon?: React.ReactNode;
428
+ PinnedIconComponent?: React.ComponentType;
429
+ /** Custom component for channel actions dropdown */
430
+ ChannelActionsComponent?: React.ComponentType<ChannelActionsProps>;
431
+ /** Handler when Edit Topic action is triggered */
432
+ onEditTopic?: (channel: Channel) => void;
433
+ /** Handler when Close/Reopen Topic action is triggered */
434
+ onToggleCloseTopic?: (channel: Channel, isClosed: boolean) => void;
435
+ /** Custom labels for default channel actions */
436
+ actionLabels?: ChannelActionLabels;
437
+ /** Custom icons for default channel actions */
438
+ actionIcons?: ChannelActionIcons;
345
439
  };
346
440
 
347
441
  /* ----------------------------------------------------------
@@ -433,6 +527,9 @@ export type MessageListProps = {
433
527
  pendingOverlaySubtitle?: string;
434
528
  pendingAcceptLabel?: string;
435
529
  pendingRejectLabel?: string;
530
+ closedTopicOverlayTitle?: string;
531
+ closedTopicOverlaySubtitle?: string;
532
+ closedTopicReopenLabel?: string;
436
533
  };
437
534
 
438
535
  /* ----------------------------------------------------------
@@ -460,6 +557,8 @@ export type MessageReactionsProps = {
460
557
  AvatarComponent?: React.ComponentType<AvatarProps>;
461
558
  /** Callback when clicking a reaction */
462
559
  onClickReaction?: (type: string) => void;
560
+ /** Whether interactions are disabled */
561
+ disabled?: boolean;
463
562
  };
464
563
 
465
564
  /* ----------------------------------------------------------
@@ -580,7 +679,11 @@ export type MessageInputProps = {
580
679
  /** Custom reply preview component */
581
680
  ReplyPreviewComponent?: React.ComponentType<ReplyPreviewProps>;
582
681
  /** Custom edit preview component */
583
- EditPreviewComponent?: React.ComponentType<{ message: FormatMessageResponse; onDismiss: () => void; editingMessageLabel?: string }>;
682
+ EditPreviewComponent?: React.ComponentType<{
683
+ message: FormatMessageResponse;
684
+ onDismiss: () => void;
685
+ editingMessageLabel?: string;
686
+ }>;
584
687
  /** I18n Label for banned state */
585
688
  bannedLabel?: string;
586
689
  /** I18n Label for blocked state (messaging channels) */
@@ -593,6 +696,8 @@ export type MessageInputProps = {
593
696
  sendDisabledLabel?: string;
594
697
  /** I18n Label for slow mode active */
595
698
  slowModeLabel?: (cooldown: number) => React.ReactNode;
699
+ /** I18n Label for closed topic */
700
+ closedTopicLabel?: string;
596
701
  };
597
702
 
598
703
  /* ----------------------------------------------------------
@@ -867,6 +972,10 @@ export type ChannelInfoCoverProps = {
867
972
  onEditClick?: () => void;
868
973
  /** Whether the channel is public */
869
974
  isPublic?: boolean;
975
+ /** Name of the parent channel (if this is a topic) */
976
+ parentChannelName?: string;
977
+ /** Whether the channel is a topic */
978
+ isTopic?: boolean;
870
979
  /** Whether the channel is a team channel */
871
980
  isTeamChannel?: boolean;
872
981
  };
@@ -879,6 +988,8 @@ export type ChannelInfoActionsProps = {
879
988
  onBlockUser?: () => void;
880
989
  onUnblockUser?: () => void;
881
990
  isTeamChannel?: boolean;
991
+ isTopic?: boolean;
992
+ isClosedTopic?: boolean;
882
993
  isBlocked?: boolean;
883
994
  currentUserRole?: string;
884
995
  searchLabel?: string;
@@ -887,6 +998,10 @@ export type ChannelInfoActionsProps = {
887
998
  leaveLabel?: string;
888
999
  blockLabel?: string;
889
1000
  unblockLabel?: string;
1001
+ onCloseTopic?: () => void;
1002
+ onReopenTopic?: () => void;
1003
+ closeTopicLabel?: string;
1004
+ reopenTopicLabel?: string;
890
1005
  };
891
1006
 
892
1007
  export type ChannelInfoMember = {
@@ -988,7 +1103,11 @@ export type AddMemberModalProps = {
988
1103
  /** Custom user item component (replaces the default row) */
989
1104
  UserItemComponent?: React.ComponentType<AddMemberUserItemProps>;
990
1105
  /** Custom search input component */
991
- SearchInputComponent?: React.ComponentType<{ value: string; onChange: (e: React.ChangeEvent<HTMLInputElement>) => void; placeholder: string }>;
1106
+ SearchInputComponent?: React.ComponentType<{
1107
+ value: string;
1108
+ onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
1109
+ placeholder: string;
1110
+ }>;
992
1111
  };
993
1112
 
994
1113
  export type ChannelInfoTabsProps = {
@@ -1101,6 +1220,13 @@ export type ChannelInfoProps = {
1101
1220
  /** I18n labels for block/unblock actions */
1102
1221
  actionsBlockLabel?: string;
1103
1222
  actionsUnblockLabel?: string;
1223
+ actionsCloseTopicLabel?: string;
1224
+ actionsReopenTopicLabel?: string;
1225
+
1226
+ /** Settings Panel Topics Labels */
1227
+ settingsWorkspaceTopicsTitle?: string;
1228
+ settingsTopicsFeatureName?: string;
1229
+ settingsTopicsFeatureDescription?: string;
1104
1230
  };
1105
1231
 
1106
1232
  /* ----------------------------------------------------------
@@ -1144,6 +1270,10 @@ export type ChannelSettingsPanelProps = {
1144
1270
  title?: string;
1145
1271
  /** Custom slow mode options */
1146
1272
  slowModeOptions?: { label: string; value: number }[];
1273
+ /** I18n labels for Topics settings */
1274
+ workspaceTopicsTitle?: string;
1275
+ topicsFeatureName?: string;
1276
+ topicsFeatureDescription?: string;
1147
1277
  };
1148
1278
 
1149
1279
  /* ----------------------------------------------------------
@@ -1245,3 +1375,27 @@ export type CreateChannelModalProps = {
1245
1375
  maxImageSize?: number; // bytes
1246
1376
  maxImageSizeError?: string;
1247
1377
  };
1378
+
1379
+ export type TopicModalProps = {
1380
+ isOpen: boolean;
1381
+ onClose: () => void;
1382
+ onSuccess?: (channel: Channel) => void;
1383
+ /** Inject external emoji picker component */
1384
+ EmojiPickerComponent?: React.ComponentType<{ onSelect: (emoji: any) => void; [key: string]: any }>;
1385
+ /** Parent team channel to create topic under, will use activeChannel if not provided */
1386
+ parentChannel?: Channel;
1387
+
1388
+ /** If provided, operates in edit mode for this topic */
1389
+ topic?: Channel;
1390
+
1391
+ /** i18n labels */
1392
+ title?: string;
1393
+ nameLabel?: string;
1394
+ namePlaceholder?: string;
1395
+ emojiLabel?: string;
1396
+ descriptionLabel?: string;
1397
+ descriptionPlaceholder?: string;
1398
+ cancelButtonLabel?: string;
1399
+ saveButtonLabel?: string;
1400
+ savingButtonLabel?: string;
1401
+ };