@unif/react-native-chat 3.2.3 → 3.3.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.
Files changed (114) hide show
  1. package/lib/module/components/Attachments/AttachmentItem.js +3 -2
  2. package/lib/module/components/Attachments/AttachmentItem.js.map +1 -1
  3. package/lib/module/components/Attachments/Attachments.js +1 -0
  4. package/lib/module/components/Attachments/Attachments.js.map +1 -1
  5. package/lib/module/components/Attachments/styles.js +4 -0
  6. package/lib/module/components/Attachments/styles.js.map +1 -1
  7. package/lib/module/components/Composer/Composer.js +13 -9
  8. package/lib/module/components/Composer/Composer.js.map +1 -1
  9. package/lib/module/components/Confirmation/Confirmation.js +29 -13
  10. package/lib/module/components/Confirmation/Confirmation.js.map +1 -1
  11. package/lib/module/components/Confirmation/styles.js +17 -6
  12. package/lib/module/components/Confirmation/styles.js.map +1 -1
  13. package/lib/module/components/Message/MarkdownContent/styles.js +29 -33
  14. package/lib/module/components/Message/MarkdownContent/styles.js.map +1 -1
  15. package/lib/module/components/Message/Message.js +37 -24
  16. package/lib/module/components/Message/Message.js.map +1 -1
  17. package/lib/module/components/Message/MessageWaiting.js +53 -0
  18. package/lib/module/components/Message/MessageWaiting.js.map +1 -0
  19. package/lib/module/components/Message/constants.js +3 -0
  20. package/lib/module/components/Message/constants.js.map +1 -1
  21. package/lib/module/components/Message/styles.js +41 -3
  22. package/lib/module/components/Message/styles.js.map +1 -1
  23. package/lib/module/components/MessageList/MessageList.js +60 -31
  24. package/lib/module/components/MessageList/MessageList.js.map +1 -1
  25. package/lib/module/components/MessageList/MessageListEndButton.js +60 -0
  26. package/lib/module/components/MessageList/MessageListEndButton.js.map +1 -0
  27. package/lib/module/components/MessageList/MessageListRow.js +9 -2
  28. package/lib/module/components/MessageList/MessageListRow.js.map +1 -1
  29. package/lib/module/components/MessageList/styles.js +6 -0
  30. package/lib/module/components/MessageList/styles.js.map +1 -1
  31. package/lib/module/components/MessageList/useMessageListScroll.js +218 -13
  32. package/lib/module/components/MessageList/useMessageListScroll.js.map +1 -1
  33. package/lib/module/components/Process/Process.js +15 -5
  34. package/lib/module/components/Process/Process.js.map +1 -1
  35. package/lib/module/components/Process/ProcessCompactStep.js +21 -7
  36. package/lib/module/components/Process/ProcessCompactStep.js.map +1 -1
  37. package/lib/module/components/Process/ProcessTimelineStep.js +79 -0
  38. package/lib/module/components/Process/ProcessTimelineStep.js.map +1 -0
  39. package/lib/module/components/Process/styles.js +63 -3
  40. package/lib/module/components/Process/styles.js.map +1 -1
  41. package/lib/module/index.js.map +1 -1
  42. package/lib/typescript/src/components/Attachments/AttachmentItem.d.ts +1 -1
  43. package/lib/typescript/src/components/Attachments/AttachmentItem.d.ts.map +1 -1
  44. package/lib/typescript/src/components/Attachments/Attachments.d.ts.map +1 -1
  45. package/lib/typescript/src/components/Attachments/styles.d.ts +4 -0
  46. package/lib/typescript/src/components/Attachments/styles.d.ts.map +1 -1
  47. package/lib/typescript/src/components/Attachments/types.d.ts +2 -1
  48. package/lib/typescript/src/components/Attachments/types.d.ts.map +1 -1
  49. package/lib/typescript/src/components/Composer/Composer.d.ts.map +1 -1
  50. package/lib/typescript/src/components/Confirmation/Confirmation.d.ts.map +1 -1
  51. package/lib/typescript/src/components/Confirmation/styles.d.ts +13 -2
  52. package/lib/typescript/src/components/Confirmation/styles.d.ts.map +1 -1
  53. package/lib/typescript/src/components/Message/MarkdownContent/styles.d.ts +32 -66
  54. package/lib/typescript/src/components/Message/MarkdownContent/styles.d.ts.map +1 -1
  55. package/lib/typescript/src/components/Message/Message.d.ts.map +1 -1
  56. package/lib/typescript/src/components/Message/MessageWaiting.d.ts +3 -0
  57. package/lib/typescript/src/components/Message/MessageWaiting.d.ts.map +1 -0
  58. package/lib/typescript/src/components/Message/constants.d.ts +3 -0
  59. package/lib/typescript/src/components/Message/constants.d.ts.map +1 -1
  60. package/lib/typescript/src/components/Message/styles.d.ts +40 -2
  61. package/lib/typescript/src/components/Message/styles.d.ts.map +1 -1
  62. package/lib/typescript/src/components/Message/types.d.ts +5 -0
  63. package/lib/typescript/src/components/Message/types.d.ts.map +1 -1
  64. package/lib/typescript/src/components/MessageList/MessageList.d.ts.map +1 -1
  65. package/lib/typescript/src/components/MessageList/MessageListEndButton.d.ts +3 -0
  66. package/lib/typescript/src/components/MessageList/MessageListEndButton.d.ts.map +1 -0
  67. package/lib/typescript/src/components/MessageList/MessageListRow.d.ts +2 -8
  68. package/lib/typescript/src/components/MessageList/MessageListRow.d.ts.map +1 -1
  69. package/lib/typescript/src/components/MessageList/index.d.ts +1 -1
  70. package/lib/typescript/src/components/MessageList/index.d.ts.map +1 -1
  71. package/lib/typescript/src/components/MessageList/styles.d.ts +6 -0
  72. package/lib/typescript/src/components/MessageList/styles.d.ts.map +1 -1
  73. package/lib/typescript/src/components/MessageList/types.d.ts +41 -2
  74. package/lib/typescript/src/components/MessageList/types.d.ts.map +1 -1
  75. package/lib/typescript/src/components/MessageList/useMessageListScroll.d.ts +14 -3
  76. package/lib/typescript/src/components/MessageList/useMessageListScroll.d.ts.map +1 -1
  77. package/lib/typescript/src/components/Process/Process.d.ts.map +1 -1
  78. package/lib/typescript/src/components/Process/ProcessCompactStep.d.ts +1 -1
  79. package/lib/typescript/src/components/Process/ProcessCompactStep.d.ts.map +1 -1
  80. package/lib/typescript/src/components/Process/ProcessTimelineStep.d.ts +5 -0
  81. package/lib/typescript/src/components/Process/ProcessTimelineStep.d.ts.map +1 -0
  82. package/lib/typescript/src/components/Process/styles.d.ts +62 -2
  83. package/lib/typescript/src/components/Process/styles.d.ts.map +1 -1
  84. package/lib/typescript/src/components/Process/types.d.ts +7 -2
  85. package/lib/typescript/src/components/Process/types.d.ts.map +1 -1
  86. package/lib/typescript/src/index.d.ts +1 -1
  87. package/lib/typescript/src/index.d.ts.map +1 -1
  88. package/package.json +1 -1
  89. package/src/components/Attachments/AttachmentItem.tsx +11 -3
  90. package/src/components/Attachments/Attachments.tsx +1 -0
  91. package/src/components/Attachments/styles.ts +1 -0
  92. package/src/components/Attachments/types.ts +2 -1
  93. package/src/components/Composer/Composer.tsx +34 -8
  94. package/src/components/Confirmation/Confirmation.tsx +50 -14
  95. package/src/components/Confirmation/styles.ts +13 -6
  96. package/src/components/Message/MarkdownContent/styles.ts +18 -44
  97. package/src/components/Message/Message.tsx +53 -33
  98. package/src/components/Message/MessageWaiting.tsx +68 -0
  99. package/src/components/Message/constants.ts +4 -0
  100. package/src/components/Message/styles.ts +25 -2
  101. package/src/components/Message/types.ts +6 -0
  102. package/src/components/MessageList/MessageList.tsx +107 -35
  103. package/src/components/MessageList/MessageListEndButton.tsx +61 -0
  104. package/src/components/MessageList/MessageListRow.tsx +12 -12
  105. package/src/components/MessageList/index.ts +1 -0
  106. package/src/components/MessageList/styles.ts +6 -0
  107. package/src/components/MessageList/types.ts +52 -2
  108. package/src/components/MessageList/useMessageListScroll.ts +296 -21
  109. package/src/components/Process/Process.tsx +38 -5
  110. package/src/components/Process/ProcessCompactStep.tsx +32 -13
  111. package/src/components/Process/ProcessTimelineStep.tsx +109 -0
  112. package/src/components/Process/styles.ts +48 -3
  113. package/src/components/Process/types.ts +7 -2
  114. package/src/index.tsx +1 -0
@@ -1,19 +1,25 @@
1
- import { useCallback, useImperativeHandle, useMemo, useRef } from 'react';
1
+ import {
2
+ useCallback,
3
+ useImperativeHandle,
4
+ useLayoutEffect,
5
+ useMemo,
6
+ useRef,
7
+ } from 'react';
2
8
  import type { RefAttributes } from 'react';
3
- import { FlatList, View } from 'react-native';
9
+ import { FlatList, StyleSheet, View } from 'react-native';
4
10
  import type { ListRenderItemInfo } from 'react-native';
5
- import {
6
- Button,
7
- IconButton,
8
- Spinner,
9
- useThemedStyles,
10
- } from '@unif/react-native-design';
11
+ import { Button, useThemedStyles } from '@unif/react-native-design';
11
12
  import { DEFAULT_END_THRESHOLD } from './constants';
12
13
  import { createStyles } from './styles';
13
14
  import { useWebPrependAnchor } from './webPrependAnchor';
14
15
  import { useMessageListScroll } from './useMessageListScroll';
15
16
  import { MessageListRow } from './MessageListRow';
16
- import type { MessageListHandle, MessageListProps } from './types';
17
+ import { MessageListEndButton } from './MessageListEndButton';
18
+ import type {
19
+ MessageListCellProps,
20
+ MessageListHandle,
21
+ MessageListProps,
22
+ } from './types';
17
23
 
18
24
  const MAINTAIN_VISIBLE_POSITION = { minIndexForVisible: 0 };
19
25
 
@@ -44,16 +50,27 @@ export function MessageList<T>({
44
50
  }: MessageListProps<T> & RefAttributes<MessageListHandle>) {
45
51
  const styles = useThemedStyles(createStyles);
46
52
  const listRef = useRef<FlatList<T>>(null);
53
+ const listTestID = useRef(testID);
54
+ listTestID.current = testID;
55
+ const contentStyle = StyleSheet.flatten(contentContainerStyle);
47
56
  const keys = useMemo(() => items.map(keyExtractor), [items, keyExtractor]);
48
57
  const { getRowNativeID, preservingPrependRef, cancelPrependPreservation } =
49
58
  useWebPrependAnchor({ listRef, itemsIdentity: items, keys });
50
59
  const {
51
60
  atEnd,
61
+ anchorMinimumHeight,
62
+ anchorToItem,
63
+ onCellLayout,
64
+ onItemLayout,
65
+ onCellUnmount,
66
+ onFooterLayout,
67
+ onScrollToIndexFailed,
52
68
  scrollToEnd,
53
69
  onLayout,
54
70
  onContentSizeChange,
55
71
  onScroll,
56
72
  onUserScrollBegin,
73
+ onMomentumScrollBegin,
57
74
  onScrollEndDrag,
58
75
  onMomentumScrollEnd,
59
76
  } = useMessageListScroll({
@@ -63,16 +80,68 @@ export function MessageList<T>({
63
80
  followOutput,
64
81
  endThreshold,
65
82
  onAtEndChange,
83
+ hasFooter: !!footer,
84
+ contentMinimumHeight: contentStyle?.minHeight,
85
+ contentBottomPadding:
86
+ contentStyle?.paddingBottom ??
87
+ contentStyle?.paddingVertical ??
88
+ contentStyle?.padding,
66
89
  preservingPrependRef,
67
90
  cancelPrependPreservation,
68
91
  });
69
- useImperativeHandle(ref, () => ({ scrollToEnd }), [scrollToEnd]);
92
+ useImperativeHandle(ref, () => ({ scrollToEnd, anchorToItem }), [
93
+ scrollToEnd,
94
+ anchorToItem,
95
+ ]);
96
+
97
+ const CellRenderer = useCallback(
98
+ function MessageListCell({
99
+ cellKey,
100
+ index,
101
+ children,
102
+ style: cellStyle,
103
+ onLayout: reportLayout,
104
+ onFocusCapture,
105
+ }: MessageListCellProps<T>) {
106
+ const currentIndex = useRef(index);
107
+ currentIndex.current = index;
108
+ useLayoutEffect(
109
+ () => () => onCellUnmount(cellKey, currentIndex.current),
110
+ [cellKey]
111
+ );
112
+ return (
113
+ <View
114
+ style={cellStyle}
115
+ onFocusCapture={onFocusCapture}
116
+ testID={
117
+ listTestID.current
118
+ ? `${listTestID.current}-cell-${encodeURIComponent(cellKey)}`
119
+ : undefined
120
+ }
121
+ onLayout={(event) => {
122
+ reportLayout?.(event);
123
+ onCellLayout(cellKey, index, event.nativeEvent.layout);
124
+ }}
125
+ >
126
+ {children}
127
+ </View>
128
+ );
129
+ },
130
+ [onCellLayout, onCellUnmount]
131
+ );
70
132
 
71
133
  const renderRow = useCallback(
72
134
  ({ item, index }: ListRenderItemInfo<T>) => (
73
135
  <MessageListRow
74
136
  item={item}
75
137
  index={index}
138
+ itemKey={keys[index]!}
139
+ onItemLayout={onItemLayout}
140
+ testID={
141
+ testID
142
+ ? `${testID}-item-${encodeURIComponent(keys[index]!)}`
143
+ : undefined
144
+ }
76
145
  previous={renderSeparator ? items[index - 1] : undefined}
77
146
  nativeID={getRowNativeID(keys[index]!)}
78
147
  renderItem={renderItem}
@@ -80,7 +149,16 @@ export function MessageList<T>({
80
149
  extraData={extraData}
81
150
  />
82
151
  ),
83
- [extraData, getRowNativeID, items, keys, renderItem, renderSeparator]
152
+ [
153
+ extraData,
154
+ getRowNativeID,
155
+ items,
156
+ keys,
157
+ onItemLayout,
158
+ renderItem,
159
+ renderSeparator,
160
+ testID,
161
+ ]
84
162
  );
85
163
 
86
164
  const history = hasEarlier && onRequestEarlier;
@@ -103,8 +181,9 @@ export function MessageList<T>({
103
181
  [hasHeader, header, history, loadingEarlier, onRequestEarlier]
104
182
  );
105
183
  const listFooter = useMemo(
106
- () => (footer ? <View>{footer}</View> : undefined),
107
- [footer]
184
+ () =>
185
+ footer ? <View onLayout={onFooterLayout}>{footer}</View> : undefined,
186
+ [footer, onFooterLayout]
108
187
  );
109
188
  const listEmpty = useMemo(() => (empty ? <>{empty}</> : undefined), [empty]);
110
189
  return (
@@ -117,14 +196,21 @@ export function MessageList<T>({
117
196
  keyExtractor={keyExtractor}
118
197
  extraData={extraData}
119
198
  renderItem={renderRow}
199
+ CellRendererComponent={CellRenderer}
120
200
  ListHeaderComponent={listHeader}
121
201
  ListFooterComponent={listFooter}
122
202
  ListEmptyComponent={listEmpty}
123
203
  maintainVisibleContentPosition={
124
- items.length > 0 ? MAINTAIN_VISIBLE_POSITION : undefined
204
+ items.length > 0 && anchorMinimumHeight === undefined
205
+ ? MAINTAIN_VISIBLE_POSITION
206
+ : undefined
125
207
  }
126
208
  keyboardDismissMode={keyboardDismissMode}
127
- contentContainerStyle={contentContainerStyle}
209
+ contentContainerStyle={
210
+ anchorMinimumHeight
211
+ ? [contentContainerStyle, { minHeight: anchorMinimumHeight }]
212
+ : contentContainerStyle
213
+ }
128
214
  showsVerticalScrollIndicator={showsVerticalScrollIndicator}
129
215
  keyboardShouldPersistTaps="handled"
130
216
  scrollEventThrottle={16}
@@ -132,30 +218,16 @@ export function MessageList<T>({
132
218
  onContentSizeChange={onContentSizeChange}
133
219
  onScroll={onScroll}
134
220
  onScrollBeginDrag={onUserScrollBegin}
135
- onMomentumScrollBegin={onUserScrollBegin}
221
+ onMomentumScrollBegin={onMomentumScrollBegin}
136
222
  onScrollEndDrag={onScrollEndDrag}
137
223
  onMomentumScrollEnd={onMomentumScrollEnd}
224
+ onScrollToIndexFailed={onScrollToIndexFailed}
138
225
  />
139
226
  {showScrollToEnd && items.length > 0 && !atEnd ? (
140
- <View style={styles.returnToEnd} pointerEvents="box-none">
141
- {scrollToEndBusy ? (
142
- <View style={styles.returnProgress} pointerEvents="none">
143
- <Spinner size={44} thickness={2} />
144
- </View>
145
- ) : null}
146
- <IconButton
147
- icon="arrow-down"
148
- accessibilityLabel={
149
- scrollToEndBusy ? '回到最新消息,正在处理' : '回到最新消息'
150
- }
151
- variant="ghost"
152
- size="md"
153
- surfaceSize={36}
154
- iconSize={18}
155
- style={styles.returnButton}
156
- onPress={() => scrollToEnd()}
157
- />
158
- </View>
227
+ <MessageListEndButton
228
+ busy={scrollToEndBusy}
229
+ onPress={() => scrollToEnd()}
230
+ />
159
231
  ) : null}
160
232
  </View>
161
233
  );
@@ -0,0 +1,61 @@
1
+ import { useEffect, useRef } from 'react';
2
+ import { Animated, View } from 'react-native';
3
+ import {
4
+ IconButton,
5
+ Reveal,
6
+ Spinner,
7
+ usePrefersReducedMotion,
8
+ useThemedStyles,
9
+ } from '@unif/react-native-design';
10
+ import { createStyles } from './styles';
11
+ import type { MessageListEndButtonProps } from './types';
12
+
13
+ export function MessageListEndButton({
14
+ busy,
15
+ onPress,
16
+ }: MessageListEndButtonProps) {
17
+ const styles = useThemedStyles(createStyles);
18
+ const reducedMotion = usePrefersReducedMotion();
19
+ const scale = useRef(new Animated.Value(reducedMotion ? 1 : 0.8)).current;
20
+ useEffect(() => {
21
+ if (reducedMotion) {
22
+ scale.setValue(1);
23
+ return;
24
+ }
25
+ const animation = Animated.spring(scale, {
26
+ toValue: 1,
27
+ friction: 6,
28
+ tension: 120,
29
+ useNativeDriver: true,
30
+ });
31
+ animation.start();
32
+ return () => animation.stop();
33
+ }, [reducedMotion, scale]);
34
+ return (
35
+ <View style={styles.returnToEnd} pointerEvents="box-none">
36
+ <Reveal>
37
+ <Animated.View
38
+ style={[styles.returnVisual, { transform: [{ scale }] }]}
39
+ >
40
+ {busy ? (
41
+ <View style={styles.returnProgress} pointerEvents="none">
42
+ <Spinner size={44} thickness={2} />
43
+ </View>
44
+ ) : null}
45
+ <IconButton
46
+ icon="arrow-down"
47
+ accessibilityLabel={
48
+ busy ? '回到最新消息,正在处理' : '回到最新消息'
49
+ }
50
+ variant="ghost"
51
+ size="md"
52
+ surfaceSize={36}
53
+ iconSize={18}
54
+ style={styles.returnButton}
55
+ onPress={onPress}
56
+ />
57
+ </Animated.View>
58
+ </Reveal>
59
+ </View>
60
+ );
61
+ }
@@ -1,29 +1,29 @@
1
1
  import { memo } from 'react';
2
2
  import { View } from 'react-native';
3
- import type { MessageListProps } from './types';
4
-
5
- interface MessageListRowProps<T> extends Pick<
6
- MessageListProps<T>,
7
- 'renderItem' | 'renderSeparator' | 'extraData'
8
- > {
9
- item: T;
10
- previous: T | undefined;
11
- index: number;
12
- nativeID: string;
13
- }
3
+ import type { MessageListRowProps } from './types';
14
4
 
15
5
  function MessageListRowContent<T>({
16
6
  item,
17
7
  previous,
18
8
  index,
19
9
  nativeID,
10
+ itemKey,
11
+ testID,
12
+ onItemLayout,
20
13
  renderItem,
21
14
  renderSeparator,
22
15
  }: MessageListRowProps<T>) {
23
16
  return (
24
17
  <View nativeID={nativeID}>
25
18
  {index > 0 && renderSeparator ? renderSeparator(previous!, item) : null}
26
- {renderItem(item, index)}
19
+ <View
20
+ testID={testID}
21
+ onLayout={(event) =>
22
+ onItemLayout(itemKey, index, event.nativeEvent.layout.y)
23
+ }
24
+ >
25
+ {renderItem(item, index)}
26
+ </View>
27
27
  </View>
28
28
  );
29
29
  }
@@ -1,5 +1,6 @@
1
1
  export { MessageList } from './MessageList';
2
2
  export type {
3
+ MessageListAnchorOptions,
3
4
  MessageListHandle,
4
5
  MessageListProps,
5
6
  MessageListScrollOptions,
@@ -14,6 +14,12 @@ export const createStyles = (colors: ColorTokens, shadows: ShadowTokens) =>
14
14
  justifyContent: 'center',
15
15
  },
16
16
  returnProgress: StyleSheet.absoluteFill,
17
+ returnVisual: {
18
+ width: 44,
19
+ height: 44,
20
+ alignItems: 'center',
21
+ justifyContent: 'center',
22
+ },
17
23
  returnButton: {
18
24
  alignSelf: 'center',
19
25
  borderRadius: 18,
@@ -1,11 +1,23 @@
1
- import type { ReactNode } from 'react';
2
- import type { ScrollViewProps, StyleProp, ViewStyle } from 'react-native';
1
+ import type { ComponentProps, ReactNode } from 'react';
2
+ import type {
3
+ FlatListProps,
4
+ LayoutRectangle,
5
+ ScrollViewProps,
6
+ StyleProp,
7
+ ViewStyle,
8
+ } from 'react-native';
3
9
 
4
10
  export interface MessageListScrollOptions {
5
11
  animated?: boolean;
6
12
  }
13
+ export interface MessageListAnchorOptions extends MessageListScrollOptions {
14
+ /** 正文顶端距列表视口顶部的留白,默认 0。 */
15
+ topOffset?: number;
16
+ }
7
17
  export interface MessageListHandle {
8
18
  scrollToEnd(options?: MessageListScrollOptions): void;
19
+ /** 按稳定 key 等待真实布局并顶锚;用户拖动、回到末尾或目标删除时结束。 */
20
+ anchorToItem(key: string, options?: MessageListAnchorOptions): void;
9
21
  }
10
22
  export interface MessageListProps<T> {
11
23
  items: readonly T[];
@@ -33,8 +45,46 @@ export interface MessageListProps<T> {
33
45
  testID?: string;
34
46
  }
35
47
  export interface ListMeasurements {
48
+ width: number;
36
49
  viewport: number;
37
50
  content: number;
38
51
  offset: number;
39
52
  hasContentSize: boolean;
40
53
  }
54
+ export type MessageListCellProps<T> = ComponentProps<
55
+ NonNullable<FlatListProps<T>['CellRendererComponent']>
56
+ >;
57
+ export interface MessageListRowProps<T> extends Pick<
58
+ MessageListProps<T>,
59
+ 'renderItem' | 'renderSeparator' | 'extraData'
60
+ > {
61
+ item: T;
62
+ previous: T | undefined;
63
+ index: number;
64
+ itemKey: string;
65
+ nativeID: string;
66
+ testID?: string;
67
+ onItemLayout(key: string, index: number, y: number): void;
68
+ }
69
+ export interface MessageListItemLayout {
70
+ index: number;
71
+ cell?: LayoutRectangle;
72
+ itemY?: number;
73
+ }
74
+ export interface MessageListAnchorRequest {
75
+ key: string;
76
+ topOffset: number;
77
+ animated: boolean;
78
+ seen: boolean;
79
+ locatedAt?: number;
80
+ offset?: number;
81
+ viewport?: number;
82
+ settled?: boolean;
83
+ }
84
+ export interface MessageListPendingScroll extends MessageListScrollOptions {
85
+ contentBeforeRelease?: number;
86
+ }
87
+ export interface MessageListEndButtonProps {
88
+ busy: boolean;
89
+ onPress(): void;
90
+ }