@convokitapp/vue-ui 0.2.2 → 0.4.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/dist/index.d.cts CHANGED
@@ -1,8 +1,10 @@
1
- import { Conversation as Conversation$1, Message, MessageMedia, RealtimeSubscription, ReadEvent, TypingEvent, ConvoKitClient } from '@convokitapp/sdk';
1
+ import { Conversation as Conversation$1, MessageListOptions, Message, SendMessageInput, RealtimeConnectionHandlers, RealtimeSubscription, MessageEvent, MessageDeletedEvent, ReadEvent, TypingEvent, MessageMedia, ConvoKitClient } from '@convokitapp/sdk';
2
2
  import * as vue from 'vue';
3
3
  import { CSSProperties, HTMLAttributes, Ref, VNodeChild, PropType, MaybeRefOrGetter, TextareaHTMLAttributes } from 'vue';
4
4
 
5
+ /** Custom adapters must expose an identity unique to each login, including same-user logins. */
5
6
  interface ConvoKitUiClient {
7
+ readonly sessionIdentity: object | null;
6
8
  readonly currentUserId: string;
7
9
  getConversations(options: {
8
10
  limit: number;
@@ -10,25 +12,25 @@ interface ConvoKitUiClient {
10
12
  archived: boolean;
11
13
  }): Promise<Conversation$1[]>;
12
14
  getConversation(conversationId: string): Promise<Conversation$1>;
13
- getMessages(options: {
14
- conversationId: string;
15
- limit: number;
16
- offset: number;
17
- }): Promise<Message[]>;
18
- sendMessage(input: {
19
- conversationId: string;
20
- text?: string;
21
- media?: MessageMedia[];
22
- }): Promise<Message>;
15
+ /** Newest first, with a paired value cursor; never derive an offset from rendered rows. */
16
+ getMessages(options: MessageListOptions): Promise<Message[]>;
17
+ /** Complete authorized message, including related media absent from raw row events. */
18
+ getMessage(id: string): Promise<Message>;
19
+ sendMessage(input: SendMessageInput): Promise<Message>;
23
20
  markConversationRead(conversationId: string): Promise<void>;
24
21
  sendTyping(input: {
25
22
  conversationId: string;
26
23
  isTyping: boolean;
27
24
  }): Promise<void>;
28
- onMessage(conversationId: string, handler: (message: Message) => void, onError?: (error: Error) => void): RealtimeSubscription;
25
+ onConnectionEvent(handlers: RealtimeConnectionHandlers): RealtimeSubscription;
26
+ /** Notify on inbox mutations AND on initial subscription/reconnect. No room data in the signal. */
27
+ onInboxChanged(handler: () => void, onError?: (error: Error) => void): RealtimeSubscription;
28
+ onMessage(conversationId: string, handler: (event: MessageEvent) => void, onError?: (error: Error) => void): RealtimeSubscription;
29
+ onMessageDeleted(conversationId: string, handler: (event: MessageDeletedEvent) => void, onError?: (error: Error) => void): RealtimeSubscription;
29
30
  onReadReceipt(conversationId: string, handler: (event: ReadEvent) => void, onError?: (error: Error) => void): RealtimeSubscription;
30
31
  onTyping(conversationId: string, handler: (event: TypingEvent) => void, onError?: (error: Error) => void): RealtimeSubscription;
31
32
  }
33
+
32
34
  interface ConversationFilter {
33
35
  query?: string;
34
36
  archived?: boolean;
@@ -59,6 +61,7 @@ interface ConversationState {
59
61
  readAtByUserId: Readonly<Ref<ReadonlyMap<string, Date>>>;
60
62
  isInitialLoading: Readonly<Ref<boolean>>;
61
63
  isLoadingOlder: Readonly<Ref<boolean>>;
64
+ isReconciling: Readonly<Ref<boolean>>;
62
65
  isSending: Readonly<Ref<boolean>>;
63
66
  hasOlderMessages: Readonly<Ref<boolean>>;
64
67
  hasLoaded: Readonly<Ref<boolean>>;
@@ -172,7 +175,7 @@ interface ConversationController extends ConversationState {
172
175
  updateTyping(isTyping: boolean): Promise<void>;
173
176
  dispose(): Promise<void>;
174
177
  }
175
- /** Owns one conversation's history, realtime state, sending, and read positions. */
178
+ /** Each room/login gets an independent owner; disposal also stops reactive reloads. */
176
179
  declare function useConversation(options: UseConversationOptions): ConversationController;
177
180
 
178
181
  interface ConversationViewProps extends ConvoKitAppearanceProps {
@@ -505,11 +508,14 @@ declare const ConversationView: vue.DefineComponent<vue.ExtractPropTypes<{
505
508
  "onAdd-attachment"?: (...args: any[]) => any;
506
509
  "onUpdate:modelValue"?: (...args: any[]) => any;
507
510
  }>, {
511
+ readonly typingUserIds: ReadonlySet<string>;
508
512
  readonly readAtByUserId: ReadonlyMap<string, Date>;
513
+ readonly isInitialLoading: boolean;
514
+ readonly isLoadingOlder: boolean;
515
+ readonly isSending: boolean;
516
+ readonly hasOlderMessages: boolean;
509
517
  readonly readersResolver: (message: Message) => ReadonlySet<string>;
510
518
  readonly onLoadOlder: () => void | Promise<void>;
511
- readonly hasOlderMessages: boolean;
512
- readonly isLoadingOlder: boolean;
513
519
  readonly onAttachmentClick: (media: MessageMedia, message: Message) => void;
514
520
  readonly paginationThreshold: number;
515
521
  readonly stickToBottom: boolean;
@@ -519,13 +525,10 @@ declare const ConversationView: vue.DefineComponent<vue.ExtractPropTypes<{
519
525
  readonly styles: Partial<Record<ConvoKitUiPart, CSSProperties>>;
520
526
  readonly density: ConvoKitUiDensity;
521
527
  readonly unstyled: boolean;
522
- readonly typingUserIds: ReadonlySet<string>;
523
528
  readonly onBack: () => void;
524
529
  readonly onRefresh: () => void | Promise<void>;
525
530
  readonly onTypingChange: (isTyping: boolean) => void | Promise<void>;
526
531
  readonly onAddAttachment: () => void;
527
- readonly isInitialLoading: boolean;
528
- readonly isSending: boolean;
529
532
  readonly displayNameForUser: (userId: string) => string | null | undefined;
530
533
  readonly reverseMessages: boolean;
531
534
  readonly composerPlaceholder: string;
@@ -902,12 +905,15 @@ declare const Conversation: vue.DefineComponent<vue.ExtractPropTypes<{
902
905
  }>, {
903
906
  messages: readonly Message[];
904
907
  conversation: Conversation$1;
905
- currentUserId: string;
908
+ typingUserIds: ReadonlySet<string>;
906
909
  readAtByUserId: ReadonlyMap<string, Date>;
910
+ isInitialLoading: boolean;
911
+ isLoadingOlder: boolean;
912
+ isSending: boolean;
913
+ hasOlderMessages: boolean;
914
+ currentUserId: string;
907
915
  readersResolver: (message: Message) => ReadonlySet<string>;
908
916
  onLoadOlder: () => void | Promise<void>;
909
- hasOlderMessages: boolean;
910
- isLoadingOlder: boolean;
911
917
  onAttachmentClick: (media: MessageMedia, message: Message) => void;
912
918
  paginationThreshold: number;
913
919
  stickToBottom: boolean;
@@ -918,13 +924,10 @@ declare const Conversation: vue.DefineComponent<vue.ExtractPropTypes<{
918
924
  density: ConvoKitUiDensity;
919
925
  unstyled: boolean;
920
926
  onSendMessage: (text: string) => boolean | void | Promise<boolean | void>;
921
- typingUserIds: ReadonlySet<string>;
922
927
  onBack: () => void;
923
928
  onRefresh: () => void | Promise<void>;
924
929
  onTypingChange: (isTyping: boolean) => void | Promise<void>;
925
930
  onAddAttachment: () => void;
926
- isInitialLoading: boolean;
927
- isSending: boolean;
928
931
  displayNameForUser: (userId: string) => string | null | undefined;
929
932
  reverseMessages: boolean;
930
933
  composerPlaceholder: string;
@@ -956,7 +959,6 @@ interface ConversationListController extends ConversationListState {
956
959
  setQuery(query: string): Promise<void>;
957
960
  dispose(): Promise<void>;
958
961
  }
959
- /** Loads, de-duplicates, filters, and paginates conversations. */
960
962
  declare function useConversationList(options: UseConversationListOptions): ConversationListController;
961
963
 
962
964
  interface ConversationListViewProps extends ConvoKitAppearanceProps {
@@ -1117,6 +1119,7 @@ declare const ConversationListView: vue.DefineComponent<vue.ExtractPropTypes<{
1117
1119
  "onConversation-select"?: (_conversation: Conversation$1) => any;
1118
1120
  "onLoad-more"?: () => any;
1119
1121
  }>, {
1122
+ readonly isInitialLoading: boolean;
1120
1123
  readonly scrollElement: Ref<HTMLElement | null, HTMLElement | null>;
1121
1124
  readonly paginationThreshold: number;
1122
1125
  readonly classNames: Partial<Record<ConvoKitUiPart, string>>;
@@ -1124,12 +1127,11 @@ declare const ConversationListView: vue.DefineComponent<vue.ExtractPropTypes<{
1124
1127
  readonly density: ConvoKitUiDensity;
1125
1128
  readonly unstyled: boolean;
1126
1129
  readonly onRefresh: () => void | Promise<void>;
1127
- readonly isInitialLoading: boolean;
1130
+ readonly isLoadingMore: boolean;
1131
+ readonly hasMore: boolean;
1128
1132
  readonly selectedConversationId: string;
1129
1133
  readonly onConversationSelect: (conversation: Conversation$1) => void;
1130
1134
  readonly onLoadMore: () => void | Promise<void>;
1131
- readonly isLoadingMore: boolean;
1132
- readonly hasMore: boolean;
1133
1135
  readonly ariaLabel: string;
1134
1136
  }, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
1135
1137
  interface ConversationListProps extends Omit<ConversationListViewProps, 'conversations' | 'onRefresh' | 'onLoadMore' | 'isInitialLoading' | 'isLoadingMore' | 'hasMore' | 'error'>, Omit<UseConversationListOptions, 'client'> {
@@ -1321,6 +1323,7 @@ declare const ConversationList: vue.DefineComponent<vue.ExtractPropTypes<{
1321
1323
  "onController-change"?: (...args: any[]) => any;
1322
1324
  "onConversation-select"?: (...args: any[]) => any;
1323
1325
  }>, {
1326
+ isInitialLoading: boolean;
1324
1327
  scrollElement: Ref<HTMLElement | null, HTMLElement | null>;
1325
1328
  paginationThreshold: number;
1326
1329
  classNames: Partial<Record<ConvoKitUiPart, string>>;
@@ -1328,15 +1331,14 @@ declare const ConversationList: vue.DefineComponent<vue.ExtractPropTypes<{
1328
1331
  density: ConvoKitUiDensity;
1329
1332
  unstyled: boolean;
1330
1333
  onRefresh: () => void | Promise<void>;
1331
- isInitialLoading: boolean;
1332
1334
  autoLoad: boolean;
1333
1335
  onControllerChange: (controller: ConversationListController) => void;
1334
1336
  conversations: readonly Conversation$1[];
1337
+ isLoadingMore: boolean;
1338
+ hasMore: boolean;
1335
1339
  selectedConversationId: string;
1336
1340
  onConversationSelect: (conversation: Conversation$1) => void;
1337
1341
  onLoadMore: () => void | Promise<void>;
1338
- isLoadingMore: boolean;
1339
- hasMore: boolean;
1340
1342
  ariaLabel: string;
1341
1343
  pageLoader: ConversationPageLoader;
1342
1344
  initialFilter: ConversationFilter;
@@ -1535,10 +1537,10 @@ declare const MessageListView: vue.DefineComponent<vue.ExtractPropTypes<{
1535
1537
  }>, {
1536
1538
  reverse: boolean;
1537
1539
  readAtByUserId: ReadonlyMap<string, Date>;
1540
+ isLoadingOlder: boolean;
1541
+ hasOlderMessages: boolean;
1538
1542
  readersResolver: (message: Message) => ReadonlySet<string>;
1539
1543
  onLoadOlder: () => void | Promise<void>;
1540
- hasOlderMessages: boolean;
1541
- isLoadingOlder: boolean;
1542
1544
  onAttachmentClick: (media: MessageMedia, message: Message) => void;
1543
1545
  scrollElement: Ref<HTMLElement | null, HTMLElement | null>;
1544
1546
  paginationThreshold: number;
package/dist/index.d.ts CHANGED
@@ -1,8 +1,10 @@
1
- import { Conversation as Conversation$1, Message, MessageMedia, RealtimeSubscription, ReadEvent, TypingEvent, ConvoKitClient } from '@convokitapp/sdk';
1
+ import { Conversation as Conversation$1, MessageListOptions, Message, SendMessageInput, RealtimeConnectionHandlers, RealtimeSubscription, MessageEvent, MessageDeletedEvent, ReadEvent, TypingEvent, MessageMedia, ConvoKitClient } from '@convokitapp/sdk';
2
2
  import * as vue from 'vue';
3
3
  import { CSSProperties, HTMLAttributes, Ref, VNodeChild, PropType, MaybeRefOrGetter, TextareaHTMLAttributes } from 'vue';
4
4
 
5
+ /** Custom adapters must expose an identity unique to each login, including same-user logins. */
5
6
  interface ConvoKitUiClient {
7
+ readonly sessionIdentity: object | null;
6
8
  readonly currentUserId: string;
7
9
  getConversations(options: {
8
10
  limit: number;
@@ -10,25 +12,25 @@ interface ConvoKitUiClient {
10
12
  archived: boolean;
11
13
  }): Promise<Conversation$1[]>;
12
14
  getConversation(conversationId: string): Promise<Conversation$1>;
13
- getMessages(options: {
14
- conversationId: string;
15
- limit: number;
16
- offset: number;
17
- }): Promise<Message[]>;
18
- sendMessage(input: {
19
- conversationId: string;
20
- text?: string;
21
- media?: MessageMedia[];
22
- }): Promise<Message>;
15
+ /** Newest first, with a paired value cursor; never derive an offset from rendered rows. */
16
+ getMessages(options: MessageListOptions): Promise<Message[]>;
17
+ /** Complete authorized message, including related media absent from raw row events. */
18
+ getMessage(id: string): Promise<Message>;
19
+ sendMessage(input: SendMessageInput): Promise<Message>;
23
20
  markConversationRead(conversationId: string): Promise<void>;
24
21
  sendTyping(input: {
25
22
  conversationId: string;
26
23
  isTyping: boolean;
27
24
  }): Promise<void>;
28
- onMessage(conversationId: string, handler: (message: Message) => void, onError?: (error: Error) => void): RealtimeSubscription;
25
+ onConnectionEvent(handlers: RealtimeConnectionHandlers): RealtimeSubscription;
26
+ /** Notify on inbox mutations AND on initial subscription/reconnect. No room data in the signal. */
27
+ onInboxChanged(handler: () => void, onError?: (error: Error) => void): RealtimeSubscription;
28
+ onMessage(conversationId: string, handler: (event: MessageEvent) => void, onError?: (error: Error) => void): RealtimeSubscription;
29
+ onMessageDeleted(conversationId: string, handler: (event: MessageDeletedEvent) => void, onError?: (error: Error) => void): RealtimeSubscription;
29
30
  onReadReceipt(conversationId: string, handler: (event: ReadEvent) => void, onError?: (error: Error) => void): RealtimeSubscription;
30
31
  onTyping(conversationId: string, handler: (event: TypingEvent) => void, onError?: (error: Error) => void): RealtimeSubscription;
31
32
  }
33
+
32
34
  interface ConversationFilter {
33
35
  query?: string;
34
36
  archived?: boolean;
@@ -59,6 +61,7 @@ interface ConversationState {
59
61
  readAtByUserId: Readonly<Ref<ReadonlyMap<string, Date>>>;
60
62
  isInitialLoading: Readonly<Ref<boolean>>;
61
63
  isLoadingOlder: Readonly<Ref<boolean>>;
64
+ isReconciling: Readonly<Ref<boolean>>;
62
65
  isSending: Readonly<Ref<boolean>>;
63
66
  hasOlderMessages: Readonly<Ref<boolean>>;
64
67
  hasLoaded: Readonly<Ref<boolean>>;
@@ -172,7 +175,7 @@ interface ConversationController extends ConversationState {
172
175
  updateTyping(isTyping: boolean): Promise<void>;
173
176
  dispose(): Promise<void>;
174
177
  }
175
- /** Owns one conversation's history, realtime state, sending, and read positions. */
178
+ /** Each room/login gets an independent owner; disposal also stops reactive reloads. */
176
179
  declare function useConversation(options: UseConversationOptions): ConversationController;
177
180
 
178
181
  interface ConversationViewProps extends ConvoKitAppearanceProps {
@@ -505,11 +508,14 @@ declare const ConversationView: vue.DefineComponent<vue.ExtractPropTypes<{
505
508
  "onAdd-attachment"?: (...args: any[]) => any;
506
509
  "onUpdate:modelValue"?: (...args: any[]) => any;
507
510
  }>, {
511
+ readonly typingUserIds: ReadonlySet<string>;
508
512
  readonly readAtByUserId: ReadonlyMap<string, Date>;
513
+ readonly isInitialLoading: boolean;
514
+ readonly isLoadingOlder: boolean;
515
+ readonly isSending: boolean;
516
+ readonly hasOlderMessages: boolean;
509
517
  readonly readersResolver: (message: Message) => ReadonlySet<string>;
510
518
  readonly onLoadOlder: () => void | Promise<void>;
511
- readonly hasOlderMessages: boolean;
512
- readonly isLoadingOlder: boolean;
513
519
  readonly onAttachmentClick: (media: MessageMedia, message: Message) => void;
514
520
  readonly paginationThreshold: number;
515
521
  readonly stickToBottom: boolean;
@@ -519,13 +525,10 @@ declare const ConversationView: vue.DefineComponent<vue.ExtractPropTypes<{
519
525
  readonly styles: Partial<Record<ConvoKitUiPart, CSSProperties>>;
520
526
  readonly density: ConvoKitUiDensity;
521
527
  readonly unstyled: boolean;
522
- readonly typingUserIds: ReadonlySet<string>;
523
528
  readonly onBack: () => void;
524
529
  readonly onRefresh: () => void | Promise<void>;
525
530
  readonly onTypingChange: (isTyping: boolean) => void | Promise<void>;
526
531
  readonly onAddAttachment: () => void;
527
- readonly isInitialLoading: boolean;
528
- readonly isSending: boolean;
529
532
  readonly displayNameForUser: (userId: string) => string | null | undefined;
530
533
  readonly reverseMessages: boolean;
531
534
  readonly composerPlaceholder: string;
@@ -902,12 +905,15 @@ declare const Conversation: vue.DefineComponent<vue.ExtractPropTypes<{
902
905
  }>, {
903
906
  messages: readonly Message[];
904
907
  conversation: Conversation$1;
905
- currentUserId: string;
908
+ typingUserIds: ReadonlySet<string>;
906
909
  readAtByUserId: ReadonlyMap<string, Date>;
910
+ isInitialLoading: boolean;
911
+ isLoadingOlder: boolean;
912
+ isSending: boolean;
913
+ hasOlderMessages: boolean;
914
+ currentUserId: string;
907
915
  readersResolver: (message: Message) => ReadonlySet<string>;
908
916
  onLoadOlder: () => void | Promise<void>;
909
- hasOlderMessages: boolean;
910
- isLoadingOlder: boolean;
911
917
  onAttachmentClick: (media: MessageMedia, message: Message) => void;
912
918
  paginationThreshold: number;
913
919
  stickToBottom: boolean;
@@ -918,13 +924,10 @@ declare const Conversation: vue.DefineComponent<vue.ExtractPropTypes<{
918
924
  density: ConvoKitUiDensity;
919
925
  unstyled: boolean;
920
926
  onSendMessage: (text: string) => boolean | void | Promise<boolean | void>;
921
- typingUserIds: ReadonlySet<string>;
922
927
  onBack: () => void;
923
928
  onRefresh: () => void | Promise<void>;
924
929
  onTypingChange: (isTyping: boolean) => void | Promise<void>;
925
930
  onAddAttachment: () => void;
926
- isInitialLoading: boolean;
927
- isSending: boolean;
928
931
  displayNameForUser: (userId: string) => string | null | undefined;
929
932
  reverseMessages: boolean;
930
933
  composerPlaceholder: string;
@@ -956,7 +959,6 @@ interface ConversationListController extends ConversationListState {
956
959
  setQuery(query: string): Promise<void>;
957
960
  dispose(): Promise<void>;
958
961
  }
959
- /** Loads, de-duplicates, filters, and paginates conversations. */
960
962
  declare function useConversationList(options: UseConversationListOptions): ConversationListController;
961
963
 
962
964
  interface ConversationListViewProps extends ConvoKitAppearanceProps {
@@ -1117,6 +1119,7 @@ declare const ConversationListView: vue.DefineComponent<vue.ExtractPropTypes<{
1117
1119
  "onConversation-select"?: (_conversation: Conversation$1) => any;
1118
1120
  "onLoad-more"?: () => any;
1119
1121
  }>, {
1122
+ readonly isInitialLoading: boolean;
1120
1123
  readonly scrollElement: Ref<HTMLElement | null, HTMLElement | null>;
1121
1124
  readonly paginationThreshold: number;
1122
1125
  readonly classNames: Partial<Record<ConvoKitUiPart, string>>;
@@ -1124,12 +1127,11 @@ declare const ConversationListView: vue.DefineComponent<vue.ExtractPropTypes<{
1124
1127
  readonly density: ConvoKitUiDensity;
1125
1128
  readonly unstyled: boolean;
1126
1129
  readonly onRefresh: () => void | Promise<void>;
1127
- readonly isInitialLoading: boolean;
1130
+ readonly isLoadingMore: boolean;
1131
+ readonly hasMore: boolean;
1128
1132
  readonly selectedConversationId: string;
1129
1133
  readonly onConversationSelect: (conversation: Conversation$1) => void;
1130
1134
  readonly onLoadMore: () => void | Promise<void>;
1131
- readonly isLoadingMore: boolean;
1132
- readonly hasMore: boolean;
1133
1135
  readonly ariaLabel: string;
1134
1136
  }, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
1135
1137
  interface ConversationListProps extends Omit<ConversationListViewProps, 'conversations' | 'onRefresh' | 'onLoadMore' | 'isInitialLoading' | 'isLoadingMore' | 'hasMore' | 'error'>, Omit<UseConversationListOptions, 'client'> {
@@ -1321,6 +1323,7 @@ declare const ConversationList: vue.DefineComponent<vue.ExtractPropTypes<{
1321
1323
  "onController-change"?: (...args: any[]) => any;
1322
1324
  "onConversation-select"?: (...args: any[]) => any;
1323
1325
  }>, {
1326
+ isInitialLoading: boolean;
1324
1327
  scrollElement: Ref<HTMLElement | null, HTMLElement | null>;
1325
1328
  paginationThreshold: number;
1326
1329
  classNames: Partial<Record<ConvoKitUiPart, string>>;
@@ -1328,15 +1331,14 @@ declare const ConversationList: vue.DefineComponent<vue.ExtractPropTypes<{
1328
1331
  density: ConvoKitUiDensity;
1329
1332
  unstyled: boolean;
1330
1333
  onRefresh: () => void | Promise<void>;
1331
- isInitialLoading: boolean;
1332
1334
  autoLoad: boolean;
1333
1335
  onControllerChange: (controller: ConversationListController) => void;
1334
1336
  conversations: readonly Conversation$1[];
1337
+ isLoadingMore: boolean;
1338
+ hasMore: boolean;
1335
1339
  selectedConversationId: string;
1336
1340
  onConversationSelect: (conversation: Conversation$1) => void;
1337
1341
  onLoadMore: () => void | Promise<void>;
1338
- isLoadingMore: boolean;
1339
- hasMore: boolean;
1340
1342
  ariaLabel: string;
1341
1343
  pageLoader: ConversationPageLoader;
1342
1344
  initialFilter: ConversationFilter;
@@ -1535,10 +1537,10 @@ declare const MessageListView: vue.DefineComponent<vue.ExtractPropTypes<{
1535
1537
  }>, {
1536
1538
  reverse: boolean;
1537
1539
  readAtByUserId: ReadonlyMap<string, Date>;
1540
+ isLoadingOlder: boolean;
1541
+ hasOlderMessages: boolean;
1538
1542
  readersResolver: (message: Message) => ReadonlySet<string>;
1539
1543
  onLoadOlder: () => void | Promise<void>;
1540
- hasOlderMessages: boolean;
1541
- isLoadingOlder: boolean;
1542
1544
  onAttachmentClick: (media: MessageMedia, message: Message) => void;
1543
1545
  scrollElement: Ref<HTMLElement | null, HTMLElement | null>;
1544
1546
  paginationThreshold: number;