@chatlychat/react-native 0.0.0-stage → 0.1.1

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 (114) hide show
  1. package/README.md +208 -2
  2. package/dist/ChatlyProvider.d.ts +69 -0
  3. package/dist/ChatlyProvider.d.ts.map +1 -0
  4. package/dist/ChatlyProvider.js +146 -0
  5. package/dist/ChatlyProvider.js.map +1 -0
  6. package/dist/ChatlyWidget.d.ts +15 -0
  7. package/dist/ChatlyWidget.d.ts.map +1 -0
  8. package/dist/ChatlyWidget.js +122 -0
  9. package/dist/ChatlyWidget.js.map +1 -0
  10. package/dist/blocks/money.d.ts +56 -0
  11. package/dist/blocks/money.d.ts.map +1 -0
  12. package/dist/blocks/money.js +82 -0
  13. package/dist/blocks/money.js.map +1 -0
  14. package/dist/blocks/money.parity.spec.d.ts +2 -0
  15. package/dist/blocks/money.parity.spec.d.ts.map +1 -0
  16. package/dist/blocks/money.parity.spec.js +87 -0
  17. package/dist/blocks/money.parity.spec.js.map +1 -0
  18. package/dist/blocks/read-envelope.d.ts +15 -0
  19. package/dist/blocks/read-envelope.d.ts.map +1 -0
  20. package/dist/blocks/read-envelope.js +196 -0
  21. package/dist/blocks/read-envelope.js.map +1 -0
  22. package/dist/blocks/read-envelope.parity.spec.d.ts +2 -0
  23. package/dist/blocks/read-envelope.parity.spec.d.ts.map +1 -0
  24. package/dist/blocks/read-envelope.parity.spec.js +146 -0
  25. package/dist/blocks/read-envelope.parity.spec.js.map +1 -0
  26. package/dist/blocks/types.d.ts +171 -0
  27. package/dist/blocks/types.d.ts.map +1 -0
  28. package/dist/blocks/types.js +3 -0
  29. package/dist/blocks/types.js.map +1 -0
  30. package/dist/client/RealtimeClient.d.ts +29 -0
  31. package/dist/client/RealtimeClient.d.ts.map +1 -0
  32. package/dist/client/RealtimeClient.js +113 -0
  33. package/dist/client/RealtimeClient.js.map +1 -0
  34. package/dist/client/RealtimeClient.spec.d.ts +2 -0
  35. package/dist/client/RealtimeClient.spec.d.ts.map +1 -0
  36. package/dist/client/RealtimeClient.spec.js +123 -0
  37. package/dist/client/RealtimeClient.spec.js.map +1 -0
  38. package/dist/client/RestClient.d.ts +160 -0
  39. package/dist/client/RestClient.d.ts.map +1 -0
  40. package/dist/client/RestClient.js +395 -0
  41. package/dist/client/RestClient.js.map +1 -0
  42. package/dist/client/RestClient.spec.d.ts +2 -0
  43. package/dist/client/RestClient.spec.d.ts.map +1 -0
  44. package/dist/client/RestClient.spec.js +267 -0
  45. package/dist/client/RestClient.spec.js.map +1 -0
  46. package/dist/client/types.d.ts +148 -0
  47. package/dist/client/types.d.ts.map +1 -0
  48. package/dist/client/types.js +14 -0
  49. package/dist/client/types.js.map +1 -0
  50. package/dist/components/Composer.d.ts +35 -0
  51. package/dist/components/Composer.d.ts.map +1 -0
  52. package/dist/components/Composer.js +180 -0
  53. package/dist/components/Composer.js.map +1 -0
  54. package/dist/components/HelpCenter.d.ts +13 -0
  55. package/dist/components/HelpCenter.d.ts.map +1 -0
  56. package/dist/components/HelpCenter.js +96 -0
  57. package/dist/components/HelpCenter.js.map +1 -0
  58. package/dist/components/MessageBlocks.d.ts +41 -0
  59. package/dist/components/MessageBlocks.d.ts.map +1 -0
  60. package/dist/components/MessageBlocks.js +167 -0
  61. package/dist/components/MessageBlocks.js.map +1 -0
  62. package/dist/components/MessageBubble.d.ts +14 -0
  63. package/dist/components/MessageBubble.d.ts.map +1 -0
  64. package/dist/components/MessageBubble.js +87 -0
  65. package/dist/components/MessageBubble.js.map +1 -0
  66. package/dist/components/MessageBubble.spec.d.ts +2 -0
  67. package/dist/components/MessageBubble.spec.d.ts.map +1 -0
  68. package/dist/components/MessageBubble.spec.js +207 -0
  69. package/dist/components/MessageBubble.spec.js.map +1 -0
  70. package/dist/components/MessageCanvas.d.ts +39 -0
  71. package/dist/components/MessageCanvas.d.ts.map +1 -0
  72. package/dist/components/MessageCanvas.js +144 -0
  73. package/dist/components/MessageCanvas.js.map +1 -0
  74. package/dist/components/MessageCanvas.spec.d.ts +2 -0
  75. package/dist/components/MessageCanvas.spec.d.ts.map +1 -0
  76. package/dist/components/MessageCanvas.spec.js +142 -0
  77. package/dist/components/MessageCanvas.spec.js.map +1 -0
  78. package/dist/components/MessagesList.d.ts +8 -0
  79. package/dist/components/MessagesList.d.ts.map +1 -0
  80. package/dist/components/MessagesList.js +58 -0
  81. package/dist/components/MessagesList.js.map +1 -0
  82. package/dist/index.d.ts +48 -0
  83. package/dist/index.d.ts.map +1 -0
  84. package/dist/index.js +35 -0
  85. package/dist/index.js.map +1 -0
  86. package/dist/push/registerPushToken.d.ts +12 -0
  87. package/dist/push/registerPushToken.d.ts.map +1 -0
  88. package/dist/push/registerPushToken.js +32 -0
  89. package/dist/push/registerPushToken.js.map +1 -0
  90. package/dist/storage/TokenStore.d.ts +53 -0
  91. package/dist/storage/TokenStore.d.ts.map +1 -0
  92. package/dist/storage/TokenStore.js +89 -0
  93. package/dist/storage/TokenStore.js.map +1 -0
  94. package/dist/test/react-native-dom.d.ts +97 -0
  95. package/dist/test/react-native-dom.d.ts.map +1 -0
  96. package/dist/test/react-native-dom.js +155 -0
  97. package/dist/test/react-native-dom.js.map +1 -0
  98. package/dist/test/react-native-dom.spec.d.ts +2 -0
  99. package/dist/test/react-native-dom.spec.d.ts.map +1 -0
  100. package/dist/test/react-native-dom.spec.js +83 -0
  101. package/dist/test/react-native-dom.spec.js.map +1 -0
  102. package/dist/theme/ChatlyTheme.d.ts +37 -0
  103. package/dist/theme/ChatlyTheme.d.ts.map +1 -0
  104. package/dist/theme/ChatlyTheme.js +2 -0
  105. package/dist/theme/ChatlyTheme.js.map +1 -0
  106. package/dist/theme/defaultTheme.d.ts +7 -0
  107. package/dist/theme/defaultTheme.d.ts.map +1 -0
  108. package/dist/theme/defaultTheme.js +37 -0
  109. package/dist/theme/defaultTheme.js.map +1 -0
  110. package/dist/useChatly.d.ts +3 -0
  111. package/dist/useChatly.d.ts.map +1 -0
  112. package/dist/useChatly.js +10 -0
  113. package/dist/useChatly.js.map +1 -0
  114. package/package.json +49 -3
package/README.md CHANGED
@@ -1,3 +1,209 @@
1
- # Temporary Holding Version
1
+ # @chatlychat/react-native
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ React Native SDK for the Chatly live chat platform. Drop-in chat inbox, help
4
+ center, and push-notification wiring for iOS and Android. Talks to the same
5
+ `/v1/widget/*` REST surface and Socket.IO realtime channel as the web widget.
6
+
7
+ ## Install
8
+
9
+ ```sh
10
+ npm install @chatlychat/react-native @react-native-async-storage/async-storage
11
+ # or
12
+ yarn add @chatlychat/react-native @react-native-async-storage/async-storage
13
+ ```
14
+
15
+ `react`, `react-native`, and `@react-native-async-storage/async-storage` are
16
+ peer dependencies. `socket.io-client` is bundled.
17
+
18
+ For bare React Native apps, run `pod install` in `ios/` after installing
19
+ AsyncStorage.
20
+
21
+ ## Quick start
22
+
23
+ Wrap your app in `<ChatlyProvider>` and drop in `<ChatlyWidget />`.
24
+
25
+ ```tsx
26
+ import { ChatlyProvider, ChatlyWidget, useChatly } from '@chatlychat/react-native';
27
+
28
+ export default function App() {
29
+ return (
30
+ <ChatlyProvider config={{ publicId: 'pub_abc123', apiHost: 'api.chatly.com' }}>
31
+ <Support />
32
+ </ChatlyProvider>
33
+ );
34
+ }
35
+
36
+ function Support() {
37
+ const { unreadCount, identify, setPushToken } = useChatly();
38
+ return <ChatlyWidget />;
39
+ }
40
+ ```
41
+
42
+ ## Identifying users
43
+
44
+ Call `identify()` once you know who the user is. The SDK persists a visitor
45
+ token under `chatly:vt:<publicId>` in AsyncStorage, so subsequent app launches
46
+ re-attach to the same contact automatically.
47
+
48
+ ```tsx
49
+ const { identify } = useChatly();
50
+
51
+ await identify({
52
+ externalId: 'user-123',
53
+ email: 'alex@example.com',
54
+ name: 'Alex',
55
+ // HMAC-SHA256(externalId, workspace identity secret). Compute server-side.
56
+ userHash: 'a1b2c3…',
57
+ });
58
+ ```
59
+
60
+ `userHash` is optional but strongly recommended in production — without it,
61
+ any client could impersonate any `externalId`.
62
+
63
+ ## Push notifications
64
+
65
+ The SDK does not bundle a push provider — pick the one that suits your app:
66
+
67
+ - Expo: `expo-notifications` → `getDevicePushTokenAsync()`
68
+ - Bare RN: `@react-native-firebase/messaging` → `messaging().getToken()`
69
+ - iOS APNs directly: `@react-native-community/push-notification-ios`
70
+
71
+ Then forward the token to Chatly:
72
+
73
+ ```tsx
74
+ import messaging from '@react-native-firebase/messaging';
75
+
76
+ const { setPushToken } = useChatly();
77
+
78
+ useEffect(() => {
79
+ (async () => {
80
+ const auth = await messaging().requestPermission();
81
+ if (auth) {
82
+ const token = await messaging().getToken();
83
+ await setPushToken({ platform: 'ios', token, bundleId: 'com.your.app' });
84
+ }
85
+ })();
86
+ }, [setPushToken]);
87
+ ```
88
+
89
+ On the native side you still need the standard setup for your provider:
90
+
91
+ - iOS: enable Push Notifications + Background Modes (Remote notifications) in
92
+ Xcode, and configure an APNs key in the Chatly dashboard.
93
+ - Android: add `google-services.json` and the FCM Sender ID in the dashboard.
94
+
95
+ ## Customization
96
+
97
+ Pass a `theme` prop to override the defaults. Anything you omit falls back to
98
+ the default palette (primary `#2563eb`, background `#ffffff`, foreground
99
+ `#0f172a`).
100
+
101
+ ```tsx
102
+ <ChatlyProvider
103
+ config={{ publicId: 'pub_abc123' }}
104
+ theme={{ colors: { primary: '#10b981', onPrimary: '#ffffff' } }}
105
+ >
106
+ <App />
107
+ </ChatlyProvider>
108
+ ```
109
+
110
+ Need full control over rendering? Use the lower-level pieces directly:
111
+
112
+ ```tsx
113
+ import { MessagesList, Composer, HelpCenter } from '@chatlychat/react-native';
114
+ ```
115
+
116
+ ## Rich blocks and card actions
117
+
118
+ Bot replies can carry cards, a carousel, a price, quick replies and a status
119
+ line. `MessageBubble` renders them, so you get them for free — and the buttons
120
+ on them are real buttons, unlike the read-only rendering in the agent app.
121
+
122
+ Four of the five action kinds are handled for you: a `url` opens a link, a
123
+ `postback` sends a reply (invisibly, if the card asked), a `step` requests a
124
+ canvas. The fifth is yours.
125
+
126
+ ### `host_event` — the one your app has to run
127
+
128
+ A card saying **Pay $48.20** cannot run Stripe from inside a chat library. It
129
+ has to happen in your app, with the buyer's real session and a native payment
130
+ sheet. So the SDK does nothing for a `host_event` and calls you:
131
+
132
+ ```tsx
133
+ <ChatlyProvider
134
+ config={{ publicId: 'pub_abc123' }}
135
+ onAction={async ({ event, data, conversationId, messageId, actionId }) => {
136
+ if (event !== 'pay' || conversationId === null) return;
137
+ try {
138
+ await presentNativePaymentSheet(data);
139
+ await rest.reportAction(conversationId, {
140
+ messageId,
141
+ actionId,
142
+ status: 'done',
143
+ text: 'Paid — thank you!',
144
+ });
145
+ } catch (err) {
146
+ await rest.reportAction(conversationId, { messageId, actionId, status: 'failed' });
147
+ }
148
+ }}
149
+ >
150
+ <App />
151
+ </ChatlyProvider>
152
+ ```
153
+
154
+ **Report the outcome.** `reportAction` is what appends the visible line under
155
+ the card and tells the bot what happened. Without it the shopper is looking at
156
+ a card with nothing under it and the bot asks again.
157
+
158
+ ### Canvas steps
159
+
160
+ A Tier 2 canvas is a form inside the bubble — a confirm step for a purchase,
161
+ a return request. `MessageCanvas` renders it and submits it, and the step's
162
+ answer replaces what is on screen: a changed total comes back as a **fresh
163
+ step** rather than a charge.
164
+
165
+ A step's answer may itself carry a host event (this is how 3-D Secure works on
166
+ a phone), and that reaches the same `onAction`.
167
+
168
+ A Tier 3 canvas — your own page in a sandboxed frame — is deliberately **not**
169
+ rendered. There is no React Native equivalent of a sandbox attribute, and a
170
+ WebView is the thing a native SDK exists to avoid. The SDK shows the step's
171
+ title and leaves it to you.
172
+
173
+ ### Rendering blocks yourself
174
+
175
+ Want your own card design, a real markdown renderer, a video player, a native
176
+ clipboard? Read the envelope and render it:
177
+
178
+ ```tsx
179
+ import { readBlocksEnvelope, formatMoney } from '@chatlychat/react-native';
180
+
181
+ const envelope = readBlocksEnvelope(message.blocks);
182
+ ```
183
+
184
+ `readBlocksEnvelope` applies the same refusals the rest of the product does —
185
+ `https:` media only, an unreadable price dropped rather than rendered as
186
+ `NaN`, an unknown block type dropped instead of throwing. Prices are **minor
187
+ units**: `4820` is `$48.20` and also `¥4,820`. Use `formatMoney`; the divisor
188
+ is not 100.
189
+
190
+ ## API surface
191
+
192
+ | Export | Purpose |
193
+ | --------------------------------------------------------- | -------------------------------------------------- |
194
+ | `ChatlyProvider` | Bootstraps clients, restores session |
195
+ | `ChatlyWidget` | Drop-in inbox + help center UI |
196
+ | `useChatly()` | Access session, identify, push token, refresh |
197
+ | `MessagesList`, `Composer`, `MessageBubble`, `HelpCenter` | Composable UI |
198
+ | `MessageBlocks`, `MessageCanvas` | Cards and canvas steps, rendered |
199
+ | `onAction` on `ChatlyProvider` | `host_event` card actions, for your app to run |
200
+ | `RestClient`, `RealtimeClient` | Headless access |
201
+ | `rest.reportAction` | Tell the thread and the bot what your app did |
202
+ | `readBlocksEnvelope`, `readCanvas` | Render blocks yourself, with the same refusals |
203
+ | `formatMoney`, `readMoney` | Minor-unit prices, formatted for the device locale |
204
+ | `registerPushToken` | Helper used by `setPushToken` |
205
+ | `defaultTheme`, `ChatlyTheme` | Theming |
206
+
207
+ ## License
208
+
209
+ MIT
@@ -0,0 +1,69 @@
1
+ /**
2
+ * <ChatlyProvider /> bootstraps the REST + realtime clients, restores the
3
+ * persisted visitor token, fires `/v1/widget/init`, and exposes session state
4
+ * to descendants via the `useChatly` hook.
5
+ *
6
+ * The provider is intentionally state-light: the heavy lifting (message lists,
7
+ * composer state) lives in the components that use it. This keeps the public
8
+ * context surface stable as we add features.
9
+ */
10
+ import React from 'react';
11
+ import { RealtimeClient } from './client/RealtimeClient';
12
+ import { RestClient } from './client/RestClient';
13
+ import type { ChatlyConfig, ChatlyIdentity, ConversationSummary, InitResponse, PushTokenRegistration, SessionState } from './client/types';
14
+ import type { ChatlyTheme } from './theme/ChatlyTheme';
15
+ export interface ChatlyContextValue {
16
+ config: ChatlyConfig;
17
+ theme: ChatlyTheme;
18
+ rest: RestClient;
19
+ realtime: RealtimeClient;
20
+ session: SessionState | null;
21
+ init: InitResponse | null;
22
+ isReady: boolean;
23
+ error: Error | null;
24
+ unreadCount: number;
25
+ conversations: ConversationSummary[];
26
+ identify: (identity: ChatlyIdentity) => Promise<void>;
27
+ logout: () => Promise<void>;
28
+ setPushToken: (registration: PushTokenRegistration) => Promise<void>;
29
+ refresh: () => Promise<void>;
30
+ /**
31
+ * What the APP does about a `host_event` card action.
32
+ *
33
+ * The one feature a native SDK exists for. A card saying "Pay $48.20" has
34
+ * to run with the buyer's real session — a native payment sheet, the app's
35
+ * own cart, a screen push — and none of that can happen inside a chat
36
+ * library. So the renderer does nothing for a `host_event` and calls this.
37
+ *
38
+ * Report the outcome back with `rest.reportAction`, which appends the
39
+ * visible line under the card and tells the owning bot. Not reporting is a
40
+ * shopper looking at a card with nothing under it and a bot that asks
41
+ * again.
42
+ *
43
+ * `undefined` when the consumer did not supply one, and the renderer then
44
+ * draws the button and the tap does nothing — which is the right failure:
45
+ * a card that renders without its buttons would hide that the integrator
46
+ * has work to do.
47
+ */
48
+ onAction?: ((event: ChatlyActionEvent) => void) | undefined;
49
+ }
50
+ /** One `host_event` tap, with everything needed to report the outcome. */
51
+ export interface ChatlyActionEvent {
52
+ /** The author's own event name, e.g. `add_to_cart`. */
53
+ readonly event: string;
54
+ readonly data: Record<string, unknown>;
55
+ readonly conversationId: string | null;
56
+ readonly messageId: string;
57
+ /** Pass this back to `reportAction` so the result lands under the card. */
58
+ readonly actionId: string;
59
+ }
60
+ export declare const ChatlyContext: React.Context<ChatlyContextValue | null>;
61
+ export interface ChatlyProviderProps {
62
+ config: ChatlyConfig;
63
+ theme?: Partial<ChatlyTheme>;
64
+ children: React.ReactNode;
65
+ /** See `ChatlyContextValue.onAction`. */
66
+ onAction?: (event: ChatlyActionEvent) => void;
67
+ }
68
+ export declare function ChatlyProvider({ config, theme, children, onAction, }: ChatlyProviderProps): React.JSX.Element;
69
+ //# sourceMappingURL=ChatlyProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChatlyProvider.d.ts","sourceRoot":"","sources":["../src/ChatlyProvider.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAA2E,MAAM,OAAO,CAAC;AAEhG,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAIjD,OAAO,KAAK,EACV,YAAY,EACZ,cAAc,EACd,mBAAmB,EACnB,YAAY,EACZ,qBAAqB,EACrB,YAAY,EACb,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,YAAY,CAAC;IACrB,KAAK,EAAE,WAAW,CAAC;IACnB,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,cAAc,CAAC;IACzB,OAAO,EAAE,YAAY,GAAG,IAAI,CAAC;IAC7B,IAAI,EAAE,YAAY,GAAG,IAAI,CAAC;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,mBAAmB,EAAE,CAAC;IACrC,QAAQ,EAAE,CAAC,QAAQ,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtD,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,YAAY,EAAE,CAAC,YAAY,EAAE,qBAAqB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACrE,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B;;;;;;;;;;;;;;;;;OAiBG;IACH,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;CAC7D;AAED,0EAA0E;AAC1E,MAAM,WAAW,iBAAiB;IAChC,uDAAuD;IACvD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACvC,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,2EAA2E;IAC3E,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,eAAO,MAAM,aAAa,0CAAiD,CAAC;AAE5E,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,YAAY,CAAC;IACrB,KAAK,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;IAC7B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,yCAAyC;IACzC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;CAC/C;AAED,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EACN,KAAK,EACL,QAAQ,EACR,QAAQ,GACT,EAAE,mBAAmB,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CA6IzC"}
@@ -0,0 +1,146 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /**
3
+ * <ChatlyProvider /> bootstraps the REST + realtime clients, restores the
4
+ * persisted visitor token, fires `/v1/widget/init`, and exposes session state
5
+ * to descendants via the `useChatly` hook.
6
+ *
7
+ * The provider is intentionally state-light: the heavy lifting (message lists,
8
+ * composer state) lives in the components that use it. This keeps the public
9
+ * context surface stable as we add features.
10
+ */
11
+ import { createContext, useCallback, useEffect, useMemo, useRef, useState } from 'react';
12
+ import { RealtimeClient } from './client/RealtimeClient';
13
+ import { RestClient } from './client/RestClient';
14
+ import { registerPushToken } from './push/registerPushToken';
15
+ import { defaultTheme } from './theme/defaultTheme';
16
+ export const ChatlyContext = createContext(null);
17
+ export function ChatlyProvider({ config, theme, children, onAction, }) {
18
+ const rest = useMemo(() => new RestClient(config), [config]);
19
+ const realtime = useMemo(() => new RealtimeClient(config), [config]);
20
+ const mergedTheme = useMemo(() => mergeTheme(defaultTheme, theme), [theme]);
21
+ const [session, setSession] = useState(null);
22
+ const [init, setInit] = useState(null);
23
+ const [error, setError] = useState(null);
24
+ const [conversations, setConversations] = useState([]);
25
+ const mounted = useRef(true);
26
+ const bootstrap = useCallback(async (identity) => {
27
+ try {
28
+ const result = await rest.init(identity);
29
+ if (!mounted.current) {
30
+ return;
31
+ }
32
+ setInit(result);
33
+ setSession(result.session);
34
+ realtime.connect(result.session, result.session.token);
35
+ realtime.subscribe([`contact:${result.session.contactId}`]);
36
+ try {
37
+ const list = await rest.listConversations();
38
+ if (mounted.current) {
39
+ setConversations(list.conversations);
40
+ }
41
+ }
42
+ catch {
43
+ // Non-fatal: surface as zero conversations rather than blocking init.
44
+ }
45
+ }
46
+ catch (err) {
47
+ if (mounted.current) {
48
+ setError(err);
49
+ }
50
+ }
51
+ }, [rest, realtime]);
52
+ useEffect(() => {
53
+ mounted.current = true;
54
+ void bootstrap();
55
+ return () => {
56
+ mounted.current = false;
57
+ realtime.disconnect();
58
+ };
59
+ }, [bootstrap, realtime]);
60
+ // Refresh conversation summaries on inbound message events.
61
+ useEffect(() => {
62
+ const off = realtime.on('message.created', () => {
63
+ void rest
64
+ .listConversations()
65
+ .then((res) => {
66
+ if (mounted.current) {
67
+ setConversations(res.conversations);
68
+ }
69
+ })
70
+ .catch(() => undefined);
71
+ });
72
+ return off;
73
+ }, [realtime, rest]);
74
+ const unreadCount = useMemo(() => conversations.reduce((acc, c) => acc + (c.unreadContactCount ?? 0), 0), [conversations]);
75
+ const identify = useCallback(async (identity) => {
76
+ await bootstrap(identity);
77
+ }, [bootstrap]);
78
+ const logout = useCallback(async () => {
79
+ realtime.disconnect();
80
+ await rest.clearToken();
81
+ setSession(null);
82
+ setInit(null);
83
+ setConversations([]);
84
+ }, [realtime, rest]);
85
+ const setPushToken = useCallback(async (registration) => {
86
+ await registerPushToken(rest, registration);
87
+ }, [rest]);
88
+ const refresh = useCallback(async () => {
89
+ try {
90
+ const res = await rest.listConversations();
91
+ if (mounted.current) {
92
+ setConversations(res.conversations);
93
+ }
94
+ }
95
+ catch (err) {
96
+ if (mounted.current) {
97
+ setError(err);
98
+ }
99
+ }
100
+ }, [rest]);
101
+ const value = useMemo(() => ({
102
+ config,
103
+ theme: mergedTheme,
104
+ rest,
105
+ realtime,
106
+ session,
107
+ init,
108
+ isReady: session !== null,
109
+ error,
110
+ unreadCount,
111
+ conversations,
112
+ identify,
113
+ logout,
114
+ setPushToken,
115
+ refresh,
116
+ onAction,
117
+ }), [
118
+ config,
119
+ mergedTheme,
120
+ rest,
121
+ realtime,
122
+ session,
123
+ init,
124
+ error,
125
+ unreadCount,
126
+ conversations,
127
+ identify,
128
+ logout,
129
+ setPushToken,
130
+ refresh,
131
+ onAction,
132
+ ]);
133
+ return _jsx(ChatlyContext.Provider, { value: value, children: children });
134
+ }
135
+ function mergeTheme(base, override) {
136
+ if (override === undefined) {
137
+ return base;
138
+ }
139
+ return {
140
+ colors: { ...base.colors, ...(override.colors ?? {}) },
141
+ radius: { ...base.radius, ...(override.radius ?? {}) },
142
+ spacing: { ...base.spacing, ...(override.spacing ?? {}) },
143
+ typography: { ...base.typography, ...(override.typography ?? {}) },
144
+ };
145
+ }
146
+ //# sourceMappingURL=ChatlyProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChatlyProvider.js","sourceRoot":"","sources":["../src/ChatlyProvider.tsx"],"names":[],"mappings":";AAAA;;;;;;;;GAQG;AAEH,OAAc,EAAE,aAAa,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEhG,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AA2DpD,MAAM,CAAC,MAAM,aAAa,GAAG,aAAa,CAA4B,IAAI,CAAC,CAAC;AAU5E,MAAM,UAAU,cAAc,CAAC,EAC7B,MAAM,EACN,KAAK,EACL,QAAQ,EACR,QAAQ,GACY;IACpB,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;IAC7D,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,IAAI,cAAc,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;IAErE,MAAM,WAAW,GAAG,OAAO,CAAc,GAAG,EAAE,CAAC,UAAU,CAAC,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;IAEzF,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAsB,IAAI,CAAC,CAAC;IAClE,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAsB,IAAI,CAAC,CAAC;IAC5D,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAe,IAAI,CAAC,CAAC;IACvD,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAAwB,EAAE,CAAC,CAAC;IAC9E,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IAE7B,MAAM,SAAS,GAAG,WAAW,CAC3B,KAAK,EAAE,QAAyB,EAAiB,EAAE;QACjD,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACzC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;gBACrB,OAAO;YACT,CAAC;YACD,OAAO,CAAC,MAAM,CAAC,CAAC;YAChB,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YAC3B,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YACvD,QAAQ,CAAC,SAAS,CAAC,CAAC,WAAW,MAAM,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;YAC5D,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,iBAAiB,EAAE,CAAC;gBAC5C,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;oBACpB,gBAAgB,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;gBACvC,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,sEAAsE;YACxE,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;gBACpB,QAAQ,CAAC,GAAY,CAAC,CAAC;YACzB,CAAC;QACH,CAAC;IACH,CAAC,EACD,CAAC,IAAI,EAAE,QAAQ,CAAC,CACjB,CAAC;IAEF,SAAS,CAAC,GAAG,EAAE;QACb,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;QACvB,KAAK,SAAS,EAAE,CAAC;QACjB,OAAO,GAAS,EAAE;YAChB,OAAO,CAAC,OAAO,GAAG,KAAK,CAAC;YACxB,QAAQ,CAAC,UAAU,EAAE,CAAC;QACxB,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC;IAE1B,4DAA4D;IAC5D,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,GAAG,GAAG,QAAQ,CAAC,EAAE,CAAC,iBAAiB,EAAE,GAAG,EAAE;YAC9C,KAAK,IAAI;iBACN,iBAAiB,EAAE;iBACnB,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE;gBACZ,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;oBACpB,gBAAgB,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;gBACtC,CAAC;YACH,CAAC,CAAC;iBACD,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAC5B,CAAC,CAAC,CAAC;QACH,OAAO,GAAG,CAAC;IACb,CAAC,EAAE,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC;IAErB,MAAM,WAAW,GAAG,OAAO,CACzB,GAAG,EAAE,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,kBAAkB,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,EAC5E,CAAC,aAAa,CAAC,CAChB,CAAC;IAEF,MAAM,QAAQ,GAAG,WAAW,CAC1B,KAAK,EAAE,QAAwB,EAAiB,EAAE;QAChD,MAAM,SAAS,CAAC,QAAQ,CAAC,CAAC;IAC5B,CAAC,EACD,CAAC,SAAS,CAAC,CACZ,CAAC;IAEF,MAAM,MAAM,GAAG,WAAW,CAAC,KAAK,IAAmB,EAAE;QACnD,QAAQ,CAAC,UAAU,EAAE,CAAC;QACtB,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;QACxB,UAAU,CAAC,IAAI,CAAC,CAAC;QACjB,OAAO,CAAC,IAAI,CAAC,CAAC;QACd,gBAAgB,CAAC,EAAE,CAAC,CAAC;IACvB,CAAC,EAAE,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC;IAErB,MAAM,YAAY,GAAG,WAAW,CAC9B,KAAK,EAAE,YAAmC,EAAiB,EAAE;QAC3D,MAAM,iBAAiB,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IAC9C,CAAC,EACD,CAAC,IAAI,CAAC,CACP,CAAC;IAEF,MAAM,OAAO,GAAG,WAAW,CAAC,KAAK,IAAmB,EAAE;QACpD,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,iBAAiB,EAAE,CAAC;YAC3C,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;gBACpB,gBAAgB,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;YACtC,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;gBACpB,QAAQ,CAAC,GAAY,CAAC,CAAC;YACzB,CAAC;QACH,CAAC;IACH,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;IAEX,MAAM,KAAK,GAAG,OAAO,CACnB,GAAG,EAAE,CAAC,CAAC;QACL,MAAM;QACN,KAAK,EAAE,WAAW;QAClB,IAAI;QACJ,QAAQ;QACR,OAAO;QACP,IAAI;QACJ,OAAO,EAAE,OAAO,KAAK,IAAI;QACzB,KAAK;QACL,WAAW;QACX,aAAa;QACb,QAAQ;QACR,MAAM;QACN,YAAY;QACZ,OAAO;QACP,QAAQ;KACT,CAAC,EACF;QACE,MAAM;QACN,WAAW;QACX,IAAI;QACJ,QAAQ;QACR,OAAO;QACP,IAAI;QACJ,KAAK;QACL,WAAW;QACX,aAAa;QACb,QAAQ;QACR,MAAM;QACN,YAAY;QACZ,OAAO;QACP,QAAQ;KACT,CACF,CAAC;IAEF,OAAO,KAAC,aAAa,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,YAAG,QAAQ,GAA0B,CAAC;AACnF,CAAC;AAED,SAAS,UAAU,CAAC,IAAiB,EAAE,QAA+B;IACpE,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO;QACL,MAAM,EAAE,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,QAAQ,CAAC,MAAM,IAAI,EAAE,CAAC,EAAE;QACtD,MAAM,EAAE,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,QAAQ,CAAC,MAAM,IAAI,EAAE,CAAC,EAAE;QACtD,OAAO,EAAE,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,QAAQ,CAAC,OAAO,IAAI,EAAE,CAAC,EAAE;QACzD,UAAU,EAAE,EAAE,GAAG,IAAI,CAAC,UAAU,EAAE,GAAG,CAAC,QAAQ,CAAC,UAAU,IAAI,EAAE,CAAC,EAAE;KACnE,CAAC;AACJ,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * <ChatlyWidget /> — drop-in inbox surface. Renders the conversation list when
3
+ * none is selected, the message view + composer when one is, and (optionally)
4
+ * the help center via a tab toggle. Mirrors the "open the bubble, see your
5
+ * conversations" UX of Tawk.to / Intercom mobile SDKs.
6
+ */
7
+ import React from 'react';
8
+ export interface ChatlyWidgetProps {
9
+ /** Show the help-center tab. Defaults to true. */
10
+ enableHelpCenter?: boolean;
11
+ /** Pre-open a specific conversation. */
12
+ initialConversationId?: string;
13
+ }
14
+ export declare function ChatlyWidget({ enableHelpCenter, initialConversationId, }: ChatlyWidgetProps): React.JSX.Element;
15
+ //# sourceMappingURL=ChatlyWidget.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChatlyWidget.d.ts","sourceRoot":"","sources":["../src/ChatlyWidget.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAA2C,MAAM,OAAO,CAAC;AAqBhE,MAAM,WAAW,iBAAiB;IAChC,kDAAkD;IAClD,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,wCAAwC;IACxC,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC;AAED,wBAAgB,YAAY,CAAC,EAC3B,gBAAuB,EACvB,qBAAqB,GACtB,EAAE,iBAAiB,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAmIvC"}
@@ -0,0 +1,122 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * <ChatlyWidget /> — drop-in inbox surface. Renders the conversation list when
4
+ * none is selected, the message view + composer when one is, and (optionally)
5
+ * the help center via a tab toggle. Mirrors the "open the bubble, see your
6
+ * conversations" UX of Tawk.to / Intercom mobile SDKs.
7
+ */
8
+ import { useCallback, useEffect, useState } from 'react';
9
+ import { ActivityIndicator, FlatList, Pressable, SafeAreaView, StyleSheet, Text, View, } from 'react-native';
10
+ import { Composer } from './components/Composer';
11
+ import { HelpCenter } from './components/HelpCenter';
12
+ import { MessagesList } from './components/MessagesList';
13
+ import { useChatly } from './useChatly';
14
+ export function ChatlyWidget({ enableHelpCenter = true, initialConversationId, }) {
15
+ const { isReady, error, conversations, theme, refresh, init } = useChatly();
16
+ const [tab, setTab] = useState('messages');
17
+ const [selected, setSelected] = useState(initialConversationId ?? null);
18
+ useEffect(() => {
19
+ if (initialConversationId !== undefined) {
20
+ setSelected(initialConversationId);
21
+ }
22
+ }, [initialConversationId]);
23
+ const onSent = useCallback((conversationId) => {
24
+ setSelected(conversationId);
25
+ void refresh();
26
+ }, [refresh]);
27
+ if (error !== null) {
28
+ return (_jsx(SafeAreaView, { style: [styles.fill, { backgroundColor: theme.colors.background }], children: _jsx(View, { style: styles.center, children: _jsx(Text, { style: { color: theme.colors.danger, padding: theme.spacing.lg }, children: `Couldn't load chat: ${error.message}` }) }) }));
29
+ }
30
+ if (!isReady) {
31
+ return (_jsx(SafeAreaView, { style: [styles.fill, { backgroundColor: theme.colors.background }], children: _jsx(View, { style: styles.center, children: _jsx(ActivityIndicator, { color: theme.colors.primary }) }) }));
32
+ }
33
+ const header = (_jsxs(View, { style: [
34
+ styles.header,
35
+ {
36
+ borderBottomColor: theme.colors.border,
37
+ padding: theme.spacing.md,
38
+ backgroundColor: theme.colors.background,
39
+ },
40
+ ], children: [_jsx(Text, { style: {
41
+ color: theme.colors.foreground,
42
+ fontSize: theme.typography.sizeTitle,
43
+ fontWeight: theme.typography.weightBold,
44
+ }, children: init?.workspace.name ?? 'Support' }), enableHelpCenter && (_jsxs(View, { style: styles.tabs, children: [_jsx(TabButton, { label: "Messages", active: tab === 'messages', onPress: () => setTab('messages') }), _jsx(TabButton, { label: "Help", active: tab === 'help', onPress: () => setTab('help') })] }))] }));
45
+ if (tab === 'help') {
46
+ return (_jsxs(SafeAreaView, { style: [styles.fill, { backgroundColor: theme.colors.background }], children: [header, _jsx(HelpCenter, {})] }));
47
+ }
48
+ if (selected !== null) {
49
+ return (_jsxs(SafeAreaView, { style: [styles.fill, { backgroundColor: theme.colors.background }], children: [_jsxs(View, { style: [
50
+ styles.header,
51
+ {
52
+ borderBottomColor: theme.colors.border,
53
+ padding: theme.spacing.md,
54
+ backgroundColor: theme.colors.background,
55
+ flexDirection: 'row',
56
+ alignItems: 'center',
57
+ },
58
+ ], children: [_jsx(Pressable, { onPress: () => setSelected(null), accessibilityRole: "button", accessibilityLabel: "Back to conversation list", style: { paddingRight: theme.spacing.md }, children: _jsx(Text, { style: { color: theme.colors.primary, fontSize: theme.typography.sizeBody }, children: "\u2190" }) }), _jsx(Text, { style: {
59
+ color: theme.colors.foreground,
60
+ fontSize: theme.typography.sizeTitle,
61
+ fontWeight: theme.typography.weightBold,
62
+ }, children: "Conversation" })] }), _jsx(MessagesList, { conversationId: selected }), _jsx(Composer, { conversationId: selected, onSent: onSent })] }));
63
+ }
64
+ return (_jsxs(SafeAreaView, { style: [styles.fill, { backgroundColor: theme.colors.background }], children: [header, _jsx(ConversationList, { conversations: conversations, onOpen: setSelected }), _jsx(Composer, { conversationId: null, onSent: onSent, placeholder: "Start a new conversation\u2026" })] }));
65
+ }
66
+ function ConversationList({ conversations, onOpen, }) {
67
+ const { theme } = useChatly();
68
+ const renderItem = ({ item }) => (_jsxs(Pressable, { onPress: () => onOpen(item.id), accessibilityRole: "button", accessibilityLabel: `Open conversation ${item.subject ?? item.id}`, style: ({ pressed }) => [
69
+ {
70
+ padding: theme.spacing.md,
71
+ backgroundColor: pressed ? theme.colors.surface : theme.colors.background,
72
+ borderBottomColor: theme.colors.border,
73
+ borderBottomWidth: StyleSheet.hairlineWidth,
74
+ flexDirection: 'row',
75
+ alignItems: 'center',
76
+ },
77
+ ], children: [_jsxs(View, { style: { flex: 1 }, children: [_jsx(Text, { style: {
78
+ color: theme.colors.foreground,
79
+ fontWeight: theme.typography.weightMedium,
80
+ fontSize: theme.typography.sizeBody,
81
+ }, children: item.subject ?? 'Conversation' }), _jsx(Text, { style: {
82
+ color: theme.colors.mutedForeground,
83
+ fontSize: theme.typography.sizeSmall,
84
+ marginTop: 2,
85
+ }, numberOfLines: 1, children: item.lastMessagePreview ?? 'No messages yet.' })] }), item.unreadContactCount > 0 && (_jsx(View, { style: {
86
+ backgroundColor: theme.colors.primary,
87
+ borderRadius: 999,
88
+ minWidth: 22,
89
+ paddingHorizontal: 6,
90
+ paddingVertical: 2,
91
+ alignItems: 'center',
92
+ }, children: _jsx(Text, { style: {
93
+ color: theme.colors.onPrimary,
94
+ fontSize: theme.typography.sizeSmall,
95
+ fontWeight: theme.typography.weightBold,
96
+ }, children: item.unreadContactCount }) }))] }));
97
+ return (_jsx(FlatList, { data: conversations, keyExtractor: (c) => c.id, renderItem: renderItem, ListEmptyComponent: _jsx(Text, { style: {
98
+ color: theme.colors.mutedForeground,
99
+ textAlign: 'center',
100
+ padding: theme.spacing.lg,
101
+ }, children: "No conversations yet. Send a message to get started." }) }));
102
+ }
103
+ function TabButton({ label, active, onPress, }) {
104
+ const { theme } = useChatly();
105
+ return (_jsx(Pressable, { onPress: onPress, accessibilityRole: "tab", accessibilityState: { selected: active }, style: {
106
+ paddingHorizontal: theme.spacing.md,
107
+ paddingVertical: theme.spacing.xs,
108
+ borderBottomColor: active ? theme.colors.primary : 'transparent',
109
+ borderBottomWidth: 2,
110
+ }, children: _jsx(Text, { style: {
111
+ color: active ? theme.colors.primary : theme.colors.mutedForeground,
112
+ fontWeight: active ? theme.typography.weightBold : theme.typography.weightRegular,
113
+ fontSize: theme.typography.sizeBody,
114
+ }, children: label }) }));
115
+ }
116
+ const styles = StyleSheet.create({
117
+ fill: { flex: 1 },
118
+ center: { flex: 1, alignItems: 'center', justifyContent: 'center' },
119
+ header: { borderBottomWidth: StyleSheet.hairlineWidth },
120
+ tabs: { flexDirection: 'row', marginTop: 6 },
121
+ });
122
+ //# sourceMappingURL=ChatlyWidget.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChatlyWidget.js","sourceRoot":"","sources":["../src/ChatlyWidget.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Money on a card, restated for the published package.
3
+ *
4
+ * ── Why this is a copy and not an import ───────────────────────────────
5
+ *
6
+ * The canonical implementation is `packages/shared/src/widget-blocks/money.ts`
7
+ * and this file is deliberately identical in behaviour. `@livechat/shared` is
8
+ * `private: true` — it is the monorepo's internal package with a hundred
9
+ * export paths — so a published npm package cannot depend on it. The same
10
+ * reason `client/types.ts` restates the realtime types rather than importing
11
+ * them.
12
+ *
13
+ * A copy is a drift risk, so it is pinned rather than trusted:
14
+ * `money.parity.spec.ts` imports BOTH this and the shared original and
15
+ * asserts they agree over a currency table that includes the cases a
16
+ * hand-rolled version gets wrong. `check-block-field-parity.mjs` knows about
17
+ * the second `Intl.NumberFormat` by name, with that spec as the reason.
18
+ *
19
+ * ── Minor units, never a float ─────────────────────────────────────────
20
+ *
21
+ * `amount` is an integer count of the currency's smallest unit: 4820 is
22
+ * $48.20, 4820 is also ¥4,820, and 4820 is 4.820 KWD.
23
+ *
24
+ * The DIVISOR IS NOT 100. Three currencies have no minor unit (JPY, KRW, VND)
25
+ * and four have three digits (KWD, BHD, JOD, OMR), so `(amount / 100)`
26
+ * renders ¥4,820 as "¥48" and 4.820 KWD as "48.200 KWD" — wrong by two orders
27
+ * of magnitude in opposite directions, and perfect in USD, which is why it
28
+ * would ship. The digit count is read off the formatter, so a currency added
29
+ * to CLDR after this was written is right with no table here.
30
+ *
31
+ * React Native ships a full ICU on iOS and, since 0.73 with Hermes
32
+ * `intl` enabled, on Android too. The `catch` below is what covers an engine
33
+ * without it: a card with an unrecognised currency still shows a price rather
34
+ * than taking the thread's render down.
35
+ */
36
+ /** A price on a card. `amount` and `compareAt` are both MINOR units. */
37
+ export interface Money {
38
+ readonly amount: number;
39
+ /** ISO 4217, upper case. */
40
+ readonly currency: string;
41
+ /** The was-price. Rendered only when above `amount`. */
42
+ readonly compareAt?: number;
43
+ }
44
+ /** Read a price off a stored card, or null. Refuses what cannot be drawn. */
45
+ export declare function readMoney(raw: unknown): Money | null;
46
+ /** The locale-free rendition, used as the fallback and for accessibility text. */
47
+ export declare function moneyToPlainText(money: Money): string;
48
+ /**
49
+ * Format one amount in the DEVICE's locale.
50
+ *
51
+ * `locale` undefined means "whatever this device is set to", which is the
52
+ * right default: the app runs on the shopper's phone and a German shopper
53
+ * reads `48,20 $`.
54
+ */
55
+ export declare function formatMoney(money: Money, locale?: string): string;
56
+ //# sourceMappingURL=money.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"money.d.ts","sourceRoot":"","sources":["../../src/blocks/money.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,wEAAwE;AACxE,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,4BAA4B;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,wDAAwD;IACxD,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAOD,6EAA6E;AAC7E,wBAAgB,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG,KAAK,GAAG,IAAI,CAepD;AAOD,kFAAkF;AAClF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,CAErD;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAUjE"}