@planningcenter/chat-react-native 1.3.0 → 1.3.1-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/CHANGELOG.md CHANGED
@@ -3,6 +3,14 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [1.3.1-rc.0](https://github.com/planningcenter/chat-js/compare/v1.3.0...v1.3.1-rc.0) (2025-02-12)
7
+
8
+ **Note:** Version bump only for package @planningcenter/chat-react-native
9
+
10
+
11
+
12
+
13
+
6
14
  ## [1.3.0](https://github.com/planningcenter/chat-js/compare/v1.2.0...v1.3.0) (2025-02-12)
7
15
 
8
16
 
@@ -1 +1 @@
1
- {"version":3,"file":"conversations.d.ts","sourceRoot":"","sources":["../../src/components/conversations.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA+B,MAAM,OAAO,CAAA;AAanD,wBAAgB,aAAa,6BAgB5B"}
1
+ {"version":3,"file":"conversations.d.ts","sourceRoot":"","sources":["../../src/components/conversations.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA+B,MAAM,OAAO,CAAA;AAcnD,wBAAgB,aAAa,6BAgB5B"}
@@ -1,10 +1,11 @@
1
1
  import { useNavigation } from '@react-navigation/native';
2
2
  import { QueryErrorResetBoundary, useSuspenseQuery } from '@tanstack/react-query';
3
3
  import React, { Suspense, useContext } from 'react';
4
- import { FlatList, Pressable, StyleSheet, Text } from 'react-native';
4
+ import { FlatList, Pressable, StyleSheet, Text, View } from 'react-native';
5
5
  import { ChatContext } from '../contexts/chat_context';
6
- import { useTheme } from '../hooks/use_theme';
7
6
  import ErrorBoundary from './error_boundary';
7
+ import { useTheme } from '../hooks';
8
+ import { Spinner } from './display/spinner';
8
9
  export function Conversations() {
9
10
  const { token } = useContext(ChatContext);
10
11
  if (!token)
@@ -23,16 +24,32 @@ const Loaded = () => {
23
24
  queryKey: ['/chat/v2/me/conversations'],
24
25
  });
25
26
  const navigation = useNavigation();
26
- return (<FlatList data={conversations?.data} contentContainerStyle={styles.container} ListEmptyComponent={<Text>No conversations found</Text>} ListHeaderComponent={<Text style={styles.foo}>Conversations</Text>} renderItem={({ item }) => (<Pressable onPress={() => navigation.navigate('Settings')}>
27
+ return (<FlatList data={conversations?.data} contentContainerStyle={styles.container} style={styles.scrollView} ListEmptyComponent={<Text>No conversations found</Text>} ListHeaderComponent={<View style={styles.column}>
28
+ <Text style={styles.foo}>Display Components</Text>
29
+ <View style={[styles.row, styles.spinnerContainer]}>
30
+ <Spinner size={24}/>
31
+ </View>
32
+ <Text style={styles.foo}>Conversations</Text>
33
+ </View>} renderItem={({ item }) => (<Pressable onPress={() => navigation.navigate('Settings')}>
27
34
  <Text style={styles.listItem}>{item.attributes.title}</Text>
28
35
  </Pressable>)}/>);
29
36
  };
30
37
  const useStyles = () => {
31
38
  const { colors } = useTheme();
32
39
  return StyleSheet.create({
33
- container: { columnGap: 16, backgroundColor: colors.fillColorNeutral080 },
40
+ scrollView: { flex: 1, backgroundColor: colors.fillColorNeutral090 },
41
+ container: { gap: 8, padding: 16 },
34
42
  foo: { fontSize: 24, color: colors.testColor },
35
43
  listItem: { color: colors.fillColorNeutral020 },
44
+ row: {
45
+ gap: 16,
46
+ flexDirection: 'row',
47
+ alignItems: 'center',
48
+ },
49
+ column: { gap: 16 },
50
+ spinnerContainer: {
51
+ height: 20,
52
+ },
36
53
  });
37
54
  };
38
55
  //# sourceMappingURL=conversations.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"conversations.js","sourceRoot":"","sources":["../../src/components/conversations.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AACxD,OAAO,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AACjF,OAAO,KAAK,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,OAAO,CAAA;AACnD,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,cAAc,CAAA;AACpE,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAE7C,OAAO,aAAa,MAAM,kBAAkB,CAAA;AAQ5C,MAAM,UAAU,aAAa;IAC3B,MAAM,EAAE,KAAK,EAAE,GAAG,UAAU,CAAC,WAAW,CAAC,CAAA;IAEzC,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAA;IAEvB,OAAO,CACL,CAAC,uBAAuB,CACtB;MAAA,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CACd,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAC5B;UAAA,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,CAC1C;YAAA,CAAC,MAAM,CAAC,AAAD,EACT;UAAA,EAAE,QAAQ,CACZ;QAAA,EAAE,aAAa,CAAC,CACjB,CACH;IAAA,EAAE,uBAAuB,CAAC,CAC3B,CAAA;AACH,CAAC;AAED,MAAM,MAAM,GAAG,GAAG,EAAE;IAClB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAA;IAC1B,MAAM,EAAE,IAAI,EAAE,aAAa,EAAE,GAAG,gBAAgB,CAAwB;QACtE,QAAQ,EAAE,CAAC,2BAA2B,CAAC;KACxC,CAAC,CAAA;IACF,MAAM,UAAU,GAAG,aAAa,EAAE,CAAA;IAElC,OAAO,CACL,CAAC,QAAQ,CACP,IAAI,CAAC,CAAC,aAAa,EAAE,IAAI,CAAC,CAC1B,qBAAqB,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CACxC,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC,sBAAsB,EAAE,IAAI,CAAC,CAAC,CACxD,mBAAmB,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC,CACnE,UAAU,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CACxB,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CACxD;UAAA,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,IAAI,CAC7D;QAAA,EAAE,SAAS,CAAC,CACb,CAAC,EACF,CACH,CAAA;AACH,CAAC,CAAA;AAED,MAAM,SAAS,GAAG,GAAG,EAAE;IACrB,MAAM,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,CAAA;IAE7B,OAAO,UAAU,CAAC,MAAM,CAAC;QACvB,SAAS,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,eAAe,EAAE,MAAM,CAAC,mBAAmB,EAAE;QACzE,GAAG,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE;QAC9C,QAAQ,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,mBAAmB,EAAE;KAChD,CAAC,CAAA;AACJ,CAAC,CAAA","sourcesContent":["import { useNavigation } from '@react-navigation/native'\nimport { QueryErrorResetBoundary, useSuspenseQuery } from '@tanstack/react-query'\nimport React, { Suspense, useContext } from 'react'\nimport { FlatList, Pressable, StyleSheet, Text } from 'react-native'\nimport { ChatContext } from '../contexts/chat_context'\nimport { useTheme } from '../hooks/use_theme'\nimport { ConversationRecord } from '../types'\nimport ErrorBoundary from './error_boundary'\n\ntype ConversationsResponse = {\n data: ConversationRecord[]\n links: Record<string, string>\n meta: Record<string, string>\n}\n\nexport function Conversations() {\n const { token } = useContext(ChatContext)\n\n if (!token) return null\n\n return (\n <QueryErrorResetBoundary>\n {({ reset }) => (\n <ErrorBoundary onReset={reset}>\n <Suspense fallback={<Text>loading...</Text>}>\n <Loaded />\n </Suspense>\n </ErrorBoundary>\n )}\n </QueryErrorResetBoundary>\n )\n}\n\nconst Loaded = () => {\n const styles = useStyles()\n const { data: conversations } = useSuspenseQuery<ConversationsResponse>({\n queryKey: ['/chat/v2/me/conversations'],\n })\n const navigation = useNavigation()\n\n return (\n <FlatList\n data={conversations?.data}\n contentContainerStyle={styles.container}\n ListEmptyComponent={<Text>No conversations found</Text>}\n ListHeaderComponent={<Text style={styles.foo}>Conversations</Text>}\n renderItem={({ item }) => (\n <Pressable onPress={() => navigation.navigate('Settings')}>\n <Text style={styles.listItem}>{item.attributes.title}</Text>\n </Pressable>\n )}\n />\n )\n}\n\nconst useStyles = () => {\n const { colors } = useTheme()\n\n return StyleSheet.create({\n container: { columnGap: 16, backgroundColor: colors.fillColorNeutral080 },\n foo: { fontSize: 24, color: colors.testColor },\n listItem: { color: colors.fillColorNeutral020 },\n })\n}\n"]}
1
+ {"version":3,"file":"conversations.js","sourceRoot":"","sources":["../../src/components/conversations.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useNavigation } from '@react-navigation/native'\nimport { QueryErrorResetBoundary, useSuspenseQuery } from '@tanstack/react-query'\nimport React, { Suspense, useContext } from 'react'\nimport { FlatList, Pressable, StyleSheet, Text, View } from 'react-native'\nimport { ChatContext } from '../contexts/chat_context'\nimport { ConversationRecord } from '../types'\nimport ErrorBoundary from './error_boundary'\nimport { useTheme } from '../hooks'\nimport { Spinner } from './display/spinner'\n\ntype ConversationsResponse = {\n data: ConversationRecord[]\n links: Record<string, string>\n meta: Record<string, string>\n}\n\nexport function Conversations() {\n const { token } = useContext(ChatContext)\n\n if (!token) return null\n\n return (\n <QueryErrorResetBoundary>\n {({ reset }) => (\n <ErrorBoundary onReset={reset}>\n <Suspense fallback={<Text>loading...</Text>}>\n <Loaded />\n </Suspense>\n </ErrorBoundary>\n )}\n </QueryErrorResetBoundary>\n )\n}\n\nconst Loaded = () => {\n const styles = useStyles()\n const { data: conversations } = useSuspenseQuery<ConversationsResponse>({\n queryKey: ['/chat/v2/me/conversations'],\n })\n const navigation = useNavigation()\n\n return (\n <FlatList\n data={conversations?.data}\n contentContainerStyle={styles.container}\n style={styles.scrollView}\n ListEmptyComponent={<Text>No conversations found</Text>}\n ListHeaderComponent={\n <View style={styles.column}>\n <Text style={styles.foo}>Display Components</Text>\n <View style={[styles.row, styles.spinnerContainer]}>\n <Spinner size={24} />\n </View>\n <Text style={styles.foo}>Conversations</Text>\n </View>\n }\n renderItem={({ item }) => (\n <Pressable onPress={() => navigation.navigate('Settings')}>\n <Text style={styles.listItem}>{item.attributes.title}</Text>\n </Pressable>\n )}\n />\n )\n}\n\nconst useStyles = () => {\n const { colors } = useTheme()\n\n return StyleSheet.create({\n scrollView: { flex: 1, backgroundColor: colors.fillColorNeutral090 },\n container: { gap: 8, padding: 16 },\n foo: { fontSize: 24, color: colors.testColor },\n listItem: { color: colors.fillColorNeutral020 },\n row: {\n gap: 16,\n flexDirection: 'row',\n alignItems: 'center',\n },\n column: { gap: 16 },\n spinnerContainer: {\n height: 20,\n },\n })\n}\n"]}
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ interface SpinnerProps {
3
+ /**
4
+ * Size of the spinner in px
5
+ * */
6
+ size?: number;
7
+ }
8
+ export declare function Spinner({ size }: SpinnerProps): React.JSX.Element;
9
+ export {};
10
+ //# sourceMappingURL=spinner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spinner.d.ts","sourceRoot":"","sources":["../../../src/components/display/spinner.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4B,MAAM,OAAO,CAAA;AAIhD,UAAU,YAAY;IACpB;;SAEK;IACL,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,wBAAgB,OAAO,CAAC,EAAE,IAAS,EAAE,EAAE,YAAY,qBAsElD"}
@@ -0,0 +1,94 @@
1
+ import React, { useEffect, useRef } from 'react';
2
+ import { Animated, Easing, StyleSheet, View } from 'react-native';
3
+ import { useTheme } from '../../hooks';
4
+ export function Spinner({ size = 20 }) {
5
+ const rotation = useRef(new Animated.Value(0)).current;
6
+ const styles = useStyles();
7
+ const animation = Animated.loop(Animated.timing(rotation, {
8
+ toValue: 1,
9
+ duration: 1000,
10
+ easing: Easing.linear,
11
+ useNativeDriver: true,
12
+ }));
13
+ const rotateValue = rotation.interpolate({
14
+ inputRange: [0, 1],
15
+ outputRange: ['0deg', '360deg'],
16
+ });
17
+ useEffect(() => {
18
+ animation.start();
19
+ return () => animation.stop();
20
+ }, [animation]);
21
+ useEffect(() => () => rotation.setValue(0), [rotation]);
22
+ return (<View style={styles.container}>
23
+ <Animated.View style={{
24
+ width: size,
25
+ height: size,
26
+ borderRadius: size / 2,
27
+ transform: [{ rotate: rotateValue }],
28
+ }}>
29
+ <View style={[
30
+ styles.clipping,
31
+ {
32
+ width: size / 2,
33
+ height: size / 2,
34
+ },
35
+ ]}>
36
+ <View style={[
37
+ styles.circle,
38
+ styles.spinner,
39
+ {
40
+ width: size,
41
+ height: size,
42
+ borderRadius: size / 2,
43
+ },
44
+ ]}/>
45
+ </View>
46
+ <View style={[
47
+ styles.circle,
48
+ styles.track,
49
+ {
50
+ width: size,
51
+ height: size,
52
+ borderRadius: size / 2,
53
+ },
54
+ ]}/>
55
+ </Animated.View>
56
+ </View>);
57
+ }
58
+ const useStyles = () => {
59
+ const { colors } = useTheme();
60
+ return StyleSheet.create({
61
+ container: {
62
+ width: '100%',
63
+ height: '100%',
64
+ position: 'absolute',
65
+ top: 0,
66
+ left: 0,
67
+ zIndex: 200,
68
+ justifyContent: 'center',
69
+ alignItems: 'center',
70
+ opacity: 0.7,
71
+ },
72
+ circle: {
73
+ borderStyle: 'solid',
74
+ borderWidth: 3,
75
+ },
76
+ spinner: {
77
+ position: 'absolute',
78
+ top: 0,
79
+ left: 0,
80
+ borderColor: colors.fillColorNeutral020,
81
+ },
82
+ track: {
83
+ borderColor: colors.fillColorNeutral050Base,
84
+ },
85
+ clipping: {
86
+ position: 'absolute',
87
+ top: 0,
88
+ left: 0,
89
+ overflow: 'hidden',
90
+ zIndex: 200,
91
+ },
92
+ });
93
+ };
94
+ //# sourceMappingURL=spinner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spinner.js","sourceRoot":"","sources":["../../../src/components/display/spinner.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { useEffect, useRef } from 'react'\nimport { Animated, Easing, StyleSheet, View } from 'react-native'\nimport { useTheme } from '../../hooks'\n\ninterface SpinnerProps {\n /**\n * Size of the spinner in px\n * */\n size?: number\n}\n\nexport function Spinner({ size = 20 }: SpinnerProps) {\n const rotation = useRef(new Animated.Value(0)).current\n const styles = useStyles()\n\n const animation = Animated.loop(\n Animated.timing(rotation, {\n toValue: 1,\n duration: 1000,\n easing: Easing.linear,\n useNativeDriver: true,\n })\n )\n\n const rotateValue = rotation.interpolate({\n inputRange: [0, 1],\n outputRange: ['0deg', '360deg'],\n })\n\n useEffect(() => {\n animation.start()\n return () => animation.stop()\n }, [animation])\n\n useEffect(() => () => rotation.setValue(0), [rotation])\n\n return (\n <View style={styles.container}>\n <Animated.View\n style={{\n width: size,\n height: size,\n borderRadius: size / 2,\n transform: [{ rotate: rotateValue }],\n }}\n >\n <View\n style={[\n styles.clipping,\n {\n width: size / 2,\n height: size / 2,\n },\n ]}\n >\n <View\n style={[\n styles.circle,\n styles.spinner,\n {\n width: size,\n height: size,\n borderRadius: size / 2,\n },\n ]}\n />\n </View>\n <View\n style={[\n styles.circle,\n styles.track,\n {\n width: size,\n height: size,\n borderRadius: size / 2,\n },\n ]}\n />\n </Animated.View>\n </View>\n )\n}\n\nconst useStyles = () => {\n const { colors } = useTheme()\n\n return StyleSheet.create({\n container: {\n width: '100%',\n height: '100%',\n position: 'absolute',\n top: 0,\n left: 0,\n zIndex: 200,\n justifyContent: 'center',\n alignItems: 'center',\n opacity: 0.7,\n },\n circle: {\n borderStyle: 'solid',\n borderWidth: 3,\n },\n spinner: {\n position: 'absolute',\n top: 0,\n left: 0,\n borderColor: colors.fillColorNeutral020,\n },\n track: {\n borderColor: colors.fillColorNeutral050Base,\n },\n clipping: {\n position: 'absolute',\n top: 0,\n left: 0,\n overflow: 'hidden',\n zIndex: 200,\n },\n })\n}\n"]}
@@ -0,0 +1,3 @@
1
+ export { useCreateChatTheme } from './use_create_chat_theme';
2
+ export { useTheme } from './use_theme';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAC5D,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA"}
@@ -0,0 +1,3 @@
1
+ export { useCreateChatTheme } from './use_create_chat_theme';
2
+ export { useTheme } from './use_theme';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAC5D,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA","sourcesContent":["export { useCreateChatTheme } from './use_create_chat_theme'\nexport { useTheme } from './use_theme'\n"]}
package/build/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Conversations } from './components/conversations';
2
2
  import { ChatContext, ChatProvider } from './contexts/chat_context';
3
- import { useCreateChatTheme } from './hooks/use_create_chat_theme';
3
+ import { useCreateChatTheme } from './hooks';
4
4
  import { OAuthToken } from './types';
5
5
  import { baseUrlMap, uploadUrlMap } from './utils/session';
6
6
  import { TemporaryDefaultColorsType } from './utils/theme';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAA;AAC1D,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AACnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAA;AAClE,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AACpC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAC1D,OAAO,EAAE,0BAA0B,EAAE,MAAM,eAAe,CAAA;AAE1D,OAAO,EACL,UAAU,EACV,WAAW,EACX,YAAY,EACZ,aAAa,EACb,UAAU,EACV,0BAA0B,EAC1B,YAAY,EACZ,kBAAkB,GACnB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAA;AAC1D,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AACnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAA;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AACpC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAC1D,OAAO,EAAE,0BAA0B,EAAE,MAAM,eAAe,CAAA;AAE1D,OAAO,EACL,UAAU,EACV,WAAW,EACX,YAAY,EACZ,aAAa,EACb,UAAU,EACV,0BAA0B,EAC1B,YAAY,EACZ,kBAAkB,GACnB,CAAA"}
package/build/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Conversations } from './components/conversations';
2
2
  import { ChatContext, ChatProvider } from './contexts/chat_context';
3
- import { useCreateChatTheme } from './hooks/use_create_chat_theme';
3
+ import { useCreateChatTheme } from './hooks';
4
4
  import { baseUrlMap, uploadUrlMap } from './utils/session';
5
5
  export { baseUrlMap, ChatContext, ChatProvider, Conversations, uploadUrlMap, useCreateChatTheme, };
6
6
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAA;AAC1D,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AACnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAA;AAElE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAG1D,OAAO,EACL,UAAU,EACV,WAAW,EACX,YAAY,EACZ,aAAa,EAGb,YAAY,EACZ,kBAAkB,GACnB,CAAA","sourcesContent":["import { Conversations } from './components/conversations'\nimport { ChatContext, ChatProvider } from './contexts/chat_context'\nimport { useCreateChatTheme } from './hooks/use_create_chat_theme'\nimport { OAuthToken } from './types'\nimport { baseUrlMap, uploadUrlMap } from './utils/session'\nimport { TemporaryDefaultColorsType } from './utils/theme'\n\nexport {\n baseUrlMap,\n ChatContext,\n ChatProvider,\n Conversations,\n OAuthToken,\n TemporaryDefaultColorsType,\n uploadUrlMap,\n useCreateChatTheme,\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAA;AAC1D,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AACnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAA;AAE5C,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAG1D,OAAO,EACL,UAAU,EACV,WAAW,EACX,YAAY,EACZ,aAAa,EAGb,YAAY,EACZ,kBAAkB,GACnB,CAAA","sourcesContent":["import { Conversations } from './components/conversations'\nimport { ChatContext, ChatProvider } from './contexts/chat_context'\nimport { useCreateChatTheme } from './hooks'\nimport { OAuthToken } from './types'\nimport { baseUrlMap, uploadUrlMap } from './utils/session'\nimport { TemporaryDefaultColorsType } from './utils/theme'\n\nexport {\n baseUrlMap,\n ChatContext,\n ChatProvider,\n Conversations,\n OAuthToken,\n TemporaryDefaultColorsType,\n uploadUrlMap,\n useCreateChatTheme,\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@planningcenter/chat-react-native",
3
- "version": "1.3.0",
3
+ "version": "1.3.1-rc.0",
4
4
  "description": "",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -33,5 +33,5 @@
33
33
  "prettier": "^3.4.2",
34
34
  "react-native": "0.74.5"
35
35
  },
36
- "gitHead": "fccff0f8691ba483d7f504423a1bd649c94a5af8"
36
+ "gitHead": "a811b0dd5f01919bbc459c906e985db1b05e1a9e"
37
37
  }
@@ -1,11 +1,12 @@
1
1
  import { useNavigation } from '@react-navigation/native'
2
2
  import { QueryErrorResetBoundary, useSuspenseQuery } from '@tanstack/react-query'
3
3
  import React, { Suspense, useContext } from 'react'
4
- import { FlatList, Pressable, StyleSheet, Text } from 'react-native'
4
+ import { FlatList, Pressable, StyleSheet, Text, View } from 'react-native'
5
5
  import { ChatContext } from '../contexts/chat_context'
6
- import { useTheme } from '../hooks/use_theme'
7
6
  import { ConversationRecord } from '../types'
8
7
  import ErrorBoundary from './error_boundary'
8
+ import { useTheme } from '../hooks'
9
+ import { Spinner } from './display/spinner'
9
10
 
10
11
  type ConversationsResponse = {
11
12
  data: ConversationRecord[]
@@ -42,8 +43,17 @@ const Loaded = () => {
42
43
  <FlatList
43
44
  data={conversations?.data}
44
45
  contentContainerStyle={styles.container}
46
+ style={styles.scrollView}
45
47
  ListEmptyComponent={<Text>No conversations found</Text>}
46
- ListHeaderComponent={<Text style={styles.foo}>Conversations</Text>}
48
+ ListHeaderComponent={
49
+ <View style={styles.column}>
50
+ <Text style={styles.foo}>Display Components</Text>
51
+ <View style={[styles.row, styles.spinnerContainer]}>
52
+ <Spinner size={24} />
53
+ </View>
54
+ <Text style={styles.foo}>Conversations</Text>
55
+ </View>
56
+ }
47
57
  renderItem={({ item }) => (
48
58
  <Pressable onPress={() => navigation.navigate('Settings')}>
49
59
  <Text style={styles.listItem}>{item.attributes.title}</Text>
@@ -57,8 +67,18 @@ const useStyles = () => {
57
67
  const { colors } = useTheme()
58
68
 
59
69
  return StyleSheet.create({
60
- container: { columnGap: 16, backgroundColor: colors.fillColorNeutral080 },
70
+ scrollView: { flex: 1, backgroundColor: colors.fillColorNeutral090 },
71
+ container: { gap: 8, padding: 16 },
61
72
  foo: { fontSize: 24, color: colors.testColor },
62
73
  listItem: { color: colors.fillColorNeutral020 },
74
+ row: {
75
+ gap: 16,
76
+ flexDirection: 'row',
77
+ alignItems: 'center',
78
+ },
79
+ column: { gap: 16 },
80
+ spinnerContainer: {
81
+ height: 20,
82
+ },
63
83
  })
64
84
  }
@@ -0,0 +1,120 @@
1
+ import React, { useEffect, useRef } from 'react'
2
+ import { Animated, Easing, StyleSheet, View } from 'react-native'
3
+ import { useTheme } from '../../hooks'
4
+
5
+ interface SpinnerProps {
6
+ /**
7
+ * Size of the spinner in px
8
+ * */
9
+ size?: number
10
+ }
11
+
12
+ export function Spinner({ size = 20 }: SpinnerProps) {
13
+ const rotation = useRef(new Animated.Value(0)).current
14
+ const styles = useStyles()
15
+
16
+ const animation = Animated.loop(
17
+ Animated.timing(rotation, {
18
+ toValue: 1,
19
+ duration: 1000,
20
+ easing: Easing.linear,
21
+ useNativeDriver: true,
22
+ })
23
+ )
24
+
25
+ const rotateValue = rotation.interpolate({
26
+ inputRange: [0, 1],
27
+ outputRange: ['0deg', '360deg'],
28
+ })
29
+
30
+ useEffect(() => {
31
+ animation.start()
32
+ return () => animation.stop()
33
+ }, [animation])
34
+
35
+ useEffect(() => () => rotation.setValue(0), [rotation])
36
+
37
+ return (
38
+ <View style={styles.container}>
39
+ <Animated.View
40
+ style={{
41
+ width: size,
42
+ height: size,
43
+ borderRadius: size / 2,
44
+ transform: [{ rotate: rotateValue }],
45
+ }}
46
+ >
47
+ <View
48
+ style={[
49
+ styles.clipping,
50
+ {
51
+ width: size / 2,
52
+ height: size / 2,
53
+ },
54
+ ]}
55
+ >
56
+ <View
57
+ style={[
58
+ styles.circle,
59
+ styles.spinner,
60
+ {
61
+ width: size,
62
+ height: size,
63
+ borderRadius: size / 2,
64
+ },
65
+ ]}
66
+ />
67
+ </View>
68
+ <View
69
+ style={[
70
+ styles.circle,
71
+ styles.track,
72
+ {
73
+ width: size,
74
+ height: size,
75
+ borderRadius: size / 2,
76
+ },
77
+ ]}
78
+ />
79
+ </Animated.View>
80
+ </View>
81
+ )
82
+ }
83
+
84
+ const useStyles = () => {
85
+ const { colors } = useTheme()
86
+
87
+ return StyleSheet.create({
88
+ container: {
89
+ width: '100%',
90
+ height: '100%',
91
+ position: 'absolute',
92
+ top: 0,
93
+ left: 0,
94
+ zIndex: 200,
95
+ justifyContent: 'center',
96
+ alignItems: 'center',
97
+ opacity: 0.7,
98
+ },
99
+ circle: {
100
+ borderStyle: 'solid',
101
+ borderWidth: 3,
102
+ },
103
+ spinner: {
104
+ position: 'absolute',
105
+ top: 0,
106
+ left: 0,
107
+ borderColor: colors.fillColorNeutral020,
108
+ },
109
+ track: {
110
+ borderColor: colors.fillColorNeutral050Base,
111
+ },
112
+ clipping: {
113
+ position: 'absolute',
114
+ top: 0,
115
+ left: 0,
116
+ overflow: 'hidden',
117
+ zIndex: 200,
118
+ },
119
+ })
120
+ }
@@ -0,0 +1,2 @@
1
+ export { useCreateChatTheme } from './use_create_chat_theme'
2
+ export { useTheme } from './use_theme'
package/src/index.tsx CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Conversations } from './components/conversations'
2
2
  import { ChatContext, ChatProvider } from './contexts/chat_context'
3
- import { useCreateChatTheme } from './hooks/use_create_chat_theme'
3
+ import { useCreateChatTheme } from './hooks'
4
4
  import { OAuthToken } from './types'
5
5
  import { baseUrlMap, uploadUrlMap } from './utils/session'
6
6
  import { TemporaryDefaultColorsType } from './utils/theme'