@planningcenter/chat-react-native 4.4.1-qa-staging.13 → 4.4.1-qa-staging.15
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/build/components/conversation/message.d.ts +2 -1
- package/build/components/conversation/message.d.ts.map +1 -1
- package/build/components/conversation/message.js +190 -161
- package/build/components/conversation/message.js.map +1 -1
- package/build/components/conversation/message_list.d.ts.map +1 -1
- package/build/components/conversation/message_list.js +35 -31
- package/build/components/conversation/message_list.js.map +1 -1
- package/build/components/conversation/message_reaction.d.ts +2 -1
- package/build/components/conversation/message_reaction.d.ts.map +1 -1
- package/build/components/conversation/message_reaction.js +67 -60
- package/build/components/conversation/message_reaction.js.map +1 -1
- package/build/components/conversation/messages_disabled_banners.d.ts +7 -5
- package/build/components/conversation/messages_disabled_banners.d.ts.map +1 -1
- package/build/components/conversation/messages_disabled_banners.js +15 -14
- package/build/components/conversation/messages_disabled_banners.js.map +1 -1
- package/build/components/conversation/reply_shadow_message.d.ts.map +1 -1
- package/build/components/conversation/reply_shadow_message.js +84 -83
- package/build/components/conversation/reply_shadow_message.js.map +1 -1
- package/build/components/conversation/system_message.d.ts +2 -1
- package/build/components/conversation/system_message.d.ts.map +1 -1
- package/build/components/conversation/system_message.js +87 -65
- package/build/components/conversation/system_message.js.map +1 -1
- package/build/components/display/filter_dropdown.d.ts +13 -0
- package/build/components/display/filter_dropdown.d.ts.map +1 -0
- package/build/components/display/filter_dropdown.js +188 -0
- package/build/components/display/filter_dropdown.js.map +1 -0
- package/build/components/display/index.d.ts +1 -0
- package/build/components/display/index.d.ts.map +1 -1
- package/build/components/display/index.js +1 -0
- package/build/components/display/index.js.map +1 -1
- package/build/hooks/use_conversation.d.ts +73 -1
- package/build/hooks/use_conversation.d.ts.map +1 -1
- package/build/hooks/use_conversation.js +122 -3
- package/build/hooks/use_conversation.js.map +1 -1
- package/build/hooks/use_unarchive_conversation_action.d.ts +7 -0
- package/build/hooks/use_unarchive_conversation_action.d.ts.map +1 -0
- package/build/hooks/use_unarchive_conversation_action.js +52 -0
- package/build/hooks/use_unarchive_conversation_action.js.map +1 -0
- package/build/screens/attachment_actions/attachment_actions_screen.d.ts.map +1 -1
- package/build/screens/attachment_actions/attachment_actions_screen.js +84 -61
- package/build/screens/attachment_actions/attachment_actions_screen.js.map +1 -1
- package/build/screens/conversation_details_screen.d.ts.map +1 -1
- package/build/screens/conversation_details_screen.js +487 -393
- package/build/screens/conversation_details_screen.js.map +1 -1
- package/build/screens/conversation_screen.d.ts.map +1 -1
- package/build/screens/conversation_screen.js +12 -9
- package/build/screens/conversation_screen.js.map +1 -1
- package/build/screens/design_system_screen.d.ts.map +1 -1
- package/build/screens/design_system_screen.js +275 -215
- package/build/screens/design_system_screen.js.map +1 -1
- package/build/screens/message_actions_screen.d.ts.map +1 -1
- package/build/screens/message_actions_screen.js +112 -92
- package/build/screens/message_actions_screen.js.map +1 -1
- package/build/types/resources/member_ability.d.ts +2 -0
- package/build/types/resources/member_ability.d.ts.map +1 -1
- package/build/types/resources/member_ability.js.map +1 -1
- package/build/utils/archived_conversation.d.ts +5 -0
- package/build/utils/archived_conversation.d.ts.map +1 -0
- package/build/utils/archived_conversation.js +5 -0
- package/build/utils/archived_conversation.js.map +1 -0
- package/build/utils/index.d.ts +1 -0
- package/build/utils/index.d.ts.map +1 -1
- package/build/utils/index.js +1 -0
- package/build/utils/index.js.map +1 -1
- package/build/utils/native_adapters/configuration.d.ts +3 -0
- package/build/utils/native_adapters/configuration.d.ts.map +1 -1
- package/build/utils/native_adapters/configuration.js +3 -0
- package/build/utils/native_adapters/configuration.js.map +1 -1
- package/build/utils/native_adapters/index.d.ts +1 -0
- package/build/utils/native_adapters/index.d.ts.map +1 -1
- package/build/utils/native_adapters/index.js +1 -0
- package/build/utils/native_adapters/index.js.map +1 -1
- package/build/utils/native_adapters/menu.d.ts +40 -0
- package/build/utils/native_adapters/menu.d.ts.map +1 -0
- package/build/utils/native_adapters/menu.js +55 -0
- package/build/utils/native_adapters/menu.js.map +1 -0
- package/package.json +3 -3
- package/src/__tests__/screens/message_actions_screen.test.tsx +65 -2
- package/src/components/conversation/__tests__/message_list.test.tsx +68 -2
- package/src/components/conversation/__tests__/system_message.test.tsx +3 -1
- package/src/components/conversation/message.tsx +11 -14
- package/src/components/conversation/message_list.tsx +9 -1
- package/src/components/conversation/message_reaction.tsx +7 -2
- package/src/components/conversation/messages_disabled_banners.tsx +17 -18
- package/src/components/conversation/reply_shadow_message.tsx +9 -8
- package/src/components/conversation/system_message.tsx +24 -10
- package/src/components/display/__tests__/filter_dropdown.test.tsx +106 -0
- package/src/components/display/filter_dropdown.tsx +123 -0
- package/src/components/display/index.ts +1 -0
- package/src/hooks/__tests__/use_conversation_archive.test.tsx +130 -0
- package/src/hooks/__tests__/use_conversation_jolt_events.test.tsx +74 -0
- package/src/hooks/__tests__/use_unarchive_conversation_action.test.tsx +67 -0
- package/src/hooks/use_conversation.ts +41 -3
- package/src/hooks/use_unarchive_conversation_action.ts +24 -0
- package/src/screens/__tests__/conversation_details_screen.test.tsx +289 -0
- package/src/screens/attachment_actions/__tests__/attachment_actions_screen.test.tsx +72 -0
- package/src/screens/attachment_actions/attachment_actions_screen.tsx +3 -1
- package/src/screens/conversation_details_screen.tsx +78 -14
- package/src/screens/conversation_screen.tsx +3 -1
- package/src/screens/design_system_screen.tsx +26 -0
- package/src/screens/message_actions_screen.tsx +29 -20
- package/src/types/resources/member_ability.ts +2 -0
- package/src/utils/archived_conversation.ts +13 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/native_adapters/__tests__/menu.test.tsx +42 -0
- package/src/utils/native_adapters/configuration.ts +5 -0
- package/src/utils/native_adapters/index.ts +1 -0
- package/src/utils/native_adapters/menu.tsx +68 -0
|
@@ -40,6 +40,7 @@ import {
|
|
|
40
40
|
usePublishProductAnalyticsEvent,
|
|
41
41
|
} from '../hooks/use_product_analytics'
|
|
42
42
|
import { useRestAwayFromDismissEdge } from '../hooks/use_rest_away_from_dismiss_edge'
|
|
43
|
+
import { useUnarchiveConversationAction } from '../hooks/use_unarchive_conversation_action'
|
|
43
44
|
import { useVideoModerationJoltEvents } from '../hooks/use_video_moderation_jolt_events'
|
|
44
45
|
import { ConversationResource } from '../types/resources/conversation'
|
|
45
46
|
import { ConversationBadgeResource } from '../types/resources/conversation_badge'
|
|
@@ -265,12 +266,13 @@ function ConversationBottomBar({
|
|
|
265
266
|
onBeforeSubmit,
|
|
266
267
|
}: ConversationBottomBarProps) {
|
|
267
268
|
const messageLink = useMessageAvailableMembersAction(conversation)
|
|
269
|
+
const unarchiveAction = useUnarchiveConversationAction(conversation)
|
|
268
270
|
|
|
269
271
|
if (conversation.disabled)
|
|
270
272
|
return (
|
|
271
273
|
<ConversationDisabledBanner
|
|
272
274
|
message={conversation.disabledMessage ?? null}
|
|
273
|
-
|
|
275
|
+
action={unarchiveAction ?? messageLink}
|
|
274
276
|
/>
|
|
275
277
|
)
|
|
276
278
|
if (!canReply) return <MemberMessagesDisabledBanner />
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
Button,
|
|
13
13
|
ConversationAvatar,
|
|
14
14
|
EmojiAvatar,
|
|
15
|
+
FilterDropdown,
|
|
15
16
|
IconAvatar,
|
|
16
17
|
ToggleButton,
|
|
17
18
|
Heading,
|
|
@@ -82,6 +83,14 @@ const personChild = {
|
|
|
82
83
|
|
|
83
84
|
const buttonPress = () => Alert.alert('Button clicked')
|
|
84
85
|
|
|
86
|
+
const filterDropdownOptions = [
|
|
87
|
+
{ id: 'all', label: 'All conversations' },
|
|
88
|
+
{ id: 'groups', label: 'Groups' },
|
|
89
|
+
{ id: 'teams', label: 'Teams' },
|
|
90
|
+
{ id: 'dms', label: 'DMs' },
|
|
91
|
+
{ id: 'unread', label: 'Unread' },
|
|
92
|
+
]
|
|
93
|
+
|
|
85
94
|
// =================================
|
|
86
95
|
// ====== Component ================
|
|
87
96
|
// =================================
|
|
@@ -213,6 +222,7 @@ function HeadingTextSection({ isLast }: SectionProps) {
|
|
|
213
222
|
function PressablesSection({ isLast }: SectionProps) {
|
|
214
223
|
const styles = useStyles()
|
|
215
224
|
const [filterSelected, setFilterSelected] = useState('Groups')
|
|
225
|
+
const [dropdownSelected, setDropdownSelected] = useState('all')
|
|
216
226
|
|
|
217
227
|
return (
|
|
218
228
|
<CollapsableSection title="Pressables" isLast={isLast}>
|
|
@@ -388,6 +398,22 @@ function PressablesSection({ isLast }: SectionProps) {
|
|
|
388
398
|
/>
|
|
389
399
|
</Row>
|
|
390
400
|
</Group>
|
|
401
|
+
<Group
|
|
402
|
+
title="FilterDropdown"
|
|
403
|
+
description="Trigger that opens the host's native menu of filter options plus a More filters action. Needs a menu adapter."
|
|
404
|
+
>
|
|
405
|
+
<Row style={styles.alignRowLeft}>
|
|
406
|
+
<FilterDropdown
|
|
407
|
+
options={filterDropdownOptions}
|
|
408
|
+
selectedId={dropdownSelected}
|
|
409
|
+
onSelect={setDropdownSelected}
|
|
410
|
+
onMoreFilters={() => Alert.alert('More filters')}
|
|
411
|
+
triggerLabel={
|
|
412
|
+
filterDropdownOptions.find(option => option.id === dropdownSelected)?.label ?? ''
|
|
413
|
+
}
|
|
414
|
+
/>
|
|
415
|
+
</Row>
|
|
416
|
+
</Group>
|
|
391
417
|
<Group
|
|
392
418
|
title="IconButton"
|
|
393
419
|
description="Supports different appearances, sizes, along with loading & disabled states. Use `iconStyle` for custom colors and font sizes. Requires `accessibilityLabel` as icon's don't provide context to screen readers."
|
|
@@ -9,6 +9,7 @@ import { useReactionStyles } from '../components/conversation/message_reaction'
|
|
|
9
9
|
import FormSheet, { getFormSheetScreenOptions } from '../components/primitive/form_sheet'
|
|
10
10
|
import { useCreateAndroidRippleColor, useFontScale, useTheme } from '../hooks'
|
|
11
11
|
import { useApiClient } from '../hooks/use_api_client'
|
|
12
|
+
import { useConversation } from '../hooks/use_conversation'
|
|
12
13
|
import { useConversationMessages } from '../hooks/use_conversation_messages'
|
|
13
14
|
import { availableFeatures, useFeatures } from '../hooks/use_features'
|
|
14
15
|
import { useMessageReactionToggle } from '../hooks/use_message_reaction_toggle'
|
|
@@ -49,6 +50,7 @@ export function MessageActionsScreen({ route }: MessageActionsScreenProps) {
|
|
|
49
50
|
{ conversation_id },
|
|
50
51
|
{ refetchOnMount: false }
|
|
51
52
|
)
|
|
53
|
+
const { data: conversation } = useConversation({ conversation_id }, { refetchOnMount: false })
|
|
52
54
|
const message = messages.find(m => m.id === message_id)
|
|
53
55
|
|
|
54
56
|
if (!message) return null
|
|
@@ -57,6 +59,7 @@ export function MessageActionsScreen({ route }: MessageActionsScreenProps) {
|
|
|
57
59
|
<MessageActionsScreenContent
|
|
58
60
|
message={message}
|
|
59
61
|
conversation_id={conversation_id}
|
|
62
|
+
conversationDisabled={!!conversation.disabled}
|
|
60
63
|
canDeleteNonAuthoredMessages={canDeleteNonAuthoredMessages || false}
|
|
61
64
|
refetchMessages={refetch}
|
|
62
65
|
inReplyScreen={inReplyScreen}
|
|
@@ -69,6 +72,7 @@ export function MessageActionsScreen({ route }: MessageActionsScreenProps) {
|
|
|
69
72
|
function MessageActionsScreenContent({
|
|
70
73
|
message,
|
|
71
74
|
conversation_id,
|
|
75
|
+
conversationDisabled,
|
|
72
76
|
canDeleteNonAuthoredMessages,
|
|
73
77
|
refetchMessages,
|
|
74
78
|
inReplyScreen,
|
|
@@ -77,6 +81,7 @@ function MessageActionsScreenContent({
|
|
|
77
81
|
}: {
|
|
78
82
|
message: MessageResource
|
|
79
83
|
conversation_id: number
|
|
84
|
+
conversationDisabled: boolean
|
|
80
85
|
canDeleteNonAuthoredMessages: boolean
|
|
81
86
|
refetchMessages: () => void
|
|
82
87
|
inReplyScreen?: boolean
|
|
@@ -241,28 +246,32 @@ function MessageActionsScreenContent({
|
|
|
241
246
|
|
|
242
247
|
const showReportMessageAction =
|
|
243
248
|
!message?.mine && featureEnabled(availableFeatures.message_reporting)
|
|
249
|
+
const showDeleteMessageAction =
|
|
250
|
+
!conversationDisabled && (message?.mine || canDeleteNonAuthoredMessages)
|
|
244
251
|
|
|
245
252
|
return (
|
|
246
253
|
<FormSheet.Root style={styles.formSheetContent}>
|
|
247
|
-
|
|
248
|
-
{
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
254
|
+
{!conversationDisabled && (
|
|
255
|
+
<View style={styles.reactionList}>
|
|
256
|
+
{availableReactions.map((reaction, index) => (
|
|
257
|
+
<Reaction
|
|
258
|
+
key={index}
|
|
259
|
+
reaction={reaction}
|
|
260
|
+
onPress={() => {
|
|
261
|
+
Haptic.impactLight()
|
|
262
|
+
handleReactionToggle({
|
|
263
|
+
value: reaction.value,
|
|
264
|
+
mine: reaction.mine,
|
|
265
|
+
})
|
|
266
|
+
navigation.goBack()
|
|
267
|
+
}}
|
|
268
|
+
/>
|
|
269
|
+
))}
|
|
270
|
+
</View>
|
|
271
|
+
)}
|
|
263
272
|
{!isSystemMessage && (
|
|
264
273
|
<View style={styles.actions}>
|
|
265
|
-
{!inReplyScreen && (
|
|
274
|
+
{!inReplyScreen && !conversationDisabled && (
|
|
266
275
|
<FormSheet.Action
|
|
267
276
|
onPress={handleReplyPress}
|
|
268
277
|
title="Reply to message"
|
|
@@ -285,7 +294,7 @@ function MessageActionsScreenContent({
|
|
|
285
294
|
accessibilityHint="Opens a form to report this message"
|
|
286
295
|
/>
|
|
287
296
|
)}
|
|
288
|
-
{message?.mine && (
|
|
297
|
+
{message?.mine && !conversationDisabled && (
|
|
289
298
|
<FormSheet.Action
|
|
290
299
|
onPress={() => handleEditPress()}
|
|
291
300
|
title="Edit message"
|
|
@@ -301,7 +310,7 @@ function MessageActionsScreenContent({
|
|
|
301
310
|
accessibilityHint="Opens a modal with a list of people who read your message."
|
|
302
311
|
/>
|
|
303
312
|
)}
|
|
304
|
-
{message?.mine && hasExpandedLink && (
|
|
313
|
+
{message?.mine && hasExpandedLink && !conversationDisabled && (
|
|
305
314
|
<FormSheet.Action
|
|
306
315
|
onPress={() => handleRemoveLinkPreviewConfirm()}
|
|
307
316
|
title="Remove link preview"
|
|
@@ -309,7 +318,7 @@ function MessageActionsScreenContent({
|
|
|
309
318
|
accessibilityHint="Removes an expanded link preview from the message."
|
|
310
319
|
/>
|
|
311
320
|
)}
|
|
312
|
-
{
|
|
321
|
+
{showDeleteMessageAction && (
|
|
313
322
|
<FormSheet.Action
|
|
314
323
|
onPress={() => handleDeleteConfirm()}
|
|
315
324
|
title="Delete message"
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ConversationResource } from '../types/resources/conversation'
|
|
2
|
+
|
|
3
|
+
export const ARCHIVED_DISABLED_REASON = 'archived'
|
|
4
|
+
|
|
5
|
+
const DEFAULT_ARCHIVED_MESSAGE = 'This conversation is archived.'
|
|
6
|
+
|
|
7
|
+
export const isArchivedConversation = (
|
|
8
|
+
conversation: Pick<ConversationResource, 'disabledReason'>
|
|
9
|
+
) => conversation.disabledReason === ARCHIVED_DISABLED_REASON
|
|
10
|
+
|
|
11
|
+
export const archivedConversationMessage = (
|
|
12
|
+
conversation: Pick<ConversationResource, 'disabledMessage'>
|
|
13
|
+
) => conversation.disabledMessage || DEFAULT_ARCHIVED_MESSAGE
|
package/src/utils/index.ts
CHANGED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { render, screen } from '@testing-library/react-native'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
import { Text } from 'react-native'
|
|
4
|
+
import { MenuAdapter, MenuViewProps } from '../menu'
|
|
5
|
+
|
|
6
|
+
const actions = [{ id: 'all', title: 'All' }]
|
|
7
|
+
|
|
8
|
+
describe('MenuAdapter', () => {
|
|
9
|
+
it('renders the trigger and warns when the host configured no menu', () => {
|
|
10
|
+
const warn = jest.spyOn(console, 'warn').mockImplementation(() => {})
|
|
11
|
+
const { View } = new MenuAdapter()
|
|
12
|
+
|
|
13
|
+
render(
|
|
14
|
+
<View actions={actions}>
|
|
15
|
+
<Text>Trigger</Text>
|
|
16
|
+
</View>
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
expect(screen.getByText('Trigger')).toBeTruthy()
|
|
20
|
+
expect(warn).toHaveBeenCalledTimes(1)
|
|
21
|
+
warn.mockRestore()
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
it('renders through the view the host supplies', () => {
|
|
25
|
+
const HostMenuView = ({ actions: hostActions, children }: MenuViewProps) => (
|
|
26
|
+
<>
|
|
27
|
+
{children}
|
|
28
|
+
<Text>{hostActions.map(action => action.title).join(',')}</Text>
|
|
29
|
+
</>
|
|
30
|
+
)
|
|
31
|
+
const { View } = new MenuAdapter({ View: HostMenuView })
|
|
32
|
+
|
|
33
|
+
render(
|
|
34
|
+
<View actions={actions}>
|
|
35
|
+
<Text>Trigger</Text>
|
|
36
|
+
</View>
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
expect(screen.getByText('Trigger')).toBeTruthy()
|
|
40
|
+
expect(screen.getByText('All')).toBeTruthy()
|
|
41
|
+
})
|
|
42
|
+
})
|
|
@@ -7,6 +7,7 @@ import { HapticAdapter } from './haptic'
|
|
|
7
7
|
import { ImagePickerAdapter } from './image_picker'
|
|
8
8
|
import { LinkingAdapter } from './linking'
|
|
9
9
|
import { LogAdapter } from './log'
|
|
10
|
+
import { MenuAdapter } from './menu'
|
|
10
11
|
import { StorageAdapter } from './storage_adapter'
|
|
11
12
|
import { VideoAdapter } from './video'
|
|
12
13
|
|
|
@@ -19,6 +20,7 @@ type ChatConfigurations = {
|
|
|
19
20
|
log?: LogAdapter
|
|
20
21
|
linking?: LinkingAdapter
|
|
21
22
|
haptic?: HapticAdapter
|
|
23
|
+
menu?: MenuAdapter
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
export class ChatAdapters {
|
|
@@ -31,6 +33,7 @@ export class ChatAdapters {
|
|
|
31
33
|
Log = configurations.log || new LogAdapter()
|
|
32
34
|
Linking = configurations.linking || new LinkingAdapter(RNLinking)
|
|
33
35
|
Haptic = configurations.haptic || new HapticAdapter()
|
|
36
|
+
Menu = configurations.menu || new MenuAdapter()
|
|
34
37
|
}
|
|
35
38
|
}
|
|
36
39
|
|
|
@@ -82,6 +85,8 @@ export let Linking: LinkingAdapter = new LinkingAdapter(RNLinking)
|
|
|
82
85
|
|
|
83
86
|
export let Haptic: HapticAdapter = new HapticAdapter()
|
|
84
87
|
|
|
88
|
+
export let Menu: MenuAdapter = new MenuAdapter()
|
|
89
|
+
|
|
85
90
|
export let Storage = new StorageAdapter({
|
|
86
91
|
getItem: AsyncStorage.getItem,
|
|
87
92
|
setItem: AsyncStorage.setItem,
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import React, { useEffect } from 'react'
|
|
2
|
+
import { StyleProp, View, ViewStyle } from 'react-native'
|
|
3
|
+
|
|
4
|
+
// =================================
|
|
5
|
+
// ====== Types ====================
|
|
6
|
+
// =================================
|
|
7
|
+
|
|
8
|
+
// Mirrors the props shared by `@expo/ui/community/menu` and
|
|
9
|
+
// `@react-native-menu/menu`, so a host can pass either `MenuView` straight in.
|
|
10
|
+
|
|
11
|
+
export type MenuActionState = 'on' | 'off'
|
|
12
|
+
|
|
13
|
+
export interface MenuActionAttributes {
|
|
14
|
+
destructive?: boolean
|
|
15
|
+
disabled?: boolean
|
|
16
|
+
hidden?: boolean
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface MenuAction {
|
|
20
|
+
id?: string
|
|
21
|
+
title: string
|
|
22
|
+
state?: MenuActionState
|
|
23
|
+
attributes?: MenuActionAttributes
|
|
24
|
+
subactions?: MenuAction[]
|
|
25
|
+
displayInline?: boolean
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface MenuActionEvent {
|
|
29
|
+
nativeEvent: { event: string }
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface MenuViewProps {
|
|
33
|
+
actions: MenuAction[]
|
|
34
|
+
onPressAction?: (event: MenuActionEvent) => void
|
|
35
|
+
onOpenMenu?: () => void
|
|
36
|
+
onCloseMenu?: () => void
|
|
37
|
+
shouldOpenOnLongPress?: boolean
|
|
38
|
+
title?: string
|
|
39
|
+
style?: StyleProp<ViewStyle>
|
|
40
|
+
testID?: string
|
|
41
|
+
children?: React.ReactNode
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export type MenuView = React.ComponentType<MenuViewProps>
|
|
45
|
+
|
|
46
|
+
// =================================
|
|
47
|
+
// ====== Adapter ==================
|
|
48
|
+
// =================================
|
|
49
|
+
|
|
50
|
+
function UnconfiguredMenuView({ children, style, testID }: MenuViewProps) {
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
console.warn('ChatAdapters.configure() must include a menu adapter before rendering a menu')
|
|
53
|
+
}, [])
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<View style={style} testID={testID}>
|
|
57
|
+
{children}
|
|
58
|
+
</View>
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export class MenuAdapter {
|
|
63
|
+
View: MenuView
|
|
64
|
+
|
|
65
|
+
constructor(methods?: { View: MenuView }) {
|
|
66
|
+
this.View = methods?.View ?? UnconfiguredMenuView
|
|
67
|
+
}
|
|
68
|
+
}
|