@planningcenter/chat-react-native 1.3.0-rc.4 → 1.3.0-rc.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/build/components/conversations.d.ts +1 -1
  3. package/build/components/conversations.d.ts.map +1 -1
  4. package/build/components/conversations.js +19 -34
  5. package/build/components/conversations.js.map +1 -1
  6. package/build/components/error_boundary.d.ts +3 -1
  7. package/build/components/error_boundary.d.ts.map +1 -1
  8. package/build/components/error_boundary.js.map +1 -1
  9. package/build/contexts/api_provider.d.ts +13 -0
  10. package/build/contexts/api_provider.d.ts.map +1 -0
  11. package/build/contexts/api_provider.js +51 -0
  12. package/build/contexts/api_provider.js.map +1 -0
  13. package/build/contexts/chat_context.d.ts +15 -0
  14. package/build/contexts/chat_context.d.ts.map +1 -0
  15. package/build/contexts/chat_context.js +18 -0
  16. package/build/contexts/chat_context.js.map +1 -0
  17. package/build/hooks/use_async_storage.d.ts +4 -0
  18. package/build/hooks/use_async_storage.d.ts.map +1 -0
  19. package/build/hooks/use_async_storage.js +31 -0
  20. package/build/hooks/use_async_storage.js.map +1 -0
  21. package/build/hooks/use_create_chat_theme.d.ts +10 -0
  22. package/build/hooks/use_create_chat_theme.d.ts.map +1 -0
  23. package/build/hooks/use_create_chat_theme.js +20 -0
  24. package/build/hooks/use_create_chat_theme.js.map +1 -0
  25. package/build/hooks/use_theme.d.ts +3 -0
  26. package/build/hooks/use_theme.d.ts.map +1 -0
  27. package/build/hooks/use_theme.js +7 -0
  28. package/build/hooks/use_theme.js.map +1 -0
  29. package/build/index.d.ts +5 -3
  30. package/build/index.d.ts.map +1 -1
  31. package/build/index.js +3 -2
  32. package/build/index.js.map +1 -1
  33. package/build/utils/theme.d.ts +34 -0
  34. package/build/utils/theme.d.ts.map +1 -0
  35. package/build/utils/theme.js +33 -0
  36. package/build/utils/theme.js.map +1 -0
  37. package/build/vendor/tapestry/tapestry_alias_tokens_color_map.d.ts +41 -0
  38. package/build/vendor/tapestry/tapestry_alias_tokens_color_map.d.ts.map +1 -0
  39. package/build/vendor/tapestry/tapestry_alias_tokens_color_map.js +50 -0
  40. package/build/vendor/tapestry/tapestry_alias_tokens_color_map.js.map +1 -0
  41. package/build/vendor/tapestry/tokens.d.ts +38 -0
  42. package/build/vendor/tapestry/tokens.d.ts.map +1 -0
  43. package/build/vendor/tapestry/tokens.js +50 -0
  44. package/build/vendor/tapestry/tokens.js.map +1 -0
  45. package/package.json +4 -2
  46. package/src/components/conversations.tsx +24 -37
  47. package/src/components/error_boundary.tsx +1 -1
  48. package/src/contexts/api_provider.tsx +69 -0
  49. package/src/contexts/chat_context.tsx +29 -0
  50. package/src/hooks/use_async_storage.ts +41 -0
  51. package/src/hooks/use_create_chat_theme.tsx +31 -0
  52. package/src/hooks/use_theme.tsx +9 -0
  53. package/src/index.tsx +12 -3
  54. package/src/types.d.ts +9 -4
  55. package/src/utils/theme.ts +73 -0
  56. package/src/vendor/tapestry/tapestry_alias_tokens_color_map.ts +82 -0
  57. package/src/vendor/tapestry/tokens.ts +97 -0
  58. package/build/context/chat_context.d.ts +0 -9
  59. package/build/context/chat_context.d.ts.map +0 -1
  60. package/build/context/chat_context.js +0 -7
  61. package/build/context/chat_context.js.map +0 -1
  62. package/src/context/chat_context.tsx +0 -14
@@ -0,0 +1,50 @@
1
+ import { tokens } from './tokens';
2
+ const neutralsLight = {
3
+ name: 'light',
4
+ fillColorNeutral000: tokens.colorNeutral12,
5
+ fillColorNeutral010: tokens.colorNeutral24,
6
+ fillColorNeutral020: tokens.colorNeutral45,
7
+ fillColorNeutral030: tokens.colorNeutral58,
8
+ fillColorNeutral040: tokens.colorNeutral81,
9
+ fillColorNeutral050Base: tokens.colorNeutral88,
10
+ fillColorNeutral060: tokens.colorNeutral93,
11
+ fillColorNeutral070: tokens.colorNeutral95,
12
+ fillColorNeutral080: tokens.colorNeutral97,
13
+ fillColorNeutral090: tokens.colorNeutral98,
14
+ fillColorNeutral100Inverted: tokens.colorNeutral100White,
15
+ };
16
+ const neutralsDark = {
17
+ name: 'dark',
18
+ fillColorNeutral000: tokens.colorNeutral98,
19
+ fillColorNeutral010: tokens.colorNeutral88,
20
+ fillColorNeutral020: tokens.colorNeutral68,
21
+ fillColorNeutral030: tokens.colorNeutral50,
22
+ fillColorNeutral040: tokens.colorNeutral32,
23
+ fillColorNeutral050Base: tokens.colorNeutral24,
24
+ fillColorNeutral060: tokens.colorNeutral19,
25
+ fillColorNeutral070: tokens.colorNeutral17,
26
+ fillColorNeutral080: tokens.colorNeutral15,
27
+ fillColorNeutral090: tokens.colorNeutral12,
28
+ fillColorNeutral100Inverted: tokens.colorNeutral7,
29
+ };
30
+ const semanticAliasesLight = {
31
+ name: 'light',
32
+ iconColorDefaultPrimary: neutralsLight.fillColorNeutral010,
33
+ iconColorDefaultSecondary: neutralsLight.fillColorNeutral020,
34
+ iconColorDefaultDim: neutralsLight.fillColorNeutral030,
35
+ iconColorDefaultDisabled: neutralsLight.fillColorNeutral040,
36
+ iconColorDefaultInverted: neutralsLight.fillColorNeutral100Inverted,
37
+ };
38
+ const semanticAliasesDark = {
39
+ name: 'dark',
40
+ iconColorDefaultPrimary: neutralsDark.fillColorNeutral010,
41
+ iconColorDefaultSecondary: neutralsDark.fillColorNeutral020,
42
+ iconColorDefaultDim: neutralsDark.fillColorNeutral030,
43
+ iconColorDefaultDisabled: neutralsDark.fillColorNeutral040,
44
+ iconColorDefaultInverted: neutralsDark.fillColorNeutral100Inverted,
45
+ };
46
+ export const tapestryAliasTokensColorMap = {
47
+ light: { ...neutralsLight, ...semanticAliasesLight },
48
+ dark: { ...neutralsDark, ...semanticAliasesDark },
49
+ };
50
+ //# sourceMappingURL=tapestry_alias_tokens_color_map.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tapestry_alias_tokens_color_map.js","sourceRoot":"","sources":["../../../src/vendor/tapestry/tapestry_alias_tokens_color_map.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AAqBjC,MAAM,aAAa,GAAkB;IACnC,IAAI,EAAE,OAAO;IACb,mBAAmB,EAAE,MAAM,CAAC,cAAc;IAC1C,mBAAmB,EAAE,MAAM,CAAC,cAAc;IAC1C,mBAAmB,EAAE,MAAM,CAAC,cAAc;IAC1C,mBAAmB,EAAE,MAAM,CAAC,cAAc;IAC1C,mBAAmB,EAAE,MAAM,CAAC,cAAc;IAC1C,uBAAuB,EAAE,MAAM,CAAC,cAAc;IAC9C,mBAAmB,EAAE,MAAM,CAAC,cAAc;IAC1C,mBAAmB,EAAE,MAAM,CAAC,cAAc;IAC1C,mBAAmB,EAAE,MAAM,CAAC,cAAc;IAC1C,mBAAmB,EAAE,MAAM,CAAC,cAAc;IAC1C,2BAA2B,EAAE,MAAM,CAAC,oBAAoB;CACzD,CAAA;AAED,MAAM,YAAY,GAAkB;IAClC,IAAI,EAAE,MAAM;IACZ,mBAAmB,EAAE,MAAM,CAAC,cAAc;IAC1C,mBAAmB,EAAE,MAAM,CAAC,cAAc;IAC1C,mBAAmB,EAAE,MAAM,CAAC,cAAc;IAC1C,mBAAmB,EAAE,MAAM,CAAC,cAAc;IAC1C,mBAAmB,EAAE,MAAM,CAAC,cAAc;IAC1C,uBAAuB,EAAE,MAAM,CAAC,cAAc;IAC9C,mBAAmB,EAAE,MAAM,CAAC,cAAc;IAC1C,mBAAmB,EAAE,MAAM,CAAC,cAAc;IAC1C,mBAAmB,EAAE,MAAM,CAAC,cAAc;IAC1C,mBAAmB,EAAE,MAAM,CAAC,cAAc;IAC1C,2BAA2B,EAAE,MAAM,CAAC,aAAa;CAClD,CAAA;AAWD,MAAM,oBAAoB,GAA0B;IAClD,IAAI,EAAE,OAAO;IACb,uBAAuB,EAAE,aAAa,CAAC,mBAAmB;IAC1D,yBAAyB,EAAE,aAAa,CAAC,mBAAmB;IAC5D,mBAAmB,EAAE,aAAa,CAAC,mBAAmB;IACtD,wBAAwB,EAAE,aAAa,CAAC,mBAAmB;IAC3D,wBAAwB,EAAE,aAAa,CAAC,2BAA2B;CACpE,CAAA;AAED,MAAM,mBAAmB,GAA0B;IACjD,IAAI,EAAE,MAAM;IACZ,uBAAuB,EAAE,YAAY,CAAC,mBAAmB;IACzD,yBAAyB,EAAE,YAAY,CAAC,mBAAmB;IAC3D,mBAAmB,EAAE,YAAY,CAAC,mBAAmB;IACrD,wBAAwB,EAAE,YAAY,CAAC,mBAAmB;IAC1D,wBAAwB,EAAE,YAAY,CAAC,2BAA2B;CACnE,CAAA;AAED,MAAM,CAAC,MAAM,2BAA2B,GAAG;IACzC,KAAK,EAAE,EAAE,GAAG,aAAa,EAAE,GAAG,oBAAoB,EAAE;IACpD,IAAI,EAAE,EAAE,GAAG,YAAY,EAAE,GAAG,mBAAmB,EAAE;CAClD,CAAA","sourcesContent":["import { tokens } from './tokens'\n\n// Copied from `@planningcenter/tapestry` package.\n// Defining these tokens locally is a temporary solution until the package supports mobile.\n// Tokens Reference: https://planningcenter.github.io/tapestry/?path=/docs/foundations-design-tokens--docs\n\ninterface NeutralColors {\n name: string\n fillColorNeutral000: string\n fillColorNeutral010: string\n fillColorNeutral020: string\n fillColorNeutral030: string\n fillColorNeutral040: string\n fillColorNeutral050Base: string\n fillColorNeutral060: string\n fillColorNeutral070: string\n fillColorNeutral080: string\n fillColorNeutral090: string\n fillColorNeutral100Inverted: string\n}\n\nconst neutralsLight: NeutralColors = {\n name: 'light',\n fillColorNeutral000: tokens.colorNeutral12,\n fillColorNeutral010: tokens.colorNeutral24,\n fillColorNeutral020: tokens.colorNeutral45,\n fillColorNeutral030: tokens.colorNeutral58,\n fillColorNeutral040: tokens.colorNeutral81,\n fillColorNeutral050Base: tokens.colorNeutral88,\n fillColorNeutral060: tokens.colorNeutral93,\n fillColorNeutral070: tokens.colorNeutral95,\n fillColorNeutral080: tokens.colorNeutral97,\n fillColorNeutral090: tokens.colorNeutral98,\n fillColorNeutral100Inverted: tokens.colorNeutral100White,\n}\n\nconst neutralsDark: NeutralColors = {\n name: 'dark',\n fillColorNeutral000: tokens.colorNeutral98,\n fillColorNeutral010: tokens.colorNeutral88,\n fillColorNeutral020: tokens.colorNeutral68,\n fillColorNeutral030: tokens.colorNeutral50,\n fillColorNeutral040: tokens.colorNeutral32,\n fillColorNeutral050Base: tokens.colorNeutral24,\n fillColorNeutral060: tokens.colorNeutral19,\n fillColorNeutral070: tokens.colorNeutral17,\n fillColorNeutral080: tokens.colorNeutral15,\n fillColorNeutral090: tokens.colorNeutral12,\n fillColorNeutral100Inverted: tokens.colorNeutral7,\n}\n\ninterface SemanticAliasesColors {\n name: string\n iconColorDefaultPrimary: string\n iconColorDefaultSecondary: string\n iconColorDefaultDim: string\n iconColorDefaultDisabled: string\n iconColorDefaultInverted: string\n}\n\nconst semanticAliasesLight: SemanticAliasesColors = {\n name: 'light',\n iconColorDefaultPrimary: neutralsLight.fillColorNeutral010,\n iconColorDefaultSecondary: neutralsLight.fillColorNeutral020,\n iconColorDefaultDim: neutralsLight.fillColorNeutral030,\n iconColorDefaultDisabled: neutralsLight.fillColorNeutral040,\n iconColorDefaultInverted: neutralsLight.fillColorNeutral100Inverted,\n}\n\nconst semanticAliasesDark: SemanticAliasesColors = {\n name: 'dark',\n iconColorDefaultPrimary: neutralsDark.fillColorNeutral010,\n iconColorDefaultSecondary: neutralsDark.fillColorNeutral020,\n iconColorDefaultDim: neutralsDark.fillColorNeutral030,\n iconColorDefaultDisabled: neutralsDark.fillColorNeutral040,\n iconColorDefaultInverted: neutralsDark.fillColorNeutral100Inverted,\n}\n\nexport const tapestryAliasTokensColorMap = {\n light: { ...neutralsLight, ...semanticAliasesLight },\n dark: { ...neutralsDark, ...semanticAliasesDark },\n}\n"]}
@@ -0,0 +1,38 @@
1
+ export declare const tokens: {
2
+ borderRadiusDefault: number;
3
+ spacingFourth: number;
4
+ spacingHalf: number;
5
+ spacing1: number;
6
+ spacing2: number;
7
+ spacing3: number;
8
+ spacing4: number;
9
+ spacing5: number;
10
+ spacing6: number;
11
+ spacing7: number;
12
+ borderRadiusSm: number;
13
+ borderRadiusMd: number;
14
+ borderRadiusLg: number;
15
+ borderRadiusXl: number;
16
+ borderRadiusRound: number;
17
+ borderSizeDefault: number;
18
+ borderSizeThick: number;
19
+ colorNeutral7: string;
20
+ colorNeutral12: string;
21
+ colorNeutral15: string;
22
+ colorNeutral17: string;
23
+ colorNeutral19: string;
24
+ colorNeutral24: string;
25
+ colorNeutral32: string;
26
+ colorNeutral45: string;
27
+ colorNeutral50: string;
28
+ colorNeutral58: string;
29
+ colorNeutral68: string;
30
+ colorNeutral81: string;
31
+ colorNeutral88: string;
32
+ colorNeutral93: string;
33
+ colorNeutral95: string;
34
+ colorNeutral97: string;
35
+ colorNeutral98: string;
36
+ colorNeutral100White: string;
37
+ };
38
+ //# sourceMappingURL=tokens.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../../src/vendor/tapestry/tokens.ts"],"names":[],"mappings":"AA4FA,eAAO,MAAM,MAAM;yBAPI,MAAM;mBAtCZ,MAAM;iBACR,MAAM;cACT,MAAM;cACN,MAAM;cACN,MAAM;cACN,MAAM;cACN,MAAM;cACN,MAAM;cACN,MAAM;oBACA,MAAM;oBACN,MAAM;oBACN,MAAM;oBACN,MAAM;uBACH,MAAM;uBACN,MAAM;qBACR,MAAM;mBAzDR,MAAM;oBACL,MAAM;oBACN,MAAM;oBACN,MAAM;oBACN,MAAM;oBACN,MAAM;oBACN,MAAM;oBACN,MAAM;oBACN,MAAM;oBACN,MAAM;oBACN,MAAM;oBACN,MAAM;oBACN,MAAM;oBACN,MAAM;oBACN,MAAM;oBACN,MAAM;oBACN,MAAM;0BACA,MAAM;CA0E7B,CAAA"}
@@ -0,0 +1,50 @@
1
+ // Copied from `@planningcenter/tapestry` package.
2
+ // Defining these tokens locally is a temporary solution until the package supports mobile.
3
+ // Tokens Reference: https://planningcenter.github.io/tapestry/?path=/docs/foundations-design-tokens--docs
4
+ const colorPrimitives = {
5
+ colorNeutral7: 'hsl(0, 0%, 7%)',
6
+ colorNeutral12: 'hsl(0, 0%, 12%)',
7
+ colorNeutral15: 'hsl(0, 0%, 15%)',
8
+ colorNeutral17: 'hsl(0, 0%, 17%)',
9
+ colorNeutral19: 'hsl(0, 0%, 19%)',
10
+ colorNeutral24: 'hsl(0, 0%, 24%)',
11
+ colorNeutral32: 'hsl(0, 0%, 32%)',
12
+ colorNeutral45: 'hsl(0, 0%, 45%)',
13
+ colorNeutral50: 'hsl(0, 0%, 50%)',
14
+ colorNeutral58: 'hsl(0, 0%, 58%)',
15
+ colorNeutral68: 'hsl(0, 0%, 68%)',
16
+ colorNeutral81: 'hsl(0, 0%, 81%)',
17
+ colorNeutral88: 'hsl(0, 0%, 88%)',
18
+ colorNeutral93: 'hsl(0, 0%, 93%)',
19
+ colorNeutral95: 'hsl(0, 0%, 95%)',
20
+ colorNeutral97: 'hsl(0, 0%, 97%)',
21
+ colorNeutral98: 'hsl(0, 0%, 98%)',
22
+ colorNeutral100White: 'hsl(0, 0%, 100%)',
23
+ };
24
+ const numericPrimtives = {
25
+ spacingFourth: 2,
26
+ spacingHalf: 4,
27
+ spacing1: 8,
28
+ spacing2: 16,
29
+ spacing3: 24,
30
+ spacing4: 32,
31
+ spacing5: 40,
32
+ spacing6: 48,
33
+ spacing7: 56,
34
+ borderRadiusSm: 2,
35
+ borderRadiusMd: 4,
36
+ borderRadiusLg: 8,
37
+ borderRadiusXl: 16,
38
+ borderRadiusRound: 56,
39
+ borderSizeDefault: 1,
40
+ borderSizeThick: 2,
41
+ };
42
+ const numericAliases = {
43
+ borderRadiusDefault: numericPrimtives.borderRadiusMd,
44
+ };
45
+ export const tokens = {
46
+ ...colorPrimitives,
47
+ ...numericPrimtives,
48
+ ...numericAliases,
49
+ };
50
+ //# sourceMappingURL=tokens.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokens.js","sourceRoot":"","sources":["../../../src/vendor/tapestry/tokens.ts"],"names":[],"mappings":"AAAA,kDAAkD;AAClD,2FAA2F;AAC3F,0GAA0G;AAuB1G,MAAM,eAAe,GAAmB;IACtC,aAAa,EAAE,gBAAgB;IAC/B,cAAc,EAAE,iBAAiB;IACjC,cAAc,EAAE,iBAAiB;IACjC,cAAc,EAAE,iBAAiB;IACjC,cAAc,EAAE,iBAAiB;IACjC,cAAc,EAAE,iBAAiB;IACjC,cAAc,EAAE,iBAAiB;IACjC,cAAc,EAAE,iBAAiB;IACjC,cAAc,EAAE,iBAAiB;IACjC,cAAc,EAAE,iBAAiB;IACjC,cAAc,EAAE,iBAAiB;IACjC,cAAc,EAAE,iBAAiB;IACjC,cAAc,EAAE,iBAAiB;IACjC,cAAc,EAAE,iBAAiB;IACjC,cAAc,EAAE,iBAAiB;IACjC,cAAc,EAAE,iBAAiB;IACjC,cAAc,EAAE,iBAAiB;IACjC,oBAAoB,EAAE,kBAAkB;CACzC,CAAA;AAqBD,MAAM,gBAAgB,GAAsB;IAC1C,aAAa,EAAE,CAAC;IAChB,WAAW,EAAE,CAAC;IACd,QAAQ,EAAE,CAAC;IACX,QAAQ,EAAE,EAAE;IACZ,QAAQ,EAAE,EAAE;IACZ,QAAQ,EAAE,EAAE;IACZ,QAAQ,EAAE,EAAE;IACZ,QAAQ,EAAE,EAAE;IACZ,QAAQ,EAAE,EAAE;IACZ,cAAc,EAAE,CAAC;IACjB,cAAc,EAAE,CAAC;IACjB,cAAc,EAAE,CAAC;IACjB,cAAc,EAAE,EAAE;IAClB,iBAAiB,EAAE,EAAE;IACrB,iBAAiB,EAAE,CAAC;IACpB,eAAe,EAAE,CAAC;CACnB,CAAA;AAMD,MAAM,cAAc,GAAmB;IACrC,mBAAmB,EAAE,gBAAgB,CAAC,cAAc;CACrD,CAAA;AAED,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,GAAG,eAAe;IAClB,GAAG,gBAAgB;IACnB,GAAG,cAAc;CAClB,CAAA","sourcesContent":["// Copied from `@planningcenter/tapestry` package.\n// Defining these tokens locally is a temporary solution until the package supports mobile.\n// Tokens Reference: https://planningcenter.github.io/tapestry/?path=/docs/foundations-design-tokens--docs\n\ninterface ColorPrimitves {\n colorNeutral7: string\n colorNeutral12: string\n colorNeutral15: string\n colorNeutral17: string\n colorNeutral19: string\n colorNeutral24: string\n colorNeutral32: string\n colorNeutral45: string\n colorNeutral50: string\n colorNeutral58: string\n colorNeutral68: string\n colorNeutral81: string\n colorNeutral88: string\n colorNeutral93: string\n colorNeutral95: string\n colorNeutral97: string\n colorNeutral98: string\n colorNeutral100White: string\n}\n\nconst colorPrimitives: ColorPrimitves = {\n colorNeutral7: 'hsl(0, 0%, 7%)',\n colorNeutral12: 'hsl(0, 0%, 12%)',\n colorNeutral15: 'hsl(0, 0%, 15%)',\n colorNeutral17: 'hsl(0, 0%, 17%)',\n colorNeutral19: 'hsl(0, 0%, 19%)',\n colorNeutral24: 'hsl(0, 0%, 24%)',\n colorNeutral32: 'hsl(0, 0%, 32%)',\n colorNeutral45: 'hsl(0, 0%, 45%)',\n colorNeutral50: 'hsl(0, 0%, 50%)',\n colorNeutral58: 'hsl(0, 0%, 58%)',\n colorNeutral68: 'hsl(0, 0%, 68%)',\n colorNeutral81: 'hsl(0, 0%, 81%)',\n colorNeutral88: 'hsl(0, 0%, 88%)',\n colorNeutral93: 'hsl(0, 0%, 93%)',\n colorNeutral95: 'hsl(0, 0%, 95%)',\n colorNeutral97: 'hsl(0, 0%, 97%)',\n colorNeutral98: 'hsl(0, 0%, 98%)',\n colorNeutral100White: 'hsl(0, 0%, 100%)',\n}\n\ninterface NumericPrimitives {\n spacingFourth: number\n spacingHalf: number\n spacing1: number\n spacing2: number\n spacing3: number\n spacing4: number\n spacing5: number\n spacing6: number\n spacing7: number\n borderRadiusSm: number\n borderRadiusMd: number\n borderRadiusLg: number\n borderRadiusXl: number\n borderRadiusRound: number\n borderSizeDefault: number\n borderSizeThick: number\n}\n\nconst numericPrimtives: NumericPrimitives = {\n spacingFourth: 2,\n spacingHalf: 4,\n spacing1: 8,\n spacing2: 16,\n spacing3: 24,\n spacing4: 32,\n spacing5: 40,\n spacing6: 48,\n spacing7: 56,\n borderRadiusSm: 2,\n borderRadiusMd: 4,\n borderRadiusLg: 8,\n borderRadiusXl: 16,\n borderRadiusRound: 56,\n borderSizeDefault: 1,\n borderSizeThick: 2,\n}\n\ninterface NumericAliases {\n borderRadiusDefault: number\n}\n\nconst numericAliases: NumericAliases = {\n borderRadiusDefault: numericPrimtives.borderRadiusMd,\n}\n\nexport const tokens = {\n ...colorPrimitives,\n ...numericPrimtives,\n ...numericAliases,\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@planningcenter/chat-react-native",
3
- "version": "1.3.0-rc.4",
3
+ "version": "1.3.0-rc.6",
4
4
  "description": "",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -14,6 +14,7 @@
14
14
  },
15
15
  "peerDependencies": {
16
16
  "@tanstack/react-query": "^5.0.0",
17
+ "lodash": "*",
17
18
  "react": "*",
18
19
  "react-native": "*"
19
20
  },
@@ -22,8 +23,9 @@
22
23
  "@tanstack/react-query": "^5.66.0",
23
24
  "@typescript-eslint/parser": "^8.23.0",
24
25
  "expo-module-scripts": "^3.4.0",
26
+ "lodash": "^4.17.21",
25
27
  "prettier": "^3.4.2",
26
28
  "react-native": "0.74.5"
27
29
  },
28
- "gitHead": "75d05da3bdb2dc2509914389d319df9b2868042f"
30
+ "gitHead": "2d5340552b2daf0cf8c973071cd3e851fff6c520"
29
31
  }
@@ -1,7 +1,8 @@
1
- import { useSuspenseQuery } from '@tanstack/react-query'
1
+ import { QueryErrorResetBoundary, useSuspenseQuery } from '@tanstack/react-query'
2
2
  import React, { Suspense, useContext } from 'react'
3
3
  import { FlatList, StyleSheet, Text } from 'react-native'
4
- import { ChatContext } from '../context/chat_context'
4
+ import { ChatContext } from '../contexts/chat_context'
5
+ import { useTheme } from '../hooks/use_theme'
5
6
  import { ConversationRecord } from '../types'
6
7
  import ErrorBoundary from './error_boundary'
7
8
 
@@ -12,60 +13,46 @@ type ConversationsResponse = {
12
13
  }
13
14
 
14
15
  export function Conversations() {
16
+ const { token } = useContext(ChatContext)
17
+
18
+ if (!token) return null
19
+
15
20
  return (
16
- <ErrorBoundary>
17
- <Suspense fallback={<></>}>
18
- <Loaded />
19
- </Suspense>
20
- </ErrorBoundary>
21
+ <QueryErrorResetBoundary>
22
+ {({ reset }) => (
23
+ <ErrorBoundary onReset={reset}>
24
+ <Suspense fallback={<Text>loading...</Text>}>
25
+ <Loaded />
26
+ </Suspense>
27
+ </ErrorBoundary>
28
+ )}
29
+ </QueryErrorResetBoundary>
21
30
  )
22
31
  }
23
32
 
24
33
  const Loaded = () => {
25
- const { token, onTokenExpired } = useContext(ChatContext)
26
34
  const styles = useStyles()
27
35
  const { data: conversations } = useSuspenseQuery<ConversationsResponse>({
28
- queryKey: ['conversations', token],
29
- queryFn: () =>
30
- // TODO: replace with an api client
31
- fetch('https://api.planningcenteronline.com/chat/v2/me/conversations', {
32
- headers: {
33
- Authorization: `Bearer ${token?.access_token}`,
34
- },
35
- })
36
- .then(validateResponse)
37
- .then(response => response.json())
38
- .catch(error => {
39
- if (error.message === 'Token expired') {
40
- onTokenExpired()
41
- }
42
- return null
43
- }),
36
+ queryKey: ['/chat/v2/me/conversations'],
44
37
  })
45
38
 
46
39
  return (
47
40
  <FlatList
48
41
  data={conversations?.data}
49
- ListEmptyComponent={<Text>No conversations</Text>}
50
42
  contentContainerStyle={styles.container}
43
+ ListEmptyComponent={<Text>No conversations found</Text>}
51
44
  ListHeaderComponent={<Text style={styles.foo}>Conversations</Text>}
52
- renderItem={({ item }) => <Text>{item.attributes.title}</Text>}
45
+ renderItem={({ item }) => <Text style={styles.listItem}>{item.attributes.title}</Text>}
53
46
  />
54
47
  )
55
48
  }
56
49
 
57
50
  const useStyles = () => {
51
+ const { colors } = useTheme()
52
+
58
53
  return StyleSheet.create({
59
- container: { columnGap: 16 },
60
- foo: { fontSize: 24 },
54
+ container: { columnGap: 16, backgroundColor: colors.fillColorNeutral080 },
55
+ foo: { fontSize: 24, color: colors.testColor },
56
+ listItem: { color: colors.fillColorNeutral020 },
61
57
  })
62
58
  }
63
-
64
- const validateResponse = (response: Response) => {
65
- const isExpired = response.status === 401
66
- if (isExpired) {
67
- throw new Error('Token expired')
68
- }
69
-
70
- return response
71
- }
@@ -1,7 +1,7 @@
1
1
  import React, { PropsWithChildren } from 'react'
2
2
  import { Text } from 'react-native'
3
3
 
4
- class ErrorBoundary extends React.Component<PropsWithChildren<{}>> {
4
+ class ErrorBoundary extends React.Component<PropsWithChildren<{ onReset?: () => void }>> {
5
5
  state = {
6
6
  error: null,
7
7
  unsubscriber: () => {},
@@ -0,0 +1,69 @@
1
+ import { QueryClient, QueryClientProvider, QueryKey } from '@tanstack/react-query'
2
+ import React from 'react'
3
+ import { ViewProps } from 'react-native'
4
+ import { OAuthToken } from '../types'
5
+
6
+ type ENV = 'production' | 'staging' | 'development'
7
+ let environment: ENV = 'production'
8
+ let oauthToken: OAuthToken | undefined
9
+ let handleTokenExpired: () => void
10
+
11
+ const hostMap = {
12
+ production: 'https://api.planningcenteronline.com',
13
+ staging: 'https://api-staging.planningcenteronline.com',
14
+ development: 'https://api.pco.test',
15
+ }
16
+
17
+ const defaultQueryFn = ({ queryKey }: { queryKey: QueryKey }) => {
18
+ if (!oauthToken) {
19
+ console.error('No token present')
20
+ throw new Error('No token present')
21
+ }
22
+
23
+ const url = `${hostMap[environment]}${queryKey[0]}`
24
+
25
+ return fetch(url, {
26
+ headers: {
27
+ Authorization: `Bearer ${oauthToken?.access_token}`,
28
+ },
29
+ })
30
+ .then(validateResponse)
31
+ .then(response => response.json())
32
+ .catch(error => {
33
+ if (error.message === 'Token expired') {
34
+ handleTokenExpired()
35
+ }
36
+ return null
37
+ })
38
+ }
39
+
40
+ export const queryClient = new QueryClient({
41
+ defaultOptions: {
42
+ queries: {
43
+ queryFn: defaultQueryFn,
44
+ },
45
+ },
46
+ })
47
+
48
+ export function ApiProvider({
49
+ children,
50
+ env = 'production',
51
+ token,
52
+ onTokenExpired,
53
+ }: ViewProps & { env?: ENV; token?: OAuthToken; onTokenExpired: () => void }) {
54
+ oauthToken = token
55
+ handleTokenExpired = onTokenExpired
56
+ environment = env
57
+
58
+ return <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
59
+ }
60
+
61
+ const validateResponse = (response: Response) => {
62
+ const isExpired = response.status === 401
63
+
64
+ if (isExpired) {
65
+ throw new Error('Token expired')
66
+ }
67
+
68
+ return response
69
+ }
@@ -0,0 +1,29 @@
1
+ import React, { createContext } from 'react'
2
+ import { OAuthToken } from '../types'
3
+ import { ApiProvider } from './api_provider'
4
+
5
+ type ContextValue = {
6
+ token?: OAuthToken
7
+ onTokenExpired: () => void
8
+ theme: any
9
+ env?: 'production' | 'staging' | 'development'
10
+ }
11
+
12
+ export const ChatContext = createContext<ContextValue>({
13
+ theme: undefined,
14
+ token: undefined,
15
+ env: undefined,
16
+ onTokenExpired: () => {},
17
+ })
18
+
19
+ export function ChatProvider({ children, value }: { children: any; value: ContextValue }) {
20
+ if (!Object.keys(value.token || {}).length) return null
21
+
22
+ return (
23
+ <ChatContext.Provider value={value}>
24
+ <ApiProvider env={value.env} token={value.token} onTokenExpired={value.onTokenExpired}>
25
+ {children}
26
+ </ApiProvider>
27
+ </ChatContext.Provider>
28
+ )
29
+ }
@@ -0,0 +1,41 @@
1
+ import AsyncStorage from '@react-native-async-storage/async-storage'
2
+ import { useSuspenseQuery } from '@tanstack/react-query'
3
+ import { useCallback } from 'react'
4
+
5
+ const cacheKeyGenerator = (key: string) => [`AsyncStorageResource:${key}`]
6
+
7
+ type SetValue<TCacheData> = (_itemValue?: TCacheData | null) => void
8
+
9
+ export function useAsyncStorage<TCacheData>(
10
+ key: string,
11
+ initialValue: TCacheData
12
+ ): [TCacheData, SetValue<TCacheData>] {
13
+ const cacheKey = cacheKeyGenerator(key)
14
+ const { data: value, refetch } = useSuspenseQuery<TCacheData>({
15
+ queryKey: cacheKey,
16
+ queryFn: () =>
17
+ AsyncStorage.getItem(key).then(storedValue => {
18
+ if (!storedValue) return initialValue
19
+
20
+ try {
21
+ return JSON.parse(storedValue)
22
+ } catch {
23
+ return storedValue
24
+ }
25
+ }),
26
+ })
27
+
28
+ const setValue: SetValue<TCacheData> = useCallback(
29
+ itemValue => {
30
+ if (itemValue === null || itemValue === undefined) {
31
+ AsyncStorage.removeItem(key)
32
+ } else {
33
+ AsyncStorage.setItem(key, JSON.stringify(itemValue))
34
+ }
35
+ refetch()
36
+ },
37
+ [key, refetch]
38
+ )
39
+
40
+ return [value || initialValue, setValue]
41
+ }
@@ -0,0 +1,31 @@
1
+ import { useMemo } from 'react'
2
+ import { useColorScheme, ColorSchemeName } from 'react-native'
3
+ import { defaultTheme, DefaultTheme } from '../utils/theme'
4
+ import { DeepPartial } from '../types'
5
+ import { tapestryAliasTokensColorMap } from '../vendor/tapestry/tapestry_alias_tokens_color_map'
6
+ import { merge } from 'lodash'
7
+
8
+ interface CreateChatThemeProps {
9
+ theme?: DeepPartial<DefaultTheme>
10
+ colorScheme?: ColorSchemeName
11
+ }
12
+
13
+ export const useCreateChatTheme = ({
14
+ theme: customTheme = {},
15
+ colorScheme: appColorScheme,
16
+ }: CreateChatThemeProps) => {
17
+ const internalColorScheme = useColorScheme() || 'light'
18
+ const colorScheme = appColorScheme || internalColorScheme
19
+
20
+ const memoizedTheme = useMemo(() => {
21
+ return {
22
+ ...merge({}, defaultTheme(colorScheme), customTheme),
23
+ colors: {
24
+ ...merge({}, defaultTheme(colorScheme).colors, customTheme?.colors),
25
+ ...tapestryAliasTokensColorMap[colorScheme],
26
+ },
27
+ }
28
+ }, [colorScheme, customTheme])
29
+
30
+ return memoizedTheme
31
+ }
@@ -0,0 +1,9 @@
1
+ import { useContext } from 'react'
2
+ import { ChatContext } from '../contexts/chat_context'
3
+ import { ChatTheme } from '../utils/theme'
4
+
5
+ export const useTheme = (): ChatTheme => {
6
+ const { theme } = useContext(ChatContext)
7
+
8
+ return theme
9
+ }
package/src/index.tsx CHANGED
@@ -1,5 +1,14 @@
1
1
  import { Conversations } from './components/conversations'
2
- import { ChatContext } from './context/chat_context'
3
- import { OauthToken } from './types'
2
+ import { ChatContext, ChatProvider } from './contexts/chat_context'
3
+ import { useCreateChatTheme } from './hooks/use_create_chat_theme'
4
+ import { OAuthToken } from './types'
5
+ import { TemporaryDefaultColorsType } from './utils/theme'
4
6
 
5
- export { ChatContext, Conversations, OauthToken as OathToken }
7
+ export {
8
+ ChatContext,
9
+ ChatProvider,
10
+ Conversations,
11
+ OAuthToken,
12
+ TemporaryDefaultColorsType,
13
+ useCreateChatTheme,
14
+ }
package/src/types.d.ts CHANGED
@@ -8,12 +8,17 @@ export type ConversationRecord = {
8
8
  }
9
9
  }
10
10
 
11
- export type OauthToken = {
12
- subdomain: any
13
- type: any
11
+ export type OAuthToken = {
12
+ token_type: any
14
13
  access_token: any
15
14
  created_at: number
16
15
  expires_in: any
17
- person: any
16
+ scope: string
18
17
  refresh_token: any
19
18
  }
19
+
20
+ // Sets all the properties of of a deeply nested object to optional.
21
+ // Example: `DeepPartial<ChatTheme>`
22
+ export type DeepPartial<T> = {
23
+ [P in keyof T]?: DeepPartial<T[P]>
24
+ }
@@ -0,0 +1,73 @@
1
+ import { TextStyle, ViewStyle, ColorSchemeName } from 'react-native'
2
+ import { tokens } from '../vendor/tapestry/tokens'
3
+ import { tapestryAliasTokensColorMap } from '../vendor/tapestry/tapestry_alias_tokens_color_map'
4
+
5
+ export interface ChatTheme extends DefaultTheme {
6
+ colors: DefaultTheme['colors'] &
7
+ (typeof tapestryAliasTokensColorMap.light | typeof tapestryAliasTokensColorMap.dark)
8
+ }
9
+
10
+ /** =============================================
11
+ NOTE: The specific values for `colors` and the `productBadge` are temporary examples that can be replaced once we start building out UI. This line's comment can be removed at that time too.
12
+
13
+ The default theme is intended to support two types of customizations:
14
+ 1. Specific color properties for a chat component (eg. `primaryButtonBackgroundColor`)
15
+ 2. Any styles for a specific component. (Use only one level of nesting.)
16
+ ```
17
+ primaryButton: {
18
+ container: ViewStyle
19
+ text: TextStyle
20
+ }
21
+ ```
22
+ ============================================= */
23
+
24
+ export interface DefaultTheme {
25
+ colors: ChatColors
26
+ temporaryProductBadge: {
27
+ container: ViewStyle
28
+ text: TextStyle
29
+ }
30
+ }
31
+
32
+ export const defaultTheme = (colorScheme: ColorSchemeName): DefaultTheme => {
33
+ const scheme = colorScheme || 'light'
34
+
35
+ return {
36
+ colors: chatThemeColorMap[scheme],
37
+ temporaryProductBadge: {
38
+ container: {
39
+ paddingHorizontal: tokens.spacing1,
40
+ backgroundColor: tapestryAliasTokensColorMap[scheme].fillColorNeutral070,
41
+ borderWidth: tokens.borderSizeDefault,
42
+ },
43
+ text: {
44
+ textAlign: 'center',
45
+ },
46
+ },
47
+ }
48
+ }
49
+
50
+ export type TemporaryDefaultColorsType = Partial<ChatColors>
51
+
52
+ interface ChatColors {
53
+ name: string
54
+ temporaryButtonBackgroundColor: string
55
+ testColor: string
56
+ }
57
+
58
+ const colorsChatLight: ChatColors = {
59
+ name: 'light',
60
+ temporaryButtonBackgroundColor: tokens.colorNeutral95,
61
+ testColor: 'red',
62
+ }
63
+
64
+ const colorsChatDark: ChatColors = {
65
+ name: 'dark',
66
+ temporaryButtonBackgroundColor: tokens.colorNeutral17,
67
+ testColor: 'blue',
68
+ }
69
+
70
+ const chatThemeColorMap = {
71
+ light: colorsChatLight,
72
+ dark: colorsChatDark,
73
+ }