@planningcenter/chat-react-native 3.1.0-rc.9 → 3.2.0-rc.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/build/components/conversation/attachments/attachment_card.d.ts +9 -0
- package/build/components/conversation/attachments/attachment_card.d.ts.map +1 -0
- package/build/components/conversation/attachments/attachment_card.js +35 -0
- package/build/components/conversation/attachments/attachment_card.js.map +1 -0
- package/build/components/conversation/attachments/audio_attachment.d.ts +6 -0
- package/build/components/conversation/attachments/audio_attachment.d.ts.map +1 -0
- package/build/components/conversation/attachments/audio_attachment.js +84 -0
- package/build/components/conversation/attachments/audio_attachment.js.map +1 -0
- package/build/components/conversation/attachments/constants.d.ts +3 -0
- package/build/components/conversation/attachments/constants.d.ts.map +1 -0
- package/build/components/conversation/attachments/constants.js +4 -0
- package/build/components/conversation/attachments/constants.js.map +1 -0
- package/build/components/conversation/attachments/download_attachment_button.d.ts +9 -0
- package/build/components/conversation/attachments/download_attachment_button.d.ts.map +1 -0
- package/build/components/conversation/attachments/download_attachment_button.js +29 -0
- package/build/components/conversation/attachments/download_attachment_button.js.map +1 -0
- package/build/components/conversation/attachments/expanded_link.d.ts +5 -0
- package/build/components/conversation/attachments/expanded_link.d.ts.map +1 -0
- package/build/components/conversation/attachments/expanded_link.js +44 -0
- package/build/components/conversation/attachments/expanded_link.js.map +1 -0
- package/build/components/conversation/attachments/generic_file_attachment.d.ts +7 -0
- package/build/components/conversation/attachments/generic_file_attachment.d.ts.map +1 -0
- package/build/components/conversation/attachments/generic_file_attachment.js +63 -0
- package/build/components/conversation/attachments/generic_file_attachment.js.map +1 -0
- package/build/components/conversation/attachments/giphy_attachment.d.ts +6 -0
- package/build/components/conversation/attachments/giphy_attachment.d.ts.map +1 -0
- package/build/components/conversation/attachments/giphy_attachment.js +42 -0
- package/build/components/conversation/attachments/giphy_attachment.js.map +1 -0
- package/build/components/conversation/attachments/image_attachment.d.ts +5 -0
- package/build/components/conversation/attachments/image_attachment.d.ts.map +1 -0
- package/build/components/conversation/attachments/image_attachment.js +24 -0
- package/build/components/conversation/attachments/image_attachment.js.map +1 -0
- package/build/components/conversation/attachments/video_attachment.d.ts +6 -0
- package/build/components/conversation/attachments/video_attachment.d.ts.map +1 -0
- package/build/components/conversation/attachments/video_attachment.js +64 -0
- package/build/components/conversation/attachments/video_attachment.js.map +1 -0
- package/build/components/conversation/message.d.ts +1 -1
- package/build/components/conversation/message.d.ts.map +1 -1
- package/build/components/conversation/message.js +13 -7
- package/build/components/conversation/message.js.map +1 -1
- package/build/components/conversation/message_attachments.d.ts +6 -0
- package/build/components/conversation/message_attachments.d.ts.map +1 -0
- package/build/components/conversation/message_attachments.js +52 -0
- package/build/components/conversation/message_attachments.js.map +1 -0
- package/build/components/conversation/message_markdown.d.ts +7 -0
- package/build/components/conversation/message_markdown.d.ts.map +1 -0
- package/build/components/conversation/message_markdown.js +38 -0
- package/build/components/conversation/message_markdown.js.map +1 -0
- package/build/components/conversations/conversation_preview.d.ts +9 -0
- package/build/components/conversations/conversation_preview.d.ts.map +1 -0
- package/build/components/conversations/conversation_preview.js +58 -0
- package/build/components/conversations/conversation_preview.js.map +1 -0
- package/build/components/conversations/conversations.d.ts +8 -0
- package/build/components/conversations/conversations.d.ts.map +1 -0
- package/build/components/conversations/conversations.js +40 -0
- package/build/components/conversations/conversations.js.map +1 -0
- package/build/components/conversations/unread_count_badge.d.ts +5 -0
- package/build/components/conversations/unread_count_badge.d.ts.map +1 -0
- package/build/components/conversations/unread_count_badge.js +33 -0
- package/build/components/conversations/unread_count_badge.js.map +1 -0
- package/build/components/display/badge.d.ts +9 -1
- package/build/components/display/badge.d.ts.map +1 -1
- package/build/components/display/badge.js +22 -10
- package/build/components/display/badge.js.map +1 -1
- package/build/components/display/button.d.ts +1 -1
- package/build/components/display/button.d.ts.map +1 -1
- package/build/components/display/button.js.map +1 -1
- package/build/components/display/child_notice.js +2 -2
- package/build/components/display/child_notice.js.map +1 -1
- package/build/components/display/icon.d.ts.map +1 -1
- package/build/components/display/icon.js +10 -8
- package/build/components/display/icon.js.map +1 -1
- package/build/components/display/text.js +2 -8
- package/build/components/display/text.js.map +1 -1
- package/build/components/index.d.ts +1 -1
- package/build/components/index.d.ts.map +1 -1
- package/build/components/index.js +1 -1
- package/build/components/index.js.map +1 -1
- package/build/components/page/error_boundary.d.ts +1 -1
- package/build/hooks/use_api.d.ts +6 -4
- package/build/hooks/use_api.d.ts.map +1 -1
- package/build/hooks/use_api.js +5 -2
- package/build/hooks/use_api.js.map +1 -1
- package/build/hooks/use_api_client.d.ts +1 -2
- package/build/hooks/use_api_client.d.ts.map +1 -1
- package/build/hooks/use_api_client.js.map +1 -1
- package/build/hooks/use_conversation.d.ts +76 -0
- package/build/hooks/use_conversation.d.ts.map +1 -1
- package/build/hooks/use_conversation.js +47 -3
- package/build/hooks/use_conversation.js.map +1 -1
- package/build/hooks/use_conversation_jolt_events.js +1 -1
- package/build/hooks/use_conversation_jolt_events.js.map +1 -1
- package/build/hooks/use_conversation_messages_jolt_events.js +1 -1
- package/build/hooks/use_conversation_messages_jolt_events.js.map +1 -1
- package/build/hooks/use_conversations.d.ts +2 -3
- package/build/hooks/use_conversations.d.ts.map +1 -1
- package/build/hooks/use_conversations.js +3 -29
- package/build/hooks/use_conversations.js.map +1 -1
- package/build/hooks/use_groups.d.ts +214 -0
- package/build/hooks/use_groups.d.ts.map +1 -0
- package/build/hooks/use_groups.js +22 -0
- package/build/hooks/use_groups.js.map +1 -0
- package/build/hooks/use_groups_groups.d.ts +208 -0
- package/build/hooks/use_groups_groups.d.ts.map +1 -0
- package/build/hooks/use_groups_groups.js +18 -0
- package/build/hooks/use_groups_groups.js.map +1 -0
- package/build/hooks/use_services_team.d.ts +4 -0
- package/build/hooks/use_services_team.d.ts.map +1 -0
- package/build/hooks/use_services_team.js +22 -0
- package/build/hooks/use_services_team.js.map +1 -0
- package/build/hooks/use_suspense_api.d.ts +2 -1
- package/build/hooks/use_suspense_api.d.ts.map +1 -1
- package/build/hooks/use_suspense_api.js +2 -1
- package/build/hooks/use_suspense_api.js.map +1 -1
- package/build/hooks/use_teams.d.ts +208 -0
- package/build/hooks/use_teams.d.ts.map +1 -0
- package/build/hooks/use_teams.js +22 -0
- package/build/hooks/use_teams.js.map +1 -0
- package/build/navigation/index.d.ts +4 -0
- package/build/navigation/index.d.ts.map +1 -1
- package/build/navigation/index.js +5 -0
- package/build/navigation/index.js.map +1 -1
- package/build/screens/conversation_details_screen.d.ts.map +1 -1
- package/build/screens/conversation_details_screen.js +139 -59
- package/build/screens/conversation_details_screen.js.map +1 -1
- package/build/screens/conversation_filters/components/conversation_filters.d.ts +3 -0
- package/build/screens/conversation_filters/components/conversation_filters.d.ts.map +1 -0
- package/build/screens/conversation_filters/components/conversation_filters.js +173 -0
- package/build/screens/conversation_filters/components/conversation_filters.js.map +1 -0
- package/build/screens/conversation_filters/components/rows.d.ts +31 -0
- package/build/screens/conversation_filters/components/rows.d.ts.map +1 -0
- package/build/screens/conversation_filters/components/rows.js +111 -0
- package/build/screens/conversation_filters/components/rows.js.map +1 -0
- package/build/screens/conversation_filters/context/conversation_filter_context.d.ts +23 -0
- package/build/screens/conversation_filters/context/conversation_filter_context.d.ts.map +1 -0
- package/build/screens/conversation_filters/context/conversation_filter_context.js +51 -0
- package/build/screens/conversation_filters/context/conversation_filter_context.js.map +1 -0
- package/build/screens/conversation_filters/filter_types.d.ts +7 -0
- package/build/screens/conversation_filters/filter_types.d.ts.map +1 -0
- package/build/screens/conversation_filters/filter_types.js +8 -0
- package/build/screens/conversation_filters/filter_types.js.map +1 -0
- package/build/screens/conversation_filters/group_filters.d.ts +6 -0
- package/build/screens/conversation_filters/group_filters.d.ts.map +1 -0
- package/build/screens/conversation_filters/group_filters.js +15 -0
- package/build/screens/conversation_filters/group_filters.js.map +1 -0
- package/build/screens/conversation_filters/hooks/filters.d.ts +415 -0
- package/build/screens/conversation_filters/hooks/filters.d.ts.map +1 -0
- package/build/screens/conversation_filters/hooks/filters.js +41 -0
- package/build/screens/conversation_filters/hooks/filters.js.map +1 -0
- package/build/screens/conversation_filters/screen_props.d.ts +13 -0
- package/build/screens/conversation_filters/screen_props.d.ts.map +1 -0
- package/build/screens/conversation_filters/screen_props.js +2 -0
- package/build/screens/conversation_filters/screen_props.js.map +1 -0
- package/build/screens/conversation_filters/team_filters.d.ts +6 -0
- package/build/screens/conversation_filters/team_filters.d.ts.map +1 -0
- package/build/screens/conversation_filters/team_filters.js +15 -0
- package/build/screens/conversation_filters/team_filters.js.map +1 -0
- package/build/screens/conversation_filters_screen.d.ts +6 -0
- package/build/screens/conversation_filters_screen.d.ts.map +1 -0
- package/build/screens/conversation_filters_screen.js +125 -0
- package/build/screens/conversation_filters_screen.js.map +1 -0
- package/build/screens/conversation_screen.js +10 -4
- package/build/screens/conversation_screen.js.map +1 -1
- package/build/screens/conversations_screen.d.ts +4 -2
- package/build/screens/conversations_screen.d.ts.map +1 -1
- package/build/screens/conversations_screen.js +139 -11
- package/build/screens/conversations_screen.js.map +1 -1
- package/build/screens/create/conversation_select_recipients_screen.d.ts.map +1 -1
- package/build/screens/create/conversation_select_recipients_screen.js +3 -11
- package/build/screens/create/conversation_select_recipients_screen.js.map +1 -1
- package/build/types/resources/group_resource.d.ts +4 -2
- package/build/types/resources/group_resource.d.ts.map +1 -1
- package/build/types/resources/group_resource.js.map +1 -1
- package/build/types/resources/index.d.ts +1 -0
- package/build/types/resources/index.d.ts.map +1 -1
- package/build/types/resources/index.js +1 -0
- package/build/types/resources/index.js.map +1 -1
- package/build/types/resources/member_ability.d.ts +1 -0
- package/build/types/resources/member_ability.d.ts.map +1 -1
- package/build/types/resources/member_ability.js.map +1 -1
- package/build/types/resources/services/index.d.ts +2 -0
- package/build/types/resources/services/index.d.ts.map +1 -0
- package/build/types/resources/services/index.js +2 -0
- package/build/types/resources/services/index.js.map +1 -0
- package/build/types/resources/services/team_resource.d.ts +48 -0
- package/build/types/resources/services/team_resource.d.ts.map +1 -0
- package/build/types/resources/services/team_resource.js +7 -0
- package/build/types/resources/services/team_resource.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/audio.d.ts +13 -0
- package/build/utils/native_adapters/audio.d.ts.map +1 -0
- package/build/utils/native_adapters/audio.js +7 -0
- package/build/utils/native_adapters/audio.js.map +1 -0
- package/build/utils/native_adapters/configuration.d.ts +7 -1
- package/build/utils/native_adapters/configuration.d.ts.map +1 -1
- package/build/utils/native_adapters/configuration.js +17 -1
- package/build/utils/native_adapters/configuration.js.map +1 -1
- package/build/utils/native_adapters/index.d.ts +2 -0
- package/build/utils/native_adapters/index.d.ts.map +1 -1
- package/build/utils/native_adapters/index.js +2 -0
- package/build/utils/native_adapters/index.js.map +1 -1
- package/build/utils/native_adapters/video.d.ts +25 -0
- package/build/utils/native_adapters/video.d.ts.map +1 -0
- package/build/utils/native_adapters/video.js +7 -0
- package/build/utils/native_adapters/video.js.map +1 -0
- package/build/utils/parse_simple_markdown.d.ts +7 -0
- package/build/utils/parse_simple_markdown.d.ts.map +1 -0
- package/build/utils/parse_simple_markdown.js +32 -0
- package/build/utils/parse_simple_markdown.js.map +1 -0
- package/build/utils/pluralize.d.ts +2 -0
- package/build/utils/pluralize.d.ts.map +1 -0
- package/build/utils/pluralize.js +10 -0
- package/build/utils/pluralize.js.map +1 -0
- package/build/utils/request/conversation.d.ts +10 -0
- package/build/utils/request/conversation.d.ts.map +1 -0
- package/build/utils/request/conversation.js +32 -0
- package/build/utils/request/conversation.js.map +1 -0
- package/build/utils/request/messages.d.ts +15 -0
- package/build/utils/request/messages.d.ts.map +1 -0
- package/build/utils/request/messages.js +22 -0
- package/build/utils/request/messages.js.map +1 -0
- package/build/utils/theme.d.ts +1 -1
- package/build/utils/theme.d.ts.map +1 -1
- package/build/utils/theme.js +1 -1
- package/build/utils/theme.js.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/utils/parse_simple_markdown.ts +93 -0
- package/src/__tests__/utils/pluralize.tsx +17 -0
- package/src/components/conversation/attachments/attachment_card.tsx +46 -0
- package/src/components/conversation/attachments/audio_attachment.tsx +102 -0
- package/src/components/conversation/attachments/constants.ts +5 -0
- package/src/components/conversation/attachments/download_attachment_button.tsx +46 -0
- package/src/components/conversation/attachments/expanded_link.tsx +54 -0
- package/src/components/conversation/attachments/generic_file_attachment.tsx +75 -0
- package/src/components/conversation/attachments/giphy_attachment.tsx +56 -0
- package/src/components/conversation/attachments/image_attachment.tsx +31 -0
- package/src/components/conversation/attachments/video_attachment.tsx +92 -0
- package/src/components/conversation/message.tsx +15 -6
- package/src/components/conversation/message_attachments.tsx +61 -0
- package/src/components/conversation/message_markdown.tsx +52 -0
- package/src/components/conversations/conversation_preview.tsx +84 -0
- package/src/components/conversations/conversations.tsx +79 -0
- package/src/components/conversations/unread_count_badge.tsx +38 -0
- package/src/components/display/badge.tsx +41 -10
- package/src/components/display/button.tsx +1 -1
- package/src/components/display/child_notice.tsx +2 -2
- package/src/components/display/icon.tsx +10 -8
- package/src/components/display/text.tsx +1 -7
- package/src/components/index.tsx +1 -1
- package/src/hooks/use_api.ts +11 -10
- package/src/hooks/use_api_client.ts +1 -1
- package/src/hooks/use_conversation.ts +51 -3
- package/src/hooks/use_conversation_jolt_events.ts +1 -1
- package/src/hooks/use_conversation_messages_jolt_events.ts +1 -1
- package/src/hooks/use_conversations.ts +3 -31
- package/src/hooks/use_groups.ts +31 -0
- package/src/hooks/use_groups_groups.ts +20 -0
- package/src/hooks/use_services_team.ts +30 -0
- package/src/hooks/use_suspense_api.ts +4 -4
- package/src/hooks/use_teams.ts +25 -0
- package/src/navigation/index.tsx +8 -0
- package/src/screens/conversation_details_screen.tsx +224 -111
- package/src/screens/conversation_filters/components/conversation_filters.tsx +233 -0
- package/src/screens/conversation_filters/components/rows.tsx +164 -0
- package/src/screens/conversation_filters/context/conversation_filter_context.tsx +65 -0
- package/src/screens/conversation_filters/filter_types.ts +6 -0
- package/src/screens/conversation_filters/group_filters.tsx +31 -0
- package/src/screens/conversation_filters/hooks/filters.ts +68 -0
- package/src/screens/conversation_filters/screen_props.ts +15 -0
- package/src/screens/conversation_filters/team_filters.tsx +31 -0
- package/src/screens/conversation_filters_screen.tsx +152 -0
- package/src/screens/conversation_screen.tsx +16 -4
- package/src/screens/conversations_screen.tsx +210 -13
- package/src/screens/create/conversation_select_recipients_screen.tsx +3 -11
- package/src/types/resources/group_resource.ts +5 -2
- package/src/types/resources/index.ts +1 -0
- package/src/types/resources/member_ability.ts +1 -0
- package/src/types/resources/services/index.ts +1 -0
- package/src/types/resources/services/team_resource.ts +60 -0
- package/src/utils/client/types.d.ts +2 -1
- package/src/utils/index.ts +1 -0
- package/src/utils/native_adapters/audio.ts +15 -0
- package/src/utils/native_adapters/configuration.ts +24 -1
- package/src/utils/native_adapters/index.ts +2 -0
- package/src/utils/native_adapters/video.ts +30 -0
- package/src/utils/parse_simple_markdown.ts +40 -0
- package/src/utils/pluralize.ts +11 -0
- package/src/utils/request/conversation.ts +46 -0
- package/src/utils/request/messages.ts +21 -0
- package/src/utils/theme.ts +2 -2
- package/build/components/conversations.d.ts +0 -3
- package/build/components/conversations.d.ts.map +0 -1
- package/build/components/conversations.js +0 -100
- package/build/components/conversations.js.map +0 -1
- package/src/components/conversations.tsx +0 -144
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { parseSimpleMarkdown } from '../../utils/parse_simple_markdown'
|
|
2
|
+
|
|
3
|
+
describe('parseSimpleMarkdown', () => {
|
|
4
|
+
it('parses bold text correctly', () => {
|
|
5
|
+
const input = 'This is **bold** text'
|
|
6
|
+
const result = parseSimpleMarkdown(input)
|
|
7
|
+
expect(result).toEqual([
|
|
8
|
+
{ type: 'text', content: 'This is ' },
|
|
9
|
+
{ type: 'bold', content: 'bold' },
|
|
10
|
+
{ type: 'text', content: ' text' },
|
|
11
|
+
])
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
it('parses italic text correctly', () => {
|
|
15
|
+
const input = 'This is *italic* text'
|
|
16
|
+
const result = parseSimpleMarkdown(input)
|
|
17
|
+
expect(result).toEqual([
|
|
18
|
+
{ type: 'text', content: 'This is ' },
|
|
19
|
+
{ type: 'italic', content: 'italic' },
|
|
20
|
+
{ type: 'text', content: ' text' },
|
|
21
|
+
])
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
it('parses links correctly', () => {
|
|
25
|
+
const input = 'Visit https://example.com/page?query=info&number=1#hash. for more info'
|
|
26
|
+
const result = parseSimpleMarkdown(input)
|
|
27
|
+
expect(result).toEqual([
|
|
28
|
+
{ type: 'text', content: 'Visit ' },
|
|
29
|
+
{ type: 'link', content: 'https://example.com/page?query=info&number=1#hash' },
|
|
30
|
+
{ type: 'text', content: '.' },
|
|
31
|
+
{ type: 'text', content: ' for more info' },
|
|
32
|
+
])
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it('parses mixed formatting correctly', () => {
|
|
36
|
+
const input = 'This is **bold** and *italic* and a link: https://example.com'
|
|
37
|
+
const result = parseSimpleMarkdown(input)
|
|
38
|
+
expect(result).toEqual([
|
|
39
|
+
{ type: 'text', content: 'This is ' },
|
|
40
|
+
{ type: 'bold', content: 'bold' },
|
|
41
|
+
{ type: 'text', content: ' and ' },
|
|
42
|
+
{ type: 'italic', content: 'italic' },
|
|
43
|
+
{ type: 'text', content: ' and a link: ' },
|
|
44
|
+
{ type: 'link', content: 'https://example.com' },
|
|
45
|
+
])
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
it('parses unordered lists correctly', () => {
|
|
49
|
+
const input = '* Item 1\n* Item 2\n* Item 3'
|
|
50
|
+
const result = parseSimpleMarkdown(input)
|
|
51
|
+
expect(result).toEqual([{ type: 'text', content: '* Item 1\n* Item 2\n* Item 3' }])
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
it('parses ordered lists correctly', () => {
|
|
55
|
+
const input = '1. Item 1\n2. Item 2\n3. Item 3'
|
|
56
|
+
const result = parseSimpleMarkdown(input)
|
|
57
|
+
expect(result).toEqual([{ type: 'text', content: '1. Item 1\n2. Item 2\n3. Item 3' }])
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
it('handles plain text without formatting', () => {
|
|
61
|
+
const input = 'Just plain text'
|
|
62
|
+
const result = parseSimpleMarkdown(input)
|
|
63
|
+
expect(result).toEqual([{ type: 'text', content: 'Just plain text' }])
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
it('handles empty input', () => {
|
|
67
|
+
const input = ''
|
|
68
|
+
const result = parseSimpleMarkdown(input)
|
|
69
|
+
expect(result).toEqual([])
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
it('handles multiple consecutive formatting', () => {
|
|
73
|
+
const input = '**bold** *italic* https://example.com'
|
|
74
|
+
const result = parseSimpleMarkdown(input)
|
|
75
|
+
expect(result).toEqual([
|
|
76
|
+
{ type: 'bold', content: 'bold' },
|
|
77
|
+
{ type: 'text', content: ' ' },
|
|
78
|
+
{ type: 'italic', content: 'italic' },
|
|
79
|
+
{ type: 'text', content: ' ' },
|
|
80
|
+
{ type: 'link', content: 'https://example.com' },
|
|
81
|
+
])
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
it('handles unmatched formatting gracefully', () => {
|
|
85
|
+
const input = 'This is **bold and *italic'
|
|
86
|
+
const result = parseSimpleMarkdown(input)
|
|
87
|
+
expect(result).toEqual([
|
|
88
|
+
{ type: 'text', content: 'This is ' },
|
|
89
|
+
{ type: 'italic', content: '*bold and ' },
|
|
90
|
+
{ type: 'text', content: 'italic' },
|
|
91
|
+
])
|
|
92
|
+
})
|
|
93
|
+
})
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { pluralize } from '../../utils'
|
|
2
|
+
|
|
3
|
+
describe('pluralize', () => {
|
|
4
|
+
it('includes count and adds an s', () => {
|
|
5
|
+
expect(pluralize(0, 'kid')).toEqual('0 kids')
|
|
6
|
+
expect(pluralize(1, 'kid')).toEqual('1 kid')
|
|
7
|
+
expect(pluralize(2, 'kid')).toEqual('2 kids')
|
|
8
|
+
expect(pluralize(10, 'kid')).toEqual('10 kids')
|
|
9
|
+
})
|
|
10
|
+
it('can optionally not include count', () => {
|
|
11
|
+
expect(pluralize(1, 'kid', false)).toEqual('kid')
|
|
12
|
+
expect(pluralize(2, 'kid', false)).toEqual('kids')
|
|
13
|
+
})
|
|
14
|
+
it('can convert "person" to "people"', () => {
|
|
15
|
+
expect(pluralize(2, 'person', false)).toEqual('people')
|
|
16
|
+
})
|
|
17
|
+
})
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import React, { ComponentProps, ReactNode } from 'react'
|
|
2
|
+
import { StyleSheet, View } from 'react-native'
|
|
3
|
+
import { MESSAGE_ATTACHMENT_WIDTH_SINGLE } from './constants'
|
|
4
|
+
import { Text } from '../../display'
|
|
5
|
+
import { tokens } from '../../../vendor/tapestry/tokens'
|
|
6
|
+
import { useTheme } from '../../../hooks'
|
|
7
|
+
|
|
8
|
+
type AttachmentCardProps = ComponentProps<typeof View>
|
|
9
|
+
|
|
10
|
+
export function AttachmentCard({ children, ...props }: AttachmentCardProps) {
|
|
11
|
+
const styles = useStyles()
|
|
12
|
+
|
|
13
|
+
return (
|
|
14
|
+
<View style={styles.card} {...props}>
|
|
15
|
+
{children}
|
|
16
|
+
</View>
|
|
17
|
+
)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function AttachmentCardTitle({ children }: { children: ReactNode }) {
|
|
21
|
+
const styles = useStyles()
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<Text style={styles.title} numberOfLines={1} ellipsizeMode="tail" selectable={false}>
|
|
25
|
+
{children}
|
|
26
|
+
</Text>
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const useStyles = () => {
|
|
31
|
+
const { colors } = useTheme()
|
|
32
|
+
|
|
33
|
+
return StyleSheet.create({
|
|
34
|
+
card: {
|
|
35
|
+
padding: 4,
|
|
36
|
+
backgroundColor: 'white',
|
|
37
|
+
borderRadius: 8,
|
|
38
|
+
minWidth: MESSAGE_ATTACHMENT_WIDTH_SINGLE,
|
|
39
|
+
minHeight: 48,
|
|
40
|
+
},
|
|
41
|
+
title: {
|
|
42
|
+
color: colors.textColorDefaultPrimary,
|
|
43
|
+
fontSize: tokens.fontSizeSm,
|
|
44
|
+
},
|
|
45
|
+
})
|
|
46
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { View, Text, StyleSheet } from 'react-native'
|
|
3
|
+
import { DenormalizedMessageAttachmentResource } from '../../../types/resources/denormalized_attachment_resource'
|
|
4
|
+
import { IconButton } from '../../display'
|
|
5
|
+
import { AttachmentCard, AttachmentCardTitle } from './attachment_card'
|
|
6
|
+
import { tokens } from '../../../vendor/tapestry/tokens'
|
|
7
|
+
import { useTheme } from '../../../hooks'
|
|
8
|
+
import { Audio } from '../../../utils/native_adapters'
|
|
9
|
+
|
|
10
|
+
export function AudioAttachment({
|
|
11
|
+
attachment,
|
|
12
|
+
}: {
|
|
13
|
+
attachment: DenormalizedMessageAttachmentResource
|
|
14
|
+
}) {
|
|
15
|
+
const styles = useStyles()
|
|
16
|
+
const { attributes } = attachment
|
|
17
|
+
const { url, filename } = attributes
|
|
18
|
+
const sound = Audio.useAudio(url)
|
|
19
|
+
|
|
20
|
+
function toggleAudio() {
|
|
21
|
+
if (!sound.isPlaying) {
|
|
22
|
+
sound.play()
|
|
23
|
+
} else {
|
|
24
|
+
sound.pause()
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const progress = sound.duration > 0 ? sound.position / sound.duration : 0
|
|
29
|
+
|
|
30
|
+
function durationText() {
|
|
31
|
+
if (sound.duration > 0) {
|
|
32
|
+
return `${Math.floor(sound.position / 1000)}s / ${Math.floor(sound.duration / 1000)}s`
|
|
33
|
+
} else {
|
|
34
|
+
return 'Loading...'
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<AttachmentCard>
|
|
40
|
+
<View style={styles.container}>
|
|
41
|
+
<IconButton
|
|
42
|
+
name={sound.isPlaying ? 'services.pause' : 'services.play'}
|
|
43
|
+
size="md"
|
|
44
|
+
accessibilityLabel={sound.isPlaying ? 'Pause' : 'Play'}
|
|
45
|
+
onPress={toggleAudio}
|
|
46
|
+
disabled={!sound}
|
|
47
|
+
style={styles.button}
|
|
48
|
+
/>
|
|
49
|
+
<View style={styles.details}>
|
|
50
|
+
<AttachmentCardTitle>{filename}</AttachmentCardTitle>
|
|
51
|
+
<View style={styles.progressContainer}>
|
|
52
|
+
<View style={[styles.progressBar, { width: `${progress * 100}%` }]} />
|
|
53
|
+
</View>
|
|
54
|
+
<Text style={styles.durationText}>{durationText()}</Text>
|
|
55
|
+
</View>
|
|
56
|
+
</View>
|
|
57
|
+
</AttachmentCard>
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const useStyles = () => {
|
|
62
|
+
const { colors } = useTheme()
|
|
63
|
+
|
|
64
|
+
return StyleSheet.create({
|
|
65
|
+
container: {
|
|
66
|
+
flexDirection: 'row',
|
|
67
|
+
},
|
|
68
|
+
button: {
|
|
69
|
+
width: 42,
|
|
70
|
+
height: 42,
|
|
71
|
+
justifyContent: 'center',
|
|
72
|
+
alignItems: 'center',
|
|
73
|
+
borderRadius: 25,
|
|
74
|
+
backgroundColor: '#eee',
|
|
75
|
+
borderColor: '#aaa',
|
|
76
|
+
borderWidth: 1,
|
|
77
|
+
},
|
|
78
|
+
buttonText: {
|
|
79
|
+
fontSize: 32,
|
|
80
|
+
lineHeight: 32,
|
|
81
|
+
},
|
|
82
|
+
details: {
|
|
83
|
+
flex: 1,
|
|
84
|
+
marginLeft: 10,
|
|
85
|
+
gap: 5,
|
|
86
|
+
},
|
|
87
|
+
progressContainer: {
|
|
88
|
+
height: 5,
|
|
89
|
+
backgroundColor: '#ccc',
|
|
90
|
+
borderRadius: 2.5,
|
|
91
|
+
overflow: 'hidden',
|
|
92
|
+
},
|
|
93
|
+
progressBar: {
|
|
94
|
+
height: '100%',
|
|
95
|
+
backgroundColor: 'blue',
|
|
96
|
+
},
|
|
97
|
+
durationText: {
|
|
98
|
+
fontSize: tokens.fontSizeXs,
|
|
99
|
+
color: colors.textColorDefaultSecondary,
|
|
100
|
+
},
|
|
101
|
+
})
|
|
102
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { IconButton } from '../../display'
|
|
3
|
+
import { useTheme } from '../../../hooks'
|
|
4
|
+
import { Linking, StyleSheet } from 'react-native'
|
|
5
|
+
|
|
6
|
+
interface DownloadAttachmentButtonProps {
|
|
7
|
+
to: string
|
|
8
|
+
filename: string
|
|
9
|
+
title: string
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function DownloadAttachmentButton({ to, title }: DownloadAttachmentButtonProps) {
|
|
13
|
+
const styles = useStyles()
|
|
14
|
+
async function handleDownload() {
|
|
15
|
+
if (to) {
|
|
16
|
+
// Open link in the default web browser
|
|
17
|
+
Linking.openURL(to)
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<IconButton
|
|
23
|
+
name="general.fromCloudArrow"
|
|
24
|
+
size="md"
|
|
25
|
+
accessibilityLabel={title}
|
|
26
|
+
onPress={handleDownload}
|
|
27
|
+
style={styles.iconButton}
|
|
28
|
+
/>
|
|
29
|
+
)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const useStyles = () => {
|
|
33
|
+
const { colors } = useTheme()
|
|
34
|
+
|
|
35
|
+
return StyleSheet.create({
|
|
36
|
+
iconButton: {
|
|
37
|
+
color: colors.fillColorInteractionDefault,
|
|
38
|
+
backgroundColor: colors.fillColorNeutral070,
|
|
39
|
+
borderWidth: 1,
|
|
40
|
+
borderColor: colors.fillColorNeutral060,
|
|
41
|
+
borderRadius: 4,
|
|
42
|
+
width: 24,
|
|
43
|
+
height: 24,
|
|
44
|
+
},
|
|
45
|
+
})
|
|
46
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { Image, Linking, Pressable, StyleSheet, Text, View } from 'react-native'
|
|
3
|
+
import { useTheme } from '../../../hooks'
|
|
4
|
+
import { tokens } from '../../../vendor/tapestry/tokens'
|
|
5
|
+
|
|
6
|
+
export function ExpandedLink({ attachment }: { attachment: any }) {
|
|
7
|
+
const styles = useStyles()
|
|
8
|
+
const { attributes } = attachment
|
|
9
|
+
const { url, title, description, imageUrl, imageHeight, imageWidth } = attributes
|
|
10
|
+
|
|
11
|
+
const aspectRatio = imageWidth && imageHeight ? imageWidth / imageHeight : 1
|
|
12
|
+
|
|
13
|
+
async function openUrl() {
|
|
14
|
+
if (url) Linking.openURL(url)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<Pressable style={styles.container} onPress={openUrl}>
|
|
19
|
+
{imageUrl && (
|
|
20
|
+
<Image source={{ uri: imageUrl }} style={[styles.image, { aspectRatio }]} alt={title} />
|
|
21
|
+
)}
|
|
22
|
+
{(title || description) && (
|
|
23
|
+
<View style={styles.textWrapper}>
|
|
24
|
+
{title && <Text style={styles.title}>{title}</Text>}
|
|
25
|
+
{description && <Text style={styles.description}>{description}</Text>}
|
|
26
|
+
</View>
|
|
27
|
+
)}
|
|
28
|
+
</Pressable>
|
|
29
|
+
)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const useStyles = () => {
|
|
33
|
+
const { colors } = useTheme()
|
|
34
|
+
|
|
35
|
+
return StyleSheet.create({
|
|
36
|
+
container: {},
|
|
37
|
+
image: {
|
|
38
|
+
borderRadius: 8,
|
|
39
|
+
},
|
|
40
|
+
textWrapper: {
|
|
41
|
+
gap: 4,
|
|
42
|
+
padding: 8,
|
|
43
|
+
},
|
|
44
|
+
title: {
|
|
45
|
+
fontSize: tokens.fontSizeSm,
|
|
46
|
+
fontWeight: tokens.fontWeightMedium,
|
|
47
|
+
color: colors.textColorDefaultPrimary,
|
|
48
|
+
},
|
|
49
|
+
description: {
|
|
50
|
+
fontSize: tokens.fontSizeXs,
|
|
51
|
+
color: colors.textColorDefaultPrimary,
|
|
52
|
+
},
|
|
53
|
+
})
|
|
54
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { Pressable, StyleSheet, View } from 'react-native'
|
|
3
|
+
import { DenormalizedMessageAttachmentResource } from '../../../types/resources/denormalized_attachment_resource'
|
|
4
|
+
import { AttachmentCard, AttachmentCardTitle } from './attachment_card'
|
|
5
|
+
import { Icon } from '../../display'
|
|
6
|
+
import { DownloadAttachmentButton } from './download_attachment_button'
|
|
7
|
+
import { useTheme } from '../../../hooks'
|
|
8
|
+
|
|
9
|
+
export function GenericFileAttachment({
|
|
10
|
+
attachment,
|
|
11
|
+
}: {
|
|
12
|
+
attachment: DenormalizedMessageAttachmentResource
|
|
13
|
+
}) {
|
|
14
|
+
const styles = useStyles()
|
|
15
|
+
const { url, filename, contentType } = attachment.attributes
|
|
16
|
+
const iconName = getAttachmentIconName(contentType)
|
|
17
|
+
const fileTypeLabel = contentType === 'application/pdf' ? 'PDF' : 'file'
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<Pressable>
|
|
21
|
+
<AttachmentCard>
|
|
22
|
+
<View style={styles.container}>
|
|
23
|
+
<View style={styles.stack}>
|
|
24
|
+
<Icon name={iconName} />
|
|
25
|
+
<AttachmentCardTitle>{filename}</AttachmentCardTitle>
|
|
26
|
+
</View>
|
|
27
|
+
<DownloadAttachmentButton
|
|
28
|
+
to={url}
|
|
29
|
+
filename={filename}
|
|
30
|
+
title={`Download ${fileTypeLabel}`}
|
|
31
|
+
/>
|
|
32
|
+
</View>
|
|
33
|
+
</AttachmentCard>
|
|
34
|
+
</Pressable>
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const useStyles = () => {
|
|
39
|
+
const { colors } = useTheme()
|
|
40
|
+
|
|
41
|
+
return StyleSheet.create({
|
|
42
|
+
container: {
|
|
43
|
+
padding: 8,
|
|
44
|
+
gap: 4,
|
|
45
|
+
flexDirection: 'row',
|
|
46
|
+
alignItems: 'center',
|
|
47
|
+
justifyContent: 'space-between',
|
|
48
|
+
minHeight: 48,
|
|
49
|
+
},
|
|
50
|
+
stack: {
|
|
51
|
+
gap: 4,
|
|
52
|
+
flexDirection: 'row',
|
|
53
|
+
alignItems: 'center',
|
|
54
|
+
maxWidth: '70%',
|
|
55
|
+
},
|
|
56
|
+
icon: {
|
|
57
|
+
color: colors.textColorDefaultPrimary,
|
|
58
|
+
width: 24,
|
|
59
|
+
height: 24,
|
|
60
|
+
},
|
|
61
|
+
})
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function getAttachmentIconName(type: string) {
|
|
65
|
+
const isImage = type.startsWith('image/')
|
|
66
|
+
const isVideo = type.startsWith('video/')
|
|
67
|
+
const isAudio = type.startsWith('audio/')
|
|
68
|
+
const isPdf = type === 'application/pdf'
|
|
69
|
+
|
|
70
|
+
if (isImage) return 'general.outlinedImageFile'
|
|
71
|
+
if (isVideo) return 'general.outlinedVideoFile'
|
|
72
|
+
if (isAudio) return 'general.outlinedMusicFile'
|
|
73
|
+
if (isPdf) return 'general.outlinedPdfFile'
|
|
74
|
+
return 'general.outlinedGenericFile'
|
|
75
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { Text, Image, StyleSheet, Linking, Pressable } from 'react-native'
|
|
3
|
+
import { tokens } from '../../../vendor/tapestry/tokens'
|
|
4
|
+
import { useTheme } from '../../../hooks'
|
|
5
|
+
import { DenormalizedGiphyAttachmentResource } from '../../../types/resources/denormalized_attachment_resource'
|
|
6
|
+
|
|
7
|
+
export function GiphyAttachment({
|
|
8
|
+
attachment,
|
|
9
|
+
}: {
|
|
10
|
+
attachment: DenormalizedGiphyAttachmentResource
|
|
11
|
+
}) {
|
|
12
|
+
const styles = useStyles()
|
|
13
|
+
const { title, titleLink, giphy } = attachment
|
|
14
|
+
const { url, width, height } = giphy.fixedWidth
|
|
15
|
+
|
|
16
|
+
function handlePress() {
|
|
17
|
+
if (titleLink) {
|
|
18
|
+
// Open Giphy link in the default web browser
|
|
19
|
+
Linking.openURL(titleLink)
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<Pressable onPress={handlePress} style={styles.container}>
|
|
25
|
+
<Image
|
|
26
|
+
source={{ uri: url }}
|
|
27
|
+
style={[styles.image, { width, height }]}
|
|
28
|
+
accessibilityLabel={title}
|
|
29
|
+
/>
|
|
30
|
+
<Text style={styles.link}>
|
|
31
|
+
<Text style={styles.tag}>/giphy</Text> {title}
|
|
32
|
+
</Text>
|
|
33
|
+
</Pressable>
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const useStyles = () => {
|
|
38
|
+
const { colors } = useTheme()
|
|
39
|
+
return StyleSheet.create({
|
|
40
|
+
container: {
|
|
41
|
+
gap: 4,
|
|
42
|
+
},
|
|
43
|
+
image: {
|
|
44
|
+
borderRadius: 8,
|
|
45
|
+
},
|
|
46
|
+
link: {
|
|
47
|
+
fontSize: tokens.fontSizeSm,
|
|
48
|
+
color: colors.fillColorInteractionDefault,
|
|
49
|
+
paddingHorizontal: 8,
|
|
50
|
+
paddingVertical: 6,
|
|
51
|
+
},
|
|
52
|
+
tag: {
|
|
53
|
+
fontWeight: 'bold',
|
|
54
|
+
},
|
|
55
|
+
})
|
|
56
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { View, Image, StyleSheet } from 'react-native'
|
|
3
|
+
|
|
4
|
+
export function ImageAttachment({ attachment }: { attachment: any }) {
|
|
5
|
+
const styles = useStyles()
|
|
6
|
+
const { attributes } = attachment
|
|
7
|
+
const { url, urlMedium, filename, metadata = {} } = attributes
|
|
8
|
+
const width = metadata.width || 100
|
|
9
|
+
const height = metadata.height || 100
|
|
10
|
+
return (
|
|
11
|
+
<View style={styles.container}>
|
|
12
|
+
<Image
|
|
13
|
+
source={{ uri: urlMedium || url }}
|
|
14
|
+
style={[styles.image, { aspectRatio: width / height }]}
|
|
15
|
+
accessibilityLabel={filename}
|
|
16
|
+
/>
|
|
17
|
+
</View>
|
|
18
|
+
)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const useStyles = () => {
|
|
22
|
+
return StyleSheet.create({
|
|
23
|
+
container: {
|
|
24
|
+
maxWidth: '100%',
|
|
25
|
+
},
|
|
26
|
+
image: {
|
|
27
|
+
borderRadius: 8,
|
|
28
|
+
minWidth: 200,
|
|
29
|
+
},
|
|
30
|
+
})
|
|
31
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import React, { useRef, useState } from 'react'
|
|
2
|
+
import { View, StyleSheet, Pressable } from 'react-native'
|
|
3
|
+
import { DenormalizedMessageAttachmentResource } from '../../../types/resources/denormalized_attachment_resource'
|
|
4
|
+
import { MESSAGE_ATTACHMENT_WIDTH_SINGLE } from './constants'
|
|
5
|
+
import { IconButton } from '../../display'
|
|
6
|
+
import { Video, VideoPlayerHandle } from '../../../utils/native_adapters'
|
|
7
|
+
|
|
8
|
+
export function VideoAttachment({
|
|
9
|
+
attachment,
|
|
10
|
+
}: {
|
|
11
|
+
attachment: DenormalizedMessageAttachmentResource
|
|
12
|
+
}) {
|
|
13
|
+
const { attributes } = attachment
|
|
14
|
+
const { width = MESSAGE_ATTACHMENT_WIDTH_SINGLE, height = MESSAGE_ATTACHMENT_WIDTH_SINGLE } =
|
|
15
|
+
attributes.metadata || {}
|
|
16
|
+
const { url } = attributes
|
|
17
|
+
|
|
18
|
+
const videoRef = useRef<VideoPlayerHandle>(null)
|
|
19
|
+
const [isOpen, setIsOpen] = useState(false)
|
|
20
|
+
|
|
21
|
+
function openVideo() {
|
|
22
|
+
if (!isOpen && videoRef.current) {
|
|
23
|
+
videoRef.current.presentFullscreenPlayer()
|
|
24
|
+
videoRef.current.play()
|
|
25
|
+
setIsOpen(true)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function onFullscreenPlayerWillDismiss() {
|
|
30
|
+
videoRef.current?.pause()
|
|
31
|
+
setIsOpen(false)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const viewRef = useRef<View>(null)
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<View style={styles.container} ref={viewRef}>
|
|
38
|
+
<Pressable onPress={openVideo}>
|
|
39
|
+
<Video.Player
|
|
40
|
+
ref={videoRef}
|
|
41
|
+
source={{ uri: url }}
|
|
42
|
+
aspectRatio={width / height}
|
|
43
|
+
style={styles.video}
|
|
44
|
+
onFullscreenPlayerWillDismiss={onFullscreenPlayerWillDismiss}
|
|
45
|
+
/>
|
|
46
|
+
{!isOpen && (
|
|
47
|
+
<View style={styles.playButtonWrapper}>
|
|
48
|
+
<IconButton
|
|
49
|
+
name="services.play"
|
|
50
|
+
size="md"
|
|
51
|
+
accessibilityLabel="Play Video"
|
|
52
|
+
onPress={openVideo}
|
|
53
|
+
style={styles.button}
|
|
54
|
+
/>
|
|
55
|
+
</View>
|
|
56
|
+
)}
|
|
57
|
+
</Pressable>
|
|
58
|
+
</View>
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const styles = StyleSheet.create({
|
|
63
|
+
container: {
|
|
64
|
+
maxWidth: 320,
|
|
65
|
+
maxHeight: 320,
|
|
66
|
+
},
|
|
67
|
+
video: {
|
|
68
|
+
width: '100%',
|
|
69
|
+
height: 'auto',
|
|
70
|
+
backgroundColor: 'black',
|
|
71
|
+
borderRadius: 8,
|
|
72
|
+
},
|
|
73
|
+
playButtonWrapper: {
|
|
74
|
+
position: 'absolute',
|
|
75
|
+
top: 0,
|
|
76
|
+
left: 0,
|
|
77
|
+
right: 0,
|
|
78
|
+
bottom: 0,
|
|
79
|
+
justifyContent: 'center',
|
|
80
|
+
alignItems: 'center',
|
|
81
|
+
},
|
|
82
|
+
button: {
|
|
83
|
+
width: 42,
|
|
84
|
+
height: 42,
|
|
85
|
+
justifyContent: 'center',
|
|
86
|
+
alignItems: 'center',
|
|
87
|
+
borderRadius: 25,
|
|
88
|
+
backgroundColor: '#eee',
|
|
89
|
+
borderColor: '#aaa',
|
|
90
|
+
borderWidth: 1,
|
|
91
|
+
},
|
|
92
|
+
})
|
|
@@ -8,6 +8,9 @@ import { Avatar, Text } from '../../components/display'
|
|
|
8
8
|
import { useTheme } from '../../hooks'
|
|
9
9
|
import { MessageResource } from '../../types'
|
|
10
10
|
import { ReactionCountResource } from '../../types/resources/reaction'
|
|
11
|
+
import { MessageAttachments } from './message_attachments'
|
|
12
|
+
import ErrorBoundary from '../page/error_boundary'
|
|
13
|
+
import { MessageMarkdown } from './message_markdown'
|
|
11
14
|
|
|
12
15
|
/** Message
|
|
13
16
|
* Component for display of a message within a conversation list
|
|
@@ -29,7 +32,6 @@ export function Message(props: MessageResource & { conversation_id: number }) {
|
|
|
29
32
|
reaction_value: reaction.value,
|
|
30
33
|
})
|
|
31
34
|
}
|
|
32
|
-
if (!text) return null
|
|
33
35
|
|
|
34
36
|
return (
|
|
35
37
|
<View style={styles.message}>
|
|
@@ -41,7 +43,14 @@ export function Message(props: MessageResource & { conversation_id: number }) {
|
|
|
41
43
|
<View style={styles.messageContent}>
|
|
42
44
|
{!props.mine && <Text variant="tertiary">{props.author.name}</Text>}
|
|
43
45
|
<PlatformPressable style={styles.messageBubble} onLongPress={handleMessagePress}>
|
|
44
|
-
<
|
|
46
|
+
<ErrorBoundary>
|
|
47
|
+
<MessageAttachments attachments={props.attachments} />
|
|
48
|
+
</ErrorBoundary>
|
|
49
|
+
{text && (
|
|
50
|
+
<View style={styles.messageText}>
|
|
51
|
+
<MessageMarkdown text={text} />
|
|
52
|
+
</View>
|
|
53
|
+
)}
|
|
45
54
|
</PlatformPressable>
|
|
46
55
|
<View style={styles.messageReactions}>
|
|
47
56
|
{reactionCounts.map(reaction => (
|
|
@@ -76,12 +85,12 @@ const useMessageStyles = ({ mine }: MessageResource) => {
|
|
|
76
85
|
},
|
|
77
86
|
messageBubble: {
|
|
78
87
|
backgroundColor: mine ? activeColor : colors.fillColorNeutral070,
|
|
79
|
-
borderRadius:
|
|
80
|
-
|
|
81
|
-
paddingHorizontal: 8,
|
|
88
|
+
borderRadius: 8,
|
|
89
|
+
maxWidth: 232,
|
|
82
90
|
},
|
|
83
91
|
messageText: {
|
|
84
|
-
|
|
92
|
+
paddingVertical: 6,
|
|
93
|
+
paddingHorizontal: 8,
|
|
85
94
|
},
|
|
86
95
|
messageReactions: {
|
|
87
96
|
flexDirection: 'row',
|