@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.
- package/CHANGELOG.md +25 -0
- package/build/components/conversations.d.ts +1 -1
- package/build/components/conversations.d.ts.map +1 -1
- package/build/components/conversations.js +19 -34
- package/build/components/conversations.js.map +1 -1
- package/build/components/error_boundary.d.ts +3 -1
- package/build/components/error_boundary.d.ts.map +1 -1
- package/build/components/error_boundary.js.map +1 -1
- package/build/contexts/api_provider.d.ts +13 -0
- package/build/contexts/api_provider.d.ts.map +1 -0
- package/build/contexts/api_provider.js +51 -0
- package/build/contexts/api_provider.js.map +1 -0
- package/build/contexts/chat_context.d.ts +15 -0
- package/build/contexts/chat_context.d.ts.map +1 -0
- package/build/contexts/chat_context.js +18 -0
- package/build/contexts/chat_context.js.map +1 -0
- package/build/hooks/use_async_storage.d.ts +4 -0
- package/build/hooks/use_async_storage.d.ts.map +1 -0
- package/build/hooks/use_async_storage.js +31 -0
- package/build/hooks/use_async_storage.js.map +1 -0
- package/build/hooks/use_create_chat_theme.d.ts +10 -0
- package/build/hooks/use_create_chat_theme.d.ts.map +1 -0
- package/build/hooks/use_create_chat_theme.js +20 -0
- package/build/hooks/use_create_chat_theme.js.map +1 -0
- package/build/hooks/use_theme.d.ts +3 -0
- package/build/hooks/use_theme.d.ts.map +1 -0
- package/build/hooks/use_theme.js +7 -0
- package/build/hooks/use_theme.js.map +1 -0
- package/build/index.d.ts +5 -3
- package/build/index.d.ts.map +1 -1
- package/build/index.js +3 -2
- package/build/index.js.map +1 -1
- package/build/utils/theme.d.ts +34 -0
- package/build/utils/theme.d.ts.map +1 -0
- package/build/utils/theme.js +33 -0
- package/build/utils/theme.js.map +1 -0
- package/build/vendor/tapestry/tapestry_alias_tokens_color_map.d.ts +41 -0
- package/build/vendor/tapestry/tapestry_alias_tokens_color_map.d.ts.map +1 -0
- package/build/vendor/tapestry/tapestry_alias_tokens_color_map.js +50 -0
- package/build/vendor/tapestry/tapestry_alias_tokens_color_map.js.map +1 -0
- package/build/vendor/tapestry/tokens.d.ts +38 -0
- package/build/vendor/tapestry/tokens.d.ts.map +1 -0
- package/build/vendor/tapestry/tokens.js +50 -0
- package/build/vendor/tapestry/tokens.js.map +1 -0
- package/package.json +4 -2
- package/src/components/conversations.tsx +24 -37
- package/src/components/error_boundary.tsx +1 -1
- package/src/contexts/api_provider.tsx +69 -0
- package/src/contexts/chat_context.tsx +29 -0
- package/src/hooks/use_async_storage.ts +41 -0
- package/src/hooks/use_create_chat_theme.tsx +31 -0
- package/src/hooks/use_theme.tsx +9 -0
- package/src/index.tsx +12 -3
- package/src/types.d.ts +9 -4
- package/src/utils/theme.ts +73 -0
- package/src/vendor/tapestry/tapestry_alias_tokens_color_map.ts +82 -0
- package/src/vendor/tapestry/tokens.ts +97 -0
- package/build/context/chat_context.d.ts +0 -9
- package/build/context/chat_context.d.ts.map +0 -1
- package/build/context/chat_context.js +0 -7
- package/build/context/chat_context.js.map +0 -1
- 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.
|
|
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": "
|
|
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 '../
|
|
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
|
-
<
|
|
17
|
-
|
|
18
|
-
<
|
|
19
|
-
|
|
20
|
-
|
|
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'
|
|
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
|
+
}
|
package/src/index.tsx
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
import { Conversations } from './components/conversations'
|
|
2
|
-
import { ChatContext } from './
|
|
3
|
-
import {
|
|
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 {
|
|
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
|
|
12
|
-
|
|
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
|
-
|
|
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
|
+
}
|