@planningcenter/chat-react-native 3.13.2-rc.2 → 3.14.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/index.d.ts +1 -1
- package/build/index.d.ts.map +1 -1
- package/build/index.js +1 -1
- package/build/index.js.map +1 -1
- package/build/screens/conversation_new/components/services_form.js +7 -3
- package/build/screens/conversation_new/components/services_form.js.map +1 -1
- package/build/screens/conversations/components/chat_group_badge.js.map +1 -1
- package/build/screens/conversations/components/list_header_component.js.map +1 -1
- package/build/screens/conversations/conversations_screen.d.ts +2 -2
- package/build/screens/conversations/conversations_screen.d.ts.map +1 -1
- package/build/screens/conversations/conversations_screen.js.map +1 -1
- package/build/screens/design_system_screen.d.ts.map +1 -1
- package/build/screens/design_system_screen.js +54 -2
- package/build/screens/design_system_screen.js.map +1 -1
- package/build/screens/index.d.ts +18 -0
- package/build/screens/index.d.ts.map +1 -1
- package/build/screens/index.js +18 -0
- package/build/screens/index.js.map +1 -1
- package/build/utils/date.js +3 -3
- package/build/utils/date.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/haptic.d.ts +23 -0
- package/build/utils/native_adapters/haptic.d.ts.map +1 -0
- package/build/utils/native_adapters/haptic.js +22 -0
- package/build/utils/native_adapters/haptic.js.map +1 -0
- 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/package.json +2 -2
- package/src/__tests__/utils/native_adapters/configuration.ts +46 -1
- package/src/index.tsx +1 -1
- package/src/screens/conversation_new/components/services_form.tsx +14 -9
- package/src/screens/conversations/components/chat_group_badge.tsx +2 -2
- package/src/screens/conversations/components/list_header_component.tsx +2 -2
- package/src/screens/conversations/conversations_screen.tsx +2 -2
- package/src/screens/design_system_screen.tsx +66 -1
- package/src/screens/index.ts +18 -0
- package/src/utils/date.ts +3 -3
- package/src/utils/native_adapters/configuration.ts +5 -0
- package/src/utils/native_adapters/haptic.ts +34 -0
- package/src/utils/native_adapters/index.ts +1 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
interface Haptic {
|
|
2
|
+
impactLight: () => void;
|
|
3
|
+
impactMedium: () => void;
|
|
4
|
+
impactHeavy: () => void;
|
|
5
|
+
rigid: () => void;
|
|
6
|
+
soft: () => void;
|
|
7
|
+
notificationSuccess: () => void;
|
|
8
|
+
notificationWarning: () => void;
|
|
9
|
+
notificationError: () => void;
|
|
10
|
+
}
|
|
11
|
+
export declare class HapticAdapter {
|
|
12
|
+
impactLight: () => void;
|
|
13
|
+
impactMedium: () => void;
|
|
14
|
+
impactHeavy: () => void;
|
|
15
|
+
rigid: () => void;
|
|
16
|
+
soft: () => void;
|
|
17
|
+
notificationSuccess: () => void;
|
|
18
|
+
notificationWarning: () => void;
|
|
19
|
+
notificationError: () => void;
|
|
20
|
+
constructor(methods?: Haptic);
|
|
21
|
+
}
|
|
22
|
+
export {};
|
|
23
|
+
//# sourceMappingURL=haptic.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"haptic.d.ts","sourceRoot":"","sources":["../../../src/utils/native_adapters/haptic.ts"],"names":[],"mappings":"AAEA,UAAU,MAAM;IACd,WAAW,EAAE,MAAM,IAAI,CAAA;IACvB,YAAY,EAAE,MAAM,IAAI,CAAA;IACxB,WAAW,EAAE,MAAM,IAAI,CAAA;IACvB,KAAK,EAAE,MAAM,IAAI,CAAA;IACjB,IAAI,EAAE,MAAM,IAAI,CAAA;IAChB,mBAAmB,EAAE,MAAM,IAAI,CAAA;IAC/B,mBAAmB,EAAE,MAAM,IAAI,CAAA;IAC/B,iBAAiB,EAAE,MAAM,IAAI,CAAA;CAC9B;AAED,qBAAa,aAAa;IACxB,WAAW,EAAE,MAAM,IAAI,CAAA;IACvB,YAAY,EAAE,MAAM,IAAI,CAAA;IACxB,WAAW,EAAE,MAAM,IAAI,CAAA;IACvB,KAAK,EAAE,MAAM,IAAI,CAAA;IACjB,IAAI,EAAE,MAAM,IAAI,CAAA;IAChB,mBAAmB,EAAE,MAAM,IAAI,CAAA;IAC/B,mBAAmB,EAAE,MAAM,IAAI,CAAA;IAC/B,iBAAiB,EAAE,MAAM,IAAI,CAAA;gBAEjB,OAAO,CAAC,EAAE,MAAM;CAU7B"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { noop } from 'lodash';
|
|
2
|
+
export class HapticAdapter {
|
|
3
|
+
impactLight;
|
|
4
|
+
impactMedium;
|
|
5
|
+
impactHeavy;
|
|
6
|
+
rigid;
|
|
7
|
+
soft;
|
|
8
|
+
notificationSuccess;
|
|
9
|
+
notificationWarning;
|
|
10
|
+
notificationError;
|
|
11
|
+
constructor(methods) {
|
|
12
|
+
this.impactLight = methods?.impactLight ?? noop;
|
|
13
|
+
this.impactMedium = methods?.impactMedium ?? noop;
|
|
14
|
+
this.impactHeavy = methods?.impactHeavy ?? noop;
|
|
15
|
+
this.rigid = methods?.rigid ?? noop;
|
|
16
|
+
this.soft = methods?.soft ?? noop;
|
|
17
|
+
this.notificationSuccess = methods?.notificationSuccess ?? noop;
|
|
18
|
+
this.notificationWarning = methods?.notificationWarning ?? noop;
|
|
19
|
+
this.notificationError = methods?.notificationError ?? noop;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=haptic.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"haptic.js","sourceRoot":"","sources":["../../../src/utils/native_adapters/haptic.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AAa7B,MAAM,OAAO,aAAa;IACxB,WAAW,CAAY;IACvB,YAAY,CAAY;IACxB,WAAW,CAAY;IACvB,KAAK,CAAY;IACjB,IAAI,CAAY;IAChB,mBAAmB,CAAY;IAC/B,mBAAmB,CAAY;IAC/B,iBAAiB,CAAY;IAE7B,YAAY,OAAgB;QAC1B,IAAI,CAAC,WAAW,GAAG,OAAO,EAAE,WAAW,IAAI,IAAI,CAAA;QAC/C,IAAI,CAAC,YAAY,GAAG,OAAO,EAAE,YAAY,IAAI,IAAI,CAAA;QACjD,IAAI,CAAC,WAAW,GAAG,OAAO,EAAE,WAAW,IAAI,IAAI,CAAA;QAC/C,IAAI,CAAC,KAAK,GAAG,OAAO,EAAE,KAAK,IAAI,IAAI,CAAA;QACnC,IAAI,CAAC,IAAI,GAAG,OAAO,EAAE,IAAI,IAAI,IAAI,CAAA;QACjC,IAAI,CAAC,mBAAmB,GAAG,OAAO,EAAE,mBAAmB,IAAI,IAAI,CAAA;QAC/D,IAAI,CAAC,mBAAmB,GAAG,OAAO,EAAE,mBAAmB,IAAI,IAAI,CAAA;QAC/D,IAAI,CAAC,iBAAiB,GAAG,OAAO,EAAE,iBAAiB,IAAI,IAAI,CAAA;IAC7D,CAAC;CACF","sourcesContent":["import { noop } from 'lodash'\n\ninterface Haptic {\n impactLight: () => void\n impactMedium: () => void\n impactHeavy: () => void\n rigid: () => void\n soft: () => void\n notificationSuccess: () => void\n notificationWarning: () => void\n notificationError: () => void\n}\n\nexport class HapticAdapter {\n impactLight: () => void\n impactMedium: () => void\n impactHeavy: () => void\n rigid: () => void\n soft: () => void\n notificationSuccess: () => void\n notificationWarning: () => void\n notificationError: () => void\n\n constructor(methods?: Haptic) {\n this.impactLight = methods?.impactLight ?? noop\n this.impactMedium = methods?.impactMedium ?? noop\n this.impactHeavy = methods?.impactHeavy ?? noop\n this.rigid = methods?.rigid ?? noop\n this.soft = methods?.soft ?? noop\n this.notificationSuccess = methods?.notificationSuccess ?? noop\n this.notificationWarning = methods?.notificationWarning ?? noop\n this.notificationError = methods?.notificationError ?? noop\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/native_adapters/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAA;AACvB,cAAc,aAAa,CAAA;AAC3B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,WAAW,CAAA;AACzB,cAAc,OAAO,CAAA;AACrB,cAAc,SAAS,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/native_adapters/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAA;AACvB,cAAc,aAAa,CAAA;AAC3B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,WAAW,CAAA;AACzB,cAAc,OAAO,CAAA;AACrB,cAAc,SAAS,CAAA;AACvB,cAAc,UAAU,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/utils/native_adapters/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAA;AACvB,cAAc,aAAa,CAAA;AAC3B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,WAAW,CAAA;AACzB,cAAc,OAAO,CAAA;AACrB,cAAc,SAAS,CAAA","sourcesContent":["export * from './audio'\nexport * from './clipboard'\nexport * from './configuration'\nexport * from './image_picker'\nexport * from './linking'\nexport * from './log'\nexport * from './video'\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/utils/native_adapters/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAA;AACvB,cAAc,aAAa,CAAA;AAC3B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,WAAW,CAAA;AACzB,cAAc,OAAO,CAAA;AACrB,cAAc,SAAS,CAAA;AACvB,cAAc,UAAU,CAAA","sourcesContent":["export * from './audio'\nexport * from './clipboard'\nexport * from './configuration'\nexport * from './image_picker'\nexport * from './linking'\nexport * from './log'\nexport * from './video'\nexport * from './haptic'\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@planningcenter/chat-react-native",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.14.0-rc.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
@@ -55,5 +55,5 @@
|
|
|
55
55
|
"react-native-url-polyfill": "^2.0.0",
|
|
56
56
|
"typescript": "<5.6.0"
|
|
57
57
|
},
|
|
58
|
-
"gitHead": "
|
|
58
|
+
"gitHead": "7581413aff42fdbe77cb4c646ab7bc38fafbb4fe"
|
|
59
59
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from 'react'
|
|
2
2
|
import { Linking as RNLinking } from 'react-native'
|
|
3
|
-
import { ChatAdapters, Linking } from '../../../utils/native_adapters/configuration'
|
|
3
|
+
import { ChatAdapters, Linking, Haptic } from '../../../utils/native_adapters/configuration'
|
|
4
4
|
import {
|
|
5
5
|
AudioAdapter,
|
|
6
6
|
Clipboard,
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
VideoAdapter,
|
|
11
11
|
} from '../../../utils/native_adapters'
|
|
12
12
|
import { VideoPlayerHandle, VideoPlayerProps } from '../../../utils/native_adapters/video'
|
|
13
|
+
import { HapticAdapter } from '../../../utils/native_adapters/haptic'
|
|
13
14
|
|
|
14
15
|
describe('ChatAdapters', () => {
|
|
15
16
|
const getStringAsync = jest.fn(async () => '')
|
|
@@ -36,6 +37,16 @@ describe('ChatAdapters', () => {
|
|
|
36
37
|
openCameraAsync: async () => ({ canceled: true, assets: null }),
|
|
37
38
|
openImageLibraryAsync: async () => ({ canceled: true, assets: null }),
|
|
38
39
|
})
|
|
40
|
+
const haptic = new HapticAdapter({
|
|
41
|
+
impactLight: jest.fn(),
|
|
42
|
+
impactMedium: jest.fn(),
|
|
43
|
+
impactHeavy: jest.fn(),
|
|
44
|
+
rigid: jest.fn(),
|
|
45
|
+
soft: jest.fn(),
|
|
46
|
+
notificationSuccess: jest.fn(),
|
|
47
|
+
notificationWarning: jest.fn(),
|
|
48
|
+
notificationError: jest.fn(),
|
|
49
|
+
})
|
|
39
50
|
|
|
40
51
|
it('should be defined', () => {
|
|
41
52
|
expect(ChatAdapters).toBeDefined()
|
|
@@ -47,6 +58,7 @@ describe('ChatAdapters', () => {
|
|
|
47
58
|
audio,
|
|
48
59
|
video,
|
|
49
60
|
imagePicker,
|
|
61
|
+
haptic,
|
|
50
62
|
})
|
|
51
63
|
|
|
52
64
|
expect(Clipboard).toEqual(clipboard)
|
|
@@ -91,4 +103,37 @@ describe('ChatAdapters', () => {
|
|
|
91
103
|
linking.canOpenURL('https://www.google.com')
|
|
92
104
|
})
|
|
93
105
|
})
|
|
106
|
+
|
|
107
|
+
describe('haptic adapter', () => {
|
|
108
|
+
it('should configure the haptic adapter', () => {
|
|
109
|
+
ChatAdapters.configure({
|
|
110
|
+
clipboard,
|
|
111
|
+
audio,
|
|
112
|
+
video,
|
|
113
|
+
imagePicker,
|
|
114
|
+
haptic,
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
expect(Haptic).toEqual(haptic)
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
it('should be configured with defaults', () => {
|
|
121
|
+
ChatAdapters.configure({
|
|
122
|
+
clipboard,
|
|
123
|
+
audio,
|
|
124
|
+
video,
|
|
125
|
+
imagePicker,
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
expect(Haptic).toBeDefined()
|
|
129
|
+
expect(Haptic.impactLight).toBeDefined()
|
|
130
|
+
expect(Haptic.impactMedium).toBeDefined()
|
|
131
|
+
expect(Haptic.impactHeavy).toBeDefined()
|
|
132
|
+
expect(Haptic.rigid).toBeDefined()
|
|
133
|
+
expect(Haptic.soft).toBeDefined()
|
|
134
|
+
expect(Haptic.notificationSuccess).toBeDefined()
|
|
135
|
+
expect(Haptic.notificationWarning).toBeDefined()
|
|
136
|
+
expect(Haptic.notificationError).toBeDefined()
|
|
137
|
+
})
|
|
138
|
+
})
|
|
94
139
|
})
|
package/src/index.tsx
CHANGED
|
@@ -3,7 +3,7 @@ export { ApiProvider, chatQueryClient, useFocusManager } from './contexts/api_pr
|
|
|
3
3
|
export * from './contexts/chat_context'
|
|
4
4
|
export * from './navigation'
|
|
5
5
|
export { ScreenLayout } from './navigation/screenLayout'
|
|
6
|
-
export
|
|
6
|
+
export * from './screens'
|
|
7
7
|
export * from './types'
|
|
8
8
|
export { platformFontWeightBold, Session, TemporaryDefaultColorsType, Uri } from './utils'
|
|
9
9
|
export * from './utils/client'
|
|
@@ -168,15 +168,20 @@ function FormContent({
|
|
|
168
168
|
</TextButton>
|
|
169
169
|
</View>
|
|
170
170
|
<View style={styles.toSectionRow}>
|
|
171
|
-
{selectedTeams.map(team =>
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
171
|
+
{selectedTeams.map(team => {
|
|
172
|
+
const serviceTypeAcronyms = team.serviceTypeAcronyms.join(', ')
|
|
173
|
+
const label = `${team.teamName} | ${serviceTypeAcronyms}`
|
|
174
|
+
|
|
175
|
+
return (
|
|
176
|
+
<View key={team.value.teamId} style={styles.badgeRow}>
|
|
177
|
+
<Badge
|
|
178
|
+
iconNameRight="general.x"
|
|
179
|
+
label={label}
|
|
180
|
+
onPress={() => removeSelection(team.value.teamId)}
|
|
181
|
+
/>
|
|
182
|
+
</View>
|
|
183
|
+
)
|
|
184
|
+
})}
|
|
180
185
|
</View>
|
|
181
186
|
</View>
|
|
182
187
|
<Divider />
|
|
@@ -4,12 +4,12 @@ import { StyleSheet, View } from 'react-native'
|
|
|
4
4
|
import { Badge } from '../../../components'
|
|
5
5
|
import { useApiGet } from '../../../hooks/use_api'
|
|
6
6
|
import { GroupResource } from '../../../types/resources/group_resource'
|
|
7
|
-
import {
|
|
7
|
+
import { ConversationsScreenProps } from '../conversations_screen'
|
|
8
8
|
|
|
9
9
|
export const ChatGroupBadge = ({ rowPaddingHorizontal }: { rowPaddingHorizontal: number }) => {
|
|
10
10
|
const styles = useStyles({ rowPaddingHorizontal })
|
|
11
11
|
const navigation = useNavigation()
|
|
12
|
-
const route = useRoute<RouteProp<
|
|
12
|
+
const route = useRoute<RouteProp<ConversationsScreenProps['route']>>()
|
|
13
13
|
const { chat_group_graph_id } = route.params || {}
|
|
14
14
|
const { data: group } = useApiGet<GroupResource>({
|
|
15
15
|
url: `/me/groups/${chat_group_graph_id}`,
|
|
@@ -5,7 +5,7 @@ import { Heading, TextButton, ToggleButton } from '../../../components'
|
|
|
5
5
|
import { useCurrentPersonCache, useTheme } from '../../../hooks'
|
|
6
6
|
import { useMarkAllRead } from '../../../hooks/use_conversations_actions'
|
|
7
7
|
import { useCanDisplayGroups } from '../../../hooks/use_groups'
|
|
8
|
-
import {
|
|
8
|
+
import { ConversationsScreenProps } from '../conversations_screen'
|
|
9
9
|
import { ChatGroupBadge } from './chat_group_badge'
|
|
10
10
|
|
|
11
11
|
const ROW_PADDING_HORIZONTAL = 16
|
|
@@ -22,7 +22,7 @@ export const ListHeaderComponent = () => {
|
|
|
22
22
|
const navigation = useNavigation()
|
|
23
23
|
const canFilterByTeams = useCanDisplayGroups({ source_app_name: 'Services', source_type: 'Team' })
|
|
24
24
|
const canFilterByGroups = useCanDisplayGroups({ source_app_name: 'Groups', source_type: 'Group' })
|
|
25
|
-
const route = useRoute<RouteProp<
|
|
25
|
+
const route = useRoute<RouteProp<ConversationsScreenProps['route']>>()
|
|
26
26
|
const { chat_group_graph_id, group_source_app_name = '' } = route.params || {}
|
|
27
27
|
const currentPersonCache = useCurrentPersonCache()
|
|
28
28
|
const { markAllRead, isPending } = useMarkAllRead()
|
|
@@ -11,13 +11,13 @@ import { ListHeaderComponent } from './components/list_header_component'
|
|
|
11
11
|
import { AppName } from '../../types/resources/app_name'
|
|
12
12
|
import { ConversationsJoltEvents } from './components/conversations_jolt_events'
|
|
13
13
|
|
|
14
|
-
export type
|
|
14
|
+
export type ConversationsScreenProps = StaticScreenProps<{
|
|
15
15
|
title?: string
|
|
16
16
|
chat_group_graph_id?: GraphId
|
|
17
17
|
group_source_app_name?: AppName
|
|
18
18
|
}>
|
|
19
19
|
|
|
20
|
-
export function ConversationsScreen({ route }:
|
|
20
|
+
export function ConversationsScreen({ route }: ConversationsScreenProps) {
|
|
21
21
|
const navigation = useNavigation()
|
|
22
22
|
const canCreateConversations = useCanCreateConversations()
|
|
23
23
|
const styles = useStyles()
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, { useState } from 'react'
|
|
2
2
|
import { Alert, Pressable, ScrollView, StyleSheet, View } from 'react-native'
|
|
3
3
|
import type { ViewStyle } from 'react-native'
|
|
4
|
-
import { useTheme } from '../hooks'
|
|
4
|
+
import { useInteractionGhostBackgroundColor, useTheme } from '../hooks'
|
|
5
5
|
import {
|
|
6
6
|
Avatar,
|
|
7
7
|
AvatarGroup,
|
|
@@ -27,6 +27,7 @@ import {
|
|
|
27
27
|
MAX_FONT_SIZE_MULTIPLIER,
|
|
28
28
|
platformPressedOpacityStyle,
|
|
29
29
|
platformFontWeightMedium,
|
|
30
|
+
Haptic,
|
|
30
31
|
} from '../utils'
|
|
31
32
|
import BannerPrimitive from '../components/primitive/banner_primitive'
|
|
32
33
|
import { VideoAttachmentPreview } from '../components/display/video_attachment_preview'
|
|
@@ -89,6 +90,7 @@ export function DesignSystemScreen() {
|
|
|
89
90
|
<IndicatorsSection />
|
|
90
91
|
<HeadingTextSection />
|
|
91
92
|
<PressablesSection />
|
|
93
|
+
<HapticsSection />
|
|
92
94
|
<ImageIconsSection />
|
|
93
95
|
<FormControlsSection />
|
|
94
96
|
<StatusComponentsSection />
|
|
@@ -678,6 +680,37 @@ function PressablesSection({ isLast }: SectionProps) {
|
|
|
678
680
|
</CollapsableSection>
|
|
679
681
|
)
|
|
680
682
|
}
|
|
683
|
+
function HapticsSection({ isLast }: SectionProps) {
|
|
684
|
+
return (
|
|
685
|
+
<CollapsableSection title="Haptics" isLast={isLast}>
|
|
686
|
+
<TextGroup>
|
|
687
|
+
<Text>
|
|
688
|
+
Haptics help communicate changes and interactions in the UI by making them feel physical
|
|
689
|
+
and "weighty". They are a progressive enhancement and shouldn't replace visual feedback.
|
|
690
|
+
</Text>
|
|
691
|
+
</TextGroup>
|
|
692
|
+
<Group title="Impact" description="Communicates that a user interaction is occurring.">
|
|
693
|
+
<Row>
|
|
694
|
+
<HapticButton title="Impact Light" onPress={() => Haptic.impactLight()} />
|
|
695
|
+
<HapticButton title="Impact Medium" onPress={() => Haptic.impactMedium()} />
|
|
696
|
+
<HapticButton title="Impact Heavy" onPress={() => Haptic.impactHeavy()} />
|
|
697
|
+
<HapticButton title="Rigid" onPress={() => Haptic.rigid()} />
|
|
698
|
+
<HapticButton title="Soft" onPress={() => Haptic.soft()} />
|
|
699
|
+
</Row>
|
|
700
|
+
</Group>
|
|
701
|
+
<Group
|
|
702
|
+
title="Notification"
|
|
703
|
+
description="Communicates the result of a user or application action."
|
|
704
|
+
>
|
|
705
|
+
<Row>
|
|
706
|
+
<HapticButton title="Notification Success" onPress={() => Haptic.notificationSuccess()} />
|
|
707
|
+
<HapticButton title="Notification Warning" onPress={() => Haptic.notificationWarning()} />
|
|
708
|
+
<HapticButton title="Notification Error" onPress={() => Haptic.notificationError()} />
|
|
709
|
+
</Row>
|
|
710
|
+
</Group>
|
|
711
|
+
</CollapsableSection>
|
|
712
|
+
)
|
|
713
|
+
}
|
|
681
714
|
|
|
682
715
|
function ImageIconsSection({ isLast }: SectionProps) {
|
|
683
716
|
const styles = useStyles()
|
|
@@ -1143,14 +1176,46 @@ function TextListItem({ label, children }: TextListItemProps) {
|
|
|
1143
1176
|
)
|
|
1144
1177
|
}
|
|
1145
1178
|
|
|
1179
|
+
function HapticButton({ title, onPress }: { title: string; onPress: () => void }) {
|
|
1180
|
+
const styles = useStyles()
|
|
1181
|
+
|
|
1182
|
+
return (
|
|
1183
|
+
<Pressable
|
|
1184
|
+
onPress={onPress}
|
|
1185
|
+
style={({ pressed }) => ({
|
|
1186
|
+
...styles.hapticButton,
|
|
1187
|
+
...{ opacity: pressed ? 0.5 : 1 },
|
|
1188
|
+
})}
|
|
1189
|
+
>
|
|
1190
|
+
<Text style={styles.hapticButtonText}>{title}</Text>
|
|
1191
|
+
</Pressable>
|
|
1192
|
+
)
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1146
1195
|
// =================================
|
|
1147
1196
|
// ====== Styles ===================
|
|
1148
1197
|
// =================================
|
|
1149
1198
|
|
|
1150
1199
|
const useStyles = () => {
|
|
1151
1200
|
const { colors } = useTheme()
|
|
1201
|
+
const interactionGhostBackgroundColor = useInteractionGhostBackgroundColor()
|
|
1152
1202
|
|
|
1153
1203
|
return StyleSheet.create({
|
|
1204
|
+
hapticButton: {
|
|
1205
|
+
flexGrow: 1,
|
|
1206
|
+
height: 100,
|
|
1207
|
+
padding: 16,
|
|
1208
|
+
alignItems: 'center',
|
|
1209
|
+
justifyContent: 'center',
|
|
1210
|
+
backgroundColor: interactionGhostBackgroundColor,
|
|
1211
|
+
borderWidth: 1,
|
|
1212
|
+
borderColor: colors.interaction,
|
|
1213
|
+
borderRadius: 8,
|
|
1214
|
+
},
|
|
1215
|
+
hapticButtonText: {
|
|
1216
|
+
textAlign: 'center',
|
|
1217
|
+
color: colors.interaction,
|
|
1218
|
+
},
|
|
1154
1219
|
scrollView: {
|
|
1155
1220
|
flex: 1,
|
|
1156
1221
|
backgroundColor: colors.fillColorNeutral100Inverted,
|
package/src/screens/index.ts
CHANGED
|
@@ -1 +1,19 @@
|
|
|
1
1
|
export * from './design_system_screen'
|
|
2
|
+
export * from './conversation_details_screen'
|
|
3
|
+
export * from './conversation_screen'
|
|
4
|
+
export * from './conversation_new/conversation_new_screen'
|
|
5
|
+
export * from './conversation_filter_recipients/conversation_filter_recipients_screen'
|
|
6
|
+
export * from './conversation_select_recipients/conversation_select_recipients_screen'
|
|
7
|
+
export * from './message_actions_screen'
|
|
8
|
+
export * from './send_giphy_screen'
|
|
9
|
+
export * from './not_found'
|
|
10
|
+
export * from './reactions_screen'
|
|
11
|
+
export * from './team_conversation_screen'
|
|
12
|
+
export * from './bug_report_screen'
|
|
13
|
+
export * from './conversation/message_read_receipts_screen'
|
|
14
|
+
export * from './conversation_filters_screen'
|
|
15
|
+
export * from './conversation_filters/screen_props'
|
|
16
|
+
export * from './conversation_select_recipients/conversation_select_group_recipients_screen'
|
|
17
|
+
export * from './conversation_select_recipients/conversation_select_teams_i_lead_recipients_screen'
|
|
18
|
+
export * from './attachment_actions/attachment_actions_screen'
|
|
19
|
+
export * from './conversations/conversations_screen'
|
package/src/utils/date.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { date as formatDate
|
|
1
|
+
import { date as formatDate } from '@planningcenter/datetime-fmt'
|
|
2
2
|
import moment from 'moment-timezone'
|
|
3
3
|
|
|
4
4
|
export type DateProps = string | number | Date
|
|
@@ -11,7 +11,7 @@ export function formatDatePreview(date?: DateProps) {
|
|
|
11
11
|
const isThisWeek = now.isSame(date, 'week')
|
|
12
12
|
const isThisYear = now.isSame(date, 'year')
|
|
13
13
|
|
|
14
|
-
if (isToday) return moment(date).format('h:
|
|
14
|
+
if (isToday) return moment(date).format('h:mma')
|
|
15
15
|
if (isThisWeek) return formatDate(date, { style: 'relative-short' })
|
|
16
16
|
if (isThisYear) return formatDate(date, { style: 'abbreviated' })
|
|
17
17
|
|
|
@@ -58,6 +58,6 @@ export function relativeTime(date: DateProps): string {
|
|
|
58
58
|
if (duration.asDays() < 1) {
|
|
59
59
|
return then.fromNow()
|
|
60
60
|
} else {
|
|
61
|
-
return
|
|
61
|
+
return moment(date).format('h:mma')
|
|
62
62
|
}
|
|
63
63
|
}
|
|
@@ -5,6 +5,7 @@ import { ImagePickerAdapter } from './image_picker'
|
|
|
5
5
|
import { VideoAdapter } from './video'
|
|
6
6
|
import { Linking as RNLinking } from 'react-native'
|
|
7
7
|
import { LinkingAdapter } from './linking'
|
|
8
|
+
import { HapticAdapter } from './haptic'
|
|
8
9
|
|
|
9
10
|
type ChatConfigurations = {
|
|
10
11
|
clipboard: ClipboardAdapter
|
|
@@ -13,6 +14,7 @@ type ChatConfigurations = {
|
|
|
13
14
|
imagePicker: ImagePickerAdapter
|
|
14
15
|
log?: LogAdapter
|
|
15
16
|
linking?: LinkingAdapter
|
|
17
|
+
haptic?: HapticAdapter
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
export class ChatAdapters {
|
|
@@ -23,6 +25,7 @@ export class ChatAdapters {
|
|
|
23
25
|
ImagePicker = configurations.imagePicker
|
|
24
26
|
Log = configurations.log || new LogAdapter()
|
|
25
27
|
Linking = configurations.linking || new LinkingAdapter(RNLinking)
|
|
28
|
+
Haptic = configurations.haptic || new HapticAdapter()
|
|
26
29
|
}
|
|
27
30
|
}
|
|
28
31
|
|
|
@@ -69,3 +72,5 @@ export let ImagePicker: ImagePickerAdapter = new ImagePickerAdapter({
|
|
|
69
72
|
export let Log: LogAdapter = new LogAdapter()
|
|
70
73
|
|
|
71
74
|
export let Linking: LinkingAdapter = new LinkingAdapter(RNLinking)
|
|
75
|
+
|
|
76
|
+
export let Haptic: HapticAdapter = new HapticAdapter()
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { noop } from 'lodash'
|
|
2
|
+
|
|
3
|
+
interface Haptic {
|
|
4
|
+
impactLight: () => void
|
|
5
|
+
impactMedium: () => void
|
|
6
|
+
impactHeavy: () => void
|
|
7
|
+
rigid: () => void
|
|
8
|
+
soft: () => void
|
|
9
|
+
notificationSuccess: () => void
|
|
10
|
+
notificationWarning: () => void
|
|
11
|
+
notificationError: () => void
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export class HapticAdapter {
|
|
15
|
+
impactLight: () => void
|
|
16
|
+
impactMedium: () => void
|
|
17
|
+
impactHeavy: () => void
|
|
18
|
+
rigid: () => void
|
|
19
|
+
soft: () => void
|
|
20
|
+
notificationSuccess: () => void
|
|
21
|
+
notificationWarning: () => void
|
|
22
|
+
notificationError: () => void
|
|
23
|
+
|
|
24
|
+
constructor(methods?: Haptic) {
|
|
25
|
+
this.impactLight = methods?.impactLight ?? noop
|
|
26
|
+
this.impactMedium = methods?.impactMedium ?? noop
|
|
27
|
+
this.impactHeavy = methods?.impactHeavy ?? noop
|
|
28
|
+
this.rigid = methods?.rigid ?? noop
|
|
29
|
+
this.soft = methods?.soft ?? noop
|
|
30
|
+
this.notificationSuccess = methods?.notificationSuccess ?? noop
|
|
31
|
+
this.notificationWarning = methods?.notificationWarning ?? noop
|
|
32
|
+
this.notificationError = methods?.notificationError ?? noop
|
|
33
|
+
}
|
|
34
|
+
}
|