@repzo/widget-react-native 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +482 -0
- package/lib/commonjs/agent-ui-blocks.js +159 -0
- package/lib/commonjs/agent-ui-blocks.js.map +1 -0
- package/lib/commonjs/api/client.js +267 -0
- package/lib/commonjs/api/client.js.map +1 -0
- package/lib/commonjs/api/realtime.js +193 -0
- package/lib/commonjs/api/realtime.js.map +1 -0
- package/lib/commonjs/api/sse-parser.js +58 -0
- package/lib/commonjs/api/sse-parser.js.map +1 -0
- package/lib/commonjs/controller.js +23 -0
- package/lib/commonjs/controller.js.map +1 -0
- package/lib/commonjs/device-id.js +75 -0
- package/lib/commonjs/device-id.js.map +1 -0
- package/lib/commonjs/events.js +49 -0
- package/lib/commonjs/events.js.map +1 -0
- package/lib/commonjs/i18n.js +106 -0
- package/lib/commonjs/i18n.js.map +1 -0
- package/lib/commonjs/index.js +98 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/locales.js +85 -0
- package/lib/commonjs/locales.js.map +1 -0
- package/lib/commonjs/package.json +1 -0
- package/lib/commonjs/push/push-notifications.js +208 -0
- package/lib/commonjs/push/push-notifications.js.map +1 -0
- package/lib/commonjs/state/use-widget-state.js +23 -0
- package/lib/commonjs/state/use-widget-state.js.map +1 -0
- package/lib/commonjs/state/widget-store.js +1682 -0
- package/lib/commonjs/state/widget-store.js.map +1 -0
- package/lib/commonjs/storage.js +147 -0
- package/lib/commonjs/storage.js.map +1 -0
- package/lib/commonjs/types.js +44 -0
- package/lib/commonjs/types.js.map +1 -0
- package/lib/commonjs/ui/WidgetProvider.js +404 -0
- package/lib/commonjs/ui/WidgetProvider.js.map +1 -0
- package/lib/commonjs/ui/components/AgentUiBlocks.js +864 -0
- package/lib/commonjs/ui/components/AgentUiBlocks.js.map +1 -0
- package/lib/commonjs/ui/components/Avatar.js +76 -0
- package/lib/commonjs/ui/components/Avatar.js.map +1 -0
- package/lib/commonjs/ui/components/ConversationRow.js +155 -0
- package/lib/commonjs/ui/components/ConversationRow.js.map +1 -0
- package/lib/commonjs/ui/components/ErrorBoundary.js +44 -0
- package/lib/commonjs/ui/components/ErrorBoundary.js.map +1 -0
- package/lib/commonjs/ui/components/Gradient.js +168 -0
- package/lib/commonjs/ui/components/Gradient.js.map +1 -0
- package/lib/commonjs/ui/components/Launcher.js +125 -0
- package/lib/commonjs/ui/components/Launcher.js.map +1 -0
- package/lib/commonjs/ui/components/Markdown.js +257 -0
- package/lib/commonjs/ui/components/Markdown.js.map +1 -0
- package/lib/commonjs/ui/components/OutboundMessageCard.js +157 -0
- package/lib/commonjs/ui/components/OutboundMessageCard.js.map +1 -0
- package/lib/commonjs/ui/components/WidgetPanel.js +131 -0
- package/lib/commonjs/ui/components/WidgetPanel.js.map +1 -0
- package/lib/commonjs/ui/components/icons.js +383 -0
- package/lib/commonjs/ui/components/icons.js.map +1 -0
- package/lib/commonjs/ui/hooks/use-keyboard-overlap.js +113 -0
- package/lib/commonjs/ui/hooks/use-keyboard-overlap.js.map +1 -0
- package/lib/commonjs/ui/hooks/use-reduce-motion.js +38 -0
- package/lib/commonjs/ui/hooks/use-reduce-motion.js.map +1 -0
- package/lib/commonjs/ui/hooks/use-widget-insets.js +41 -0
- package/lib/commonjs/ui/hooks/use-widget-insets.js.map +1 -0
- package/lib/commonjs/ui/screens/chat/ChatView.js +590 -0
- package/lib/commonjs/ui/screens/chat/ChatView.js.map +1 -0
- package/lib/commonjs/ui/screens/chat/ChatView.styles.js +362 -0
- package/lib/commonjs/ui/screens/chat/ChatView.styles.js.map +1 -0
- package/lib/commonjs/ui/screens/chat/ChatView.types.js +6 -0
- package/lib/commonjs/ui/screens/chat/ChatView.types.js.map +1 -0
- package/lib/commonjs/ui/screens/conversations/ConversationsList.js +150 -0
- package/lib/commonjs/ui/screens/conversations/ConversationsList.js.map +1 -0
- package/lib/commonjs/ui/screens/conversations/ConversationsList.styles.js +118 -0
- package/lib/commonjs/ui/screens/conversations/ConversationsList.styles.js.map +1 -0
- package/lib/commonjs/ui/screens/conversations/ConversationsList.types.js +6 -0
- package/lib/commonjs/ui/screens/conversations/ConversationsList.types.js.map +1 -0
- package/lib/commonjs/ui/screens/home/HomeView.js +336 -0
- package/lib/commonjs/ui/screens/home/HomeView.js.map +1 -0
- package/lib/commonjs/ui/screens/home/HomeView.styles.js +245 -0
- package/lib/commonjs/ui/screens/home/HomeView.styles.js.map +1 -0
- package/lib/commonjs/ui/screens/home/HomeView.types.js +6 -0
- package/lib/commonjs/ui/screens/home/HomeView.types.js.map +1 -0
- package/lib/commonjs/ui/screens/home/greeting.js +49 -0
- package/lib/commonjs/ui/screens/home/greeting.js.map +1 -0
- package/lib/commonjs/ui/screens/pre-chat/PreChatForm.js +229 -0
- package/lib/commonjs/ui/screens/pre-chat/PreChatForm.js.map +1 -0
- package/lib/commonjs/ui/screens/pre-chat/PreChatForm.styles.js +125 -0
- package/lib/commonjs/ui/screens/pre-chat/PreChatForm.styles.js.map +1 -0
- package/lib/commonjs/ui/screens/pre-chat/PreChatForm.types.js +6 -0
- package/lib/commonjs/ui/screens/pre-chat/PreChatForm.types.js.map +1 -0
- package/lib/commonjs/ui/styles/global.js +55 -0
- package/lib/commonjs/ui/styles/global.js.map +1 -0
- package/lib/commonjs/ui/styles/theme.js +148 -0
- package/lib/commonjs/ui/styles/theme.js.map +1 -0
- package/lib/commonjs/ui/utils/conversations.js +125 -0
- package/lib/commonjs/ui/utils/conversations.js.map +1 -0
- package/lib/commonjs/ui/utils/html.js +44 -0
- package/lib/commonjs/ui/utils/html.js.map +1 -0
- package/lib/commonjs/ui/utils/native-gradient.js +65 -0
- package/lib/commonjs/ui/utils/native-gradient.js.map +1 -0
- package/lib/commonjs/ui/utils/rtl.js +56 -0
- package/lib/commonjs/ui/utils/rtl.js.map +1 -0
- package/lib/commonjs/ui/utils/safe-url.js +67 -0
- package/lib/commonjs/ui/utils/safe-url.js.map +1 -0
- package/lib/module/agent-ui-blocks.js +152 -0
- package/lib/module/agent-ui-blocks.js.map +1 -0
- package/lib/module/api/client.js +261 -0
- package/lib/module/api/client.js.map +1 -0
- package/lib/module/api/realtime.js +189 -0
- package/lib/module/api/realtime.js.map +1 -0
- package/lib/module/api/sse-parser.js +53 -0
- package/lib/module/api/sse-parser.js.map +1 -0
- package/lib/module/controller.js +19 -0
- package/lib/module/controller.js.map +1 -0
- package/lib/module/device-id.js +69 -0
- package/lib/module/device-id.js.map +1 -0
- package/lib/module/events.js +44 -0
- package/lib/module/events.js.map +1 -0
- package/lib/module/i18n.js +99 -0
- package/lib/module/i18n.js.map +1 -0
- package/lib/module/index.js +55 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/locales.js +80 -0
- package/lib/module/locales.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/push/push-notifications.js +204 -0
- package/lib/module/push/push-notifications.js.map +1 -0
- package/lib/module/state/use-widget-state.js +18 -0
- package/lib/module/state/use-widget-state.js.map +1 -0
- package/lib/module/state/widget-store.js +1677 -0
- package/lib/module/state/widget-store.js.map +1 -0
- package/lib/module/storage.js +141 -0
- package/lib/module/storage.js.map +1 -0
- package/lib/module/types.js +40 -0
- package/lib/module/types.js.map +1 -0
- package/lib/module/ui/WidgetProvider.js +400 -0
- package/lib/module/ui/WidgetProvider.js.map +1 -0
- package/lib/module/ui/components/AgentUiBlocks.js +857 -0
- package/lib/module/ui/components/AgentUiBlocks.js.map +1 -0
- package/lib/module/ui/components/Avatar.js +71 -0
- package/lib/module/ui/components/Avatar.js.map +1 -0
- package/lib/module/ui/components/ConversationRow.js +150 -0
- package/lib/module/ui/components/ConversationRow.js.map +1 -0
- package/lib/module/ui/components/ErrorBoundary.js +39 -0
- package/lib/module/ui/components/ErrorBoundary.js.map +1 -0
- package/lib/module/ui/components/Gradient.js +165 -0
- package/lib/module/ui/components/Gradient.js.map +1 -0
- package/lib/module/ui/components/Launcher.js +121 -0
- package/lib/module/ui/components/Launcher.js.map +1 -0
- package/lib/module/ui/components/Markdown.js +253 -0
- package/lib/module/ui/components/Markdown.js.map +1 -0
- package/lib/module/ui/components/OutboundMessageCard.js +153 -0
- package/lib/module/ui/components/OutboundMessageCard.js.map +1 -0
- package/lib/module/ui/components/WidgetPanel.js +127 -0
- package/lib/module/ui/components/WidgetPanel.js.map +1 -0
- package/lib/module/ui/components/icons.js +370 -0
- package/lib/module/ui/components/icons.js.map +1 -0
- package/lib/module/ui/hooks/use-keyboard-overlap.js +109 -0
- package/lib/module/ui/hooks/use-keyboard-overlap.js.map +1 -0
- package/lib/module/ui/hooks/use-reduce-motion.js +34 -0
- package/lib/module/ui/hooks/use-reduce-motion.js.map +1 -0
- package/lib/module/ui/hooks/use-widget-insets.js +37 -0
- package/lib/module/ui/hooks/use-widget-insets.js.map +1 -0
- package/lib/module/ui/screens/chat/ChatView.js +586 -0
- package/lib/module/ui/screens/chat/ChatView.js.map +1 -0
- package/lib/module/ui/screens/chat/ChatView.styles.js +358 -0
- package/lib/module/ui/screens/chat/ChatView.styles.js.map +1 -0
- package/lib/module/ui/screens/chat/ChatView.types.js +4 -0
- package/lib/module/ui/screens/chat/ChatView.types.js.map +1 -0
- package/lib/module/ui/screens/conversations/ConversationsList.js +146 -0
- package/lib/module/ui/screens/conversations/ConversationsList.js.map +1 -0
- package/lib/module/ui/screens/conversations/ConversationsList.styles.js +114 -0
- package/lib/module/ui/screens/conversations/ConversationsList.styles.js.map +1 -0
- package/lib/module/ui/screens/conversations/ConversationsList.types.js +4 -0
- package/lib/module/ui/screens/conversations/ConversationsList.types.js.map +1 -0
- package/lib/module/ui/screens/home/HomeView.js +332 -0
- package/lib/module/ui/screens/home/HomeView.js.map +1 -0
- package/lib/module/ui/screens/home/HomeView.styles.js +242 -0
- package/lib/module/ui/screens/home/HomeView.styles.js.map +1 -0
- package/lib/module/ui/screens/home/HomeView.types.js +4 -0
- package/lib/module/ui/screens/home/HomeView.types.js.map +1 -0
- package/lib/module/ui/screens/home/greeting.js +44 -0
- package/lib/module/ui/screens/home/greeting.js.map +1 -0
- package/lib/module/ui/screens/pre-chat/PreChatForm.js +225 -0
- package/lib/module/ui/screens/pre-chat/PreChatForm.js.map +1 -0
- package/lib/module/ui/screens/pre-chat/PreChatForm.styles.js +121 -0
- package/lib/module/ui/screens/pre-chat/PreChatForm.styles.js.map +1 -0
- package/lib/module/ui/screens/pre-chat/PreChatForm.types.js +4 -0
- package/lib/module/ui/screens/pre-chat/PreChatForm.types.js.map +1 -0
- package/lib/module/ui/styles/global.js +51 -0
- package/lib/module/ui/styles/global.js.map +1 -0
- package/lib/module/ui/styles/theme.js +137 -0
- package/lib/module/ui/styles/theme.js.map +1 -0
- package/lib/module/ui/utils/conversations.js +115 -0
- package/lib/module/ui/utils/conversations.js.map +1 -0
- package/lib/module/ui/utils/html.js +39 -0
- package/lib/module/ui/utils/html.js.map +1 -0
- package/lib/module/ui/utils/native-gradient.js +60 -0
- package/lib/module/ui/utils/native-gradient.js.map +1 -0
- package/lib/module/ui/utils/rtl.js +49 -0
- package/lib/module/ui/utils/rtl.js.map +1 -0
- package/lib/module/ui/utils/safe-url.js +59 -0
- package/lib/module/ui/utils/safe-url.js.map +1 -0
- package/lib/typescript/commonjs/agent-ui-blocks.d.ts +20 -0
- package/lib/typescript/commonjs/agent-ui-blocks.d.ts.map +1 -0
- package/lib/typescript/commonjs/api/client.d.ts +115 -0
- package/lib/typescript/commonjs/api/client.d.ts.map +1 -0
- package/lib/typescript/commonjs/api/realtime.d.ts +39 -0
- package/lib/typescript/commonjs/api/realtime.d.ts.map +1 -0
- package/lib/typescript/commonjs/api/sse-parser.d.ts +13 -0
- package/lib/typescript/commonjs/api/sse-parser.d.ts.map +1 -0
- package/lib/typescript/commonjs/controller.d.ts +15 -0
- package/lib/typescript/commonjs/controller.d.ts.map +1 -0
- package/lib/typescript/commonjs/device-id.d.ts +15 -0
- package/lib/typescript/commonjs/device-id.d.ts.map +1 -0
- package/lib/typescript/commonjs/events.d.ts +41 -0
- package/lib/typescript/commonjs/events.d.ts.map +1 -0
- package/lib/typescript/commonjs/i18n.d.ts +78 -0
- package/lib/typescript/commonjs/i18n.d.ts.map +1 -0
- package/lib/typescript/commonjs/index.d.ts +103 -0
- package/lib/typescript/commonjs/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/locales.d.ts +18 -0
- package/lib/typescript/commonjs/locales.d.ts.map +1 -0
- package/lib/typescript/commonjs/package.json +1 -0
- package/lib/typescript/commonjs/push/push-notifications.d.ts +71 -0
- package/lib/typescript/commonjs/push/push-notifications.d.ts.map +1 -0
- package/lib/typescript/commonjs/state/use-widget-state.d.ts +10 -0
- package/lib/typescript/commonjs/state/use-widget-state.d.ts.map +1 -0
- package/lib/typescript/commonjs/state/widget-store.d.ts +227 -0
- package/lib/typescript/commonjs/state/widget-store.d.ts.map +1 -0
- package/lib/typescript/commonjs/storage.d.ts +42 -0
- package/lib/typescript/commonjs/storage.d.ts.map +1 -0
- package/lib/typescript/commonjs/types.d.ts +391 -0
- package/lib/typescript/commonjs/types.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/WidgetProvider.d.ts +15 -0
- package/lib/typescript/commonjs/ui/WidgetProvider.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/AgentUiBlocks.d.ts +27 -0
- package/lib/typescript/commonjs/ui/components/AgentUiBlocks.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/Avatar.d.ts +19 -0
- package/lib/typescript/commonjs/ui/components/Avatar.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/ConversationRow.d.ts +26 -0
- package/lib/typescript/commonjs/ui/components/ConversationRow.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/ErrorBoundary.d.ts +27 -0
- package/lib/typescript/commonjs/ui/components/ErrorBoundary.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/Gradient.d.ts +33 -0
- package/lib/typescript/commonjs/ui/components/Gradient.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/Launcher.d.ts +18 -0
- package/lib/typescript/commonjs/ui/components/Launcher.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/Markdown.d.ts +19 -0
- package/lib/typescript/commonjs/ui/components/Markdown.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/OutboundMessageCard.d.ts +20 -0
- package/lib/typescript/commonjs/ui/components/OutboundMessageCard.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/WidgetPanel.d.ts +26 -0
- package/lib/typescript/commonjs/ui/components/WidgetPanel.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/icons.d.ts +38 -0
- package/lib/typescript/commonjs/ui/components/icons.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/hooks/use-keyboard-overlap.d.ts +33 -0
- package/lib/typescript/commonjs/ui/hooks/use-keyboard-overlap.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/hooks/use-reduce-motion.d.ts +11 -0
- package/lib/typescript/commonjs/ui/hooks/use-reduce-motion.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/hooks/use-widget-insets.d.ts +16 -0
- package/lib/typescript/commonjs/ui/hooks/use-widget-insets.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/screens/chat/ChatView.d.ts +11 -0
- package/lib/typescript/commonjs/ui/screens/chat/ChatView.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/screens/chat/ChatView.styles.d.ts +349 -0
- package/lib/typescript/commonjs/ui/screens/chat/ChatView.styles.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/screens/chat/ChatView.types.d.ts +48 -0
- package/lib/typescript/commonjs/ui/screens/chat/ChatView.types.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/screens/conversations/ConversationsList.d.ts +10 -0
- package/lib/typescript/commonjs/ui/screens/conversations/ConversationsList.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/screens/conversations/ConversationsList.styles.d.ts +113 -0
- package/lib/typescript/commonjs/ui/screens/conversations/ConversationsList.styles.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/screens/conversations/ConversationsList.types.d.ts +31 -0
- package/lib/typescript/commonjs/ui/screens/conversations/ConversationsList.types.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/screens/home/HomeView.d.ts +17 -0
- package/lib/typescript/commonjs/ui/screens/home/HomeView.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/screens/home/HomeView.styles.d.ts +227 -0
- package/lib/typescript/commonjs/ui/screens/home/HomeView.styles.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/screens/home/HomeView.types.d.ts +40 -0
- package/lib/typescript/commonjs/ui/screens/home/HomeView.types.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/screens/home/greeting.d.ts +19 -0
- package/lib/typescript/commonjs/ui/screens/home/greeting.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/screens/pre-chat/PreChatForm.d.ts +7 -0
- package/lib/typescript/commonjs/ui/screens/pre-chat/PreChatForm.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/screens/pre-chat/PreChatForm.styles.d.ts +115 -0
- package/lib/typescript/commonjs/ui/screens/pre-chat/PreChatForm.styles.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/screens/pre-chat/PreChatForm.types.d.ts +20 -0
- package/lib/typescript/commonjs/ui/screens/pre-chat/PreChatForm.types.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/styles/global.d.ts +46 -0
- package/lib/typescript/commonjs/ui/styles/global.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/styles/theme.d.ts +103 -0
- package/lib/typescript/commonjs/ui/styles/theme.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/utils/conversations.d.ts +41 -0
- package/lib/typescript/commonjs/ui/utils/conversations.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/utils/html.d.ts +10 -0
- package/lib/typescript/commonjs/ui/utils/html.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/utils/native-gradient.d.ts +61 -0
- package/lib/typescript/commonjs/ui/utils/native-gradient.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/utils/rtl.d.ts +33 -0
- package/lib/typescript/commonjs/ui/utils/rtl.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/utils/safe-url.d.ts +21 -0
- package/lib/typescript/commonjs/ui/utils/safe-url.d.ts.map +1 -0
- package/lib/typescript/module/agent-ui-blocks.d.ts +20 -0
- package/lib/typescript/module/agent-ui-blocks.d.ts.map +1 -0
- package/lib/typescript/module/api/client.d.ts +115 -0
- package/lib/typescript/module/api/client.d.ts.map +1 -0
- package/lib/typescript/module/api/realtime.d.ts +39 -0
- package/lib/typescript/module/api/realtime.d.ts.map +1 -0
- package/lib/typescript/module/api/sse-parser.d.ts +13 -0
- package/lib/typescript/module/api/sse-parser.d.ts.map +1 -0
- package/lib/typescript/module/controller.d.ts +15 -0
- package/lib/typescript/module/controller.d.ts.map +1 -0
- package/lib/typescript/module/device-id.d.ts +15 -0
- package/lib/typescript/module/device-id.d.ts.map +1 -0
- package/lib/typescript/module/events.d.ts +41 -0
- package/lib/typescript/module/events.d.ts.map +1 -0
- package/lib/typescript/module/i18n.d.ts +78 -0
- package/lib/typescript/module/i18n.d.ts.map +1 -0
- package/lib/typescript/module/index.d.ts +103 -0
- package/lib/typescript/module/index.d.ts.map +1 -0
- package/lib/typescript/module/locales.d.ts +18 -0
- package/lib/typescript/module/locales.d.ts.map +1 -0
- package/lib/typescript/module/package.json +1 -0
- package/lib/typescript/module/push/push-notifications.d.ts +71 -0
- package/lib/typescript/module/push/push-notifications.d.ts.map +1 -0
- package/lib/typescript/module/state/use-widget-state.d.ts +10 -0
- package/lib/typescript/module/state/use-widget-state.d.ts.map +1 -0
- package/lib/typescript/module/state/widget-store.d.ts +227 -0
- package/lib/typescript/module/state/widget-store.d.ts.map +1 -0
- package/lib/typescript/module/storage.d.ts +42 -0
- package/lib/typescript/module/storage.d.ts.map +1 -0
- package/lib/typescript/module/types.d.ts +391 -0
- package/lib/typescript/module/types.d.ts.map +1 -0
- package/lib/typescript/module/ui/WidgetProvider.d.ts +15 -0
- package/lib/typescript/module/ui/WidgetProvider.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/AgentUiBlocks.d.ts +27 -0
- package/lib/typescript/module/ui/components/AgentUiBlocks.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/Avatar.d.ts +19 -0
- package/lib/typescript/module/ui/components/Avatar.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/ConversationRow.d.ts +26 -0
- package/lib/typescript/module/ui/components/ConversationRow.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/ErrorBoundary.d.ts +27 -0
- package/lib/typescript/module/ui/components/ErrorBoundary.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/Gradient.d.ts +33 -0
- package/lib/typescript/module/ui/components/Gradient.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/Launcher.d.ts +18 -0
- package/lib/typescript/module/ui/components/Launcher.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/Markdown.d.ts +19 -0
- package/lib/typescript/module/ui/components/Markdown.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/OutboundMessageCard.d.ts +20 -0
- package/lib/typescript/module/ui/components/OutboundMessageCard.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/WidgetPanel.d.ts +26 -0
- package/lib/typescript/module/ui/components/WidgetPanel.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/icons.d.ts +38 -0
- package/lib/typescript/module/ui/components/icons.d.ts.map +1 -0
- package/lib/typescript/module/ui/hooks/use-keyboard-overlap.d.ts +33 -0
- package/lib/typescript/module/ui/hooks/use-keyboard-overlap.d.ts.map +1 -0
- package/lib/typescript/module/ui/hooks/use-reduce-motion.d.ts +11 -0
- package/lib/typescript/module/ui/hooks/use-reduce-motion.d.ts.map +1 -0
- package/lib/typescript/module/ui/hooks/use-widget-insets.d.ts +16 -0
- package/lib/typescript/module/ui/hooks/use-widget-insets.d.ts.map +1 -0
- package/lib/typescript/module/ui/screens/chat/ChatView.d.ts +11 -0
- package/lib/typescript/module/ui/screens/chat/ChatView.d.ts.map +1 -0
- package/lib/typescript/module/ui/screens/chat/ChatView.styles.d.ts +349 -0
- package/lib/typescript/module/ui/screens/chat/ChatView.styles.d.ts.map +1 -0
- package/lib/typescript/module/ui/screens/chat/ChatView.types.d.ts +48 -0
- package/lib/typescript/module/ui/screens/chat/ChatView.types.d.ts.map +1 -0
- package/lib/typescript/module/ui/screens/conversations/ConversationsList.d.ts +10 -0
- package/lib/typescript/module/ui/screens/conversations/ConversationsList.d.ts.map +1 -0
- package/lib/typescript/module/ui/screens/conversations/ConversationsList.styles.d.ts +113 -0
- package/lib/typescript/module/ui/screens/conversations/ConversationsList.styles.d.ts.map +1 -0
- package/lib/typescript/module/ui/screens/conversations/ConversationsList.types.d.ts +31 -0
- package/lib/typescript/module/ui/screens/conversations/ConversationsList.types.d.ts.map +1 -0
- package/lib/typescript/module/ui/screens/home/HomeView.d.ts +17 -0
- package/lib/typescript/module/ui/screens/home/HomeView.d.ts.map +1 -0
- package/lib/typescript/module/ui/screens/home/HomeView.styles.d.ts +227 -0
- package/lib/typescript/module/ui/screens/home/HomeView.styles.d.ts.map +1 -0
- package/lib/typescript/module/ui/screens/home/HomeView.types.d.ts +40 -0
- package/lib/typescript/module/ui/screens/home/HomeView.types.d.ts.map +1 -0
- package/lib/typescript/module/ui/screens/home/greeting.d.ts +19 -0
- package/lib/typescript/module/ui/screens/home/greeting.d.ts.map +1 -0
- package/lib/typescript/module/ui/screens/pre-chat/PreChatForm.d.ts +7 -0
- package/lib/typescript/module/ui/screens/pre-chat/PreChatForm.d.ts.map +1 -0
- package/lib/typescript/module/ui/screens/pre-chat/PreChatForm.styles.d.ts +115 -0
- package/lib/typescript/module/ui/screens/pre-chat/PreChatForm.styles.d.ts.map +1 -0
- package/lib/typescript/module/ui/screens/pre-chat/PreChatForm.types.d.ts +20 -0
- package/lib/typescript/module/ui/screens/pre-chat/PreChatForm.types.d.ts.map +1 -0
- package/lib/typescript/module/ui/styles/global.d.ts +46 -0
- package/lib/typescript/module/ui/styles/global.d.ts.map +1 -0
- package/lib/typescript/module/ui/styles/theme.d.ts +103 -0
- package/lib/typescript/module/ui/styles/theme.d.ts.map +1 -0
- package/lib/typescript/module/ui/utils/conversations.d.ts +41 -0
- package/lib/typescript/module/ui/utils/conversations.d.ts.map +1 -0
- package/lib/typescript/module/ui/utils/html.d.ts +10 -0
- package/lib/typescript/module/ui/utils/html.d.ts.map +1 -0
- package/lib/typescript/module/ui/utils/native-gradient.d.ts +61 -0
- package/lib/typescript/module/ui/utils/native-gradient.d.ts.map +1 -0
- package/lib/typescript/module/ui/utils/rtl.d.ts +33 -0
- package/lib/typescript/module/ui/utils/rtl.d.ts.map +1 -0
- package/lib/typescript/module/ui/utils/safe-url.d.ts +21 -0
- package/lib/typescript/module/ui/utils/safe-url.d.ts.map +1 -0
- package/metro.js +40 -0
- package/package.json +116 -0
- package/src/agent-ui-blocks.ts +302 -0
- package/src/api/client.ts +332 -0
- package/src/api/realtime.ts +225 -0
- package/src/api/sse-parser.ts +51 -0
- package/src/controller.ts +20 -0
- package/src/device-id.ts +71 -0
- package/src/events.ts +74 -0
- package/src/i18n.ts +114 -0
- package/src/index.tsx +199 -0
- package/src/locales.ts +80 -0
- package/src/push/push-notifications.ts +254 -0
- package/src/state/use-widget-state.ts +20 -0
- package/src/state/widget-store.ts +1815 -0
- package/src/storage.ts +153 -0
- package/src/types.ts +445 -0
- package/src/ui/WidgetProvider.tsx +434 -0
- package/src/ui/components/AgentUiBlocks.tsx +912 -0
- package/src/ui/components/Avatar.tsx +86 -0
- package/src/ui/components/ConversationRow.tsx +163 -0
- package/src/ui/components/ErrorBoundary.tsx +49 -0
- package/src/ui/components/Gradient.tsx +165 -0
- package/src/ui/components/Launcher.tsx +128 -0
- package/src/ui/components/Markdown.tsx +291 -0
- package/src/ui/components/OutboundMessageCard.tsx +154 -0
- package/src/ui/components/WidgetPanel.tsx +133 -0
- package/src/ui/components/icons.tsx +315 -0
- package/src/ui/hooks/use-keyboard-overlap.ts +134 -0
- package/src/ui/hooks/use-reduce-motion.ts +39 -0
- package/src/ui/hooks/use-widget-insets.ts +44 -0
- package/src/ui/screens/chat/ChatView.styles.ts +357 -0
- package/src/ui/screens/chat/ChatView.tsx +690 -0
- package/src/ui/screens/chat/ChatView.types.ts +46 -0
- package/src/ui/screens/conversations/ConversationsList.styles.ts +111 -0
- package/src/ui/screens/conversations/ConversationsList.tsx +144 -0
- package/src/ui/screens/conversations/ConversationsList.types.ts +33 -0
- package/src/ui/screens/home/HomeView.styles.ts +246 -0
- package/src/ui/screens/home/HomeView.tsx +336 -0
- package/src/ui/screens/home/HomeView.types.ts +42 -0
- package/src/ui/screens/home/greeting.ts +50 -0
- package/src/ui/screens/pre-chat/PreChatForm.styles.ts +120 -0
- package/src/ui/screens/pre-chat/PreChatForm.tsx +221 -0
- package/src/ui/screens/pre-chat/PreChatForm.types.ts +22 -0
- package/src/ui/styles/global.ts +50 -0
- package/src/ui/styles/theme.ts +155 -0
- package/src/ui/utils/conversations.ts +122 -0
- package/src/ui/utils/html.ts +58 -0
- package/src/ui/utils/native-gradient.ts +60 -0
- package/src/ui/utils/rtl.ts +43 -0
- package/src/ui/utils/safe-url.ts +63 -0
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pre-chat form — collects visitor info before the first message.
|
|
3
|
+
* Port of `client/src/widget/components/PreChatForm.tsx`.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { useCallback, useRef, useState } from 'react';
|
|
7
|
+
import { Pressable, ScrollView, Text, TextInput, View } from 'react-native';
|
|
8
|
+
import type { LayoutChangeEvent, NativeScrollEvent, NativeSyntheticEvent } from 'react-native';
|
|
9
|
+
|
|
10
|
+
import { formatLabel } from '../../../i18n';
|
|
11
|
+
import { GradientBackground } from '../../components/Gradient';
|
|
12
|
+
import { ChevronIcon } from '../../components/icons';
|
|
13
|
+
import { globalStyles } from '../../styles/global';
|
|
14
|
+
import { contrastingTextColor, mixHex, palette, withAlpha } from '../../styles/theme';
|
|
15
|
+
import { forwardDirection } from '../../utils/rtl';
|
|
16
|
+
import { styles } from './PreChatForm.styles';
|
|
17
|
+
import type { PreChatFormProps } from './PreChatForm.types';
|
|
18
|
+
|
|
19
|
+
/** Breathing room kept under a focused field when it is scrolled into view. */
|
|
20
|
+
const FIELD_GUTTER = 16;
|
|
21
|
+
|
|
22
|
+
export function PreChatForm({
|
|
23
|
+
fields,
|
|
24
|
+
color,
|
|
25
|
+
labels,
|
|
26
|
+
onSubmit,
|
|
27
|
+
onSkip,
|
|
28
|
+
onClose,
|
|
29
|
+
}: PreChatFormProps) {
|
|
30
|
+
const [values, setValues] = useState<Record<string, string>>({});
|
|
31
|
+
const [errors, setErrors] = useState<Record<string, string>>({});
|
|
32
|
+
|
|
33
|
+
const scrollRef = useRef<ScrollView>(null);
|
|
34
|
+
const scrollOffset = useRef(0);
|
|
35
|
+
const viewportHeight = useRef(0);
|
|
36
|
+
const fieldRefs = useRef<Record<string, View | null>>({});
|
|
37
|
+
const focusedField = useRef<string | null>(null);
|
|
38
|
+
|
|
39
|
+
// The keyboard shortens the form instead of scrolling it, so a field low in
|
|
40
|
+
// the list ends up behind it. Once the viewport has shrunk, lift the focused
|
|
41
|
+
// field back above the fold. Both edges are measured the same way, so the
|
|
42
|
+
// offset a modal adds to either cancels out, and RN folds the scroll position
|
|
43
|
+
// into the field's own measurement.
|
|
44
|
+
const revealFocusedField = useCallback(() => {
|
|
45
|
+
const name = focusedField.current;
|
|
46
|
+
const field = name ? fieldRefs.current[name] : null;
|
|
47
|
+
const viewport = scrollRef.current?.getNativeScrollRef();
|
|
48
|
+
if (!field || !viewport) return;
|
|
49
|
+
|
|
50
|
+
viewport.measureInWindow((_vx, viewportY, _vw, height) => {
|
|
51
|
+
field.measureInWindow((_fx, fieldY, _fw, fieldHeight) => {
|
|
52
|
+
const hidden = fieldY + fieldHeight + FIELD_GUTTER - (viewportY + height);
|
|
53
|
+
if (hidden <= 0) return;
|
|
54
|
+
scrollRef.current?.scrollTo({ y: scrollOffset.current + hidden, animated: false });
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
}, []);
|
|
58
|
+
|
|
59
|
+
const handleViewportLayout = useCallback(
|
|
60
|
+
(event: LayoutChangeEvent) => {
|
|
61
|
+
const { height } = event.nativeEvent.layout;
|
|
62
|
+
const shrank = viewportHeight.current - height > 1;
|
|
63
|
+
viewportHeight.current = height;
|
|
64
|
+
if (shrank) revealFocusedField();
|
|
65
|
+
},
|
|
66
|
+
[revealFocusedField]
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
const handleScroll = useCallback((event: NativeSyntheticEvent<NativeScrollEvent>) => {
|
|
70
|
+
scrollOffset.current = event.nativeEvent.contentOffset.y;
|
|
71
|
+
}, []);
|
|
72
|
+
|
|
73
|
+
const hasRequired = fields.some((field) => field.required);
|
|
74
|
+
|
|
75
|
+
const handleSubmit = () => {
|
|
76
|
+
const nextErrors: Record<string, string> = {};
|
|
77
|
+
for (const field of fields) {
|
|
78
|
+
const value = values[field.name]?.trim() || '';
|
|
79
|
+
if (field.required && !value) {
|
|
80
|
+
nextErrors[field.name] = formatLabel(labels.fieldRequired, { field: field.label });
|
|
81
|
+
}
|
|
82
|
+
if (field.type === 'email' && value && !value.includes('@')) {
|
|
83
|
+
nextErrors[field.name] = labels.invalidEmail;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (Object.keys(nextErrors).length > 0) {
|
|
88
|
+
setErrors(nextErrors);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
onSubmit(values);
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const headerTextColor = contrastingTextColor(color);
|
|
95
|
+
|
|
96
|
+
return (
|
|
97
|
+
<View style={globalStyles.screen}>
|
|
98
|
+
{/* The shared panel header used to sit here with nothing in it; the
|
|
99
|
+
form's own title fills that space instead. */}
|
|
100
|
+
<GradientBackground colors={[color, mixHex(color, '#000000', 0.16)]} style={styles.header}>
|
|
101
|
+
<View style={styles.headerCopy}>
|
|
102
|
+
<Text style={[styles.headerTitle, { color: headerTextColor }]}>{labels.title}</Text>
|
|
103
|
+
<Text
|
|
104
|
+
style={[styles.headerSubtitle, { color: withAlpha(headerTextColor, 0.75) }]}
|
|
105
|
+
numberOfLines={2}>
|
|
106
|
+
{labels.subtitle}
|
|
107
|
+
</Text>
|
|
108
|
+
</View>
|
|
109
|
+
<Pressable
|
|
110
|
+
onPress={onClose}
|
|
111
|
+
accessibilityRole="button"
|
|
112
|
+
accessibilityLabel={labels.close}
|
|
113
|
+
hitSlop={12}
|
|
114
|
+
style={({ pressed }) => [
|
|
115
|
+
globalStyles.iconButton,
|
|
116
|
+
{ backgroundColor: withAlpha(headerTextColor, 0.16) },
|
|
117
|
+
pressed && globalStyles.pressed,
|
|
118
|
+
]}>
|
|
119
|
+
<ChevronIcon size={20} direction="down" color={headerTextColor} />
|
|
120
|
+
</Pressable>
|
|
121
|
+
</GradientBackground>
|
|
122
|
+
|
|
123
|
+
<ScrollView
|
|
124
|
+
ref={scrollRef}
|
|
125
|
+
style={globalStyles.fill}
|
|
126
|
+
contentContainerStyle={styles.content}
|
|
127
|
+
keyboardShouldPersistTaps="handled"
|
|
128
|
+
keyboardDismissMode="on-drag"
|
|
129
|
+
onLayout={handleViewportLayout}
|
|
130
|
+
onScroll={handleScroll}
|
|
131
|
+
scrollEventThrottle={16}>
|
|
132
|
+
<View style={globalStyles.fill}>
|
|
133
|
+
{fields.map((field) => (
|
|
134
|
+
<View
|
|
135
|
+
key={field.name}
|
|
136
|
+
ref={(node) => {
|
|
137
|
+
fieldRefs.current[field.name] = node;
|
|
138
|
+
}}
|
|
139
|
+
collapsable={false}
|
|
140
|
+
style={styles.field}>
|
|
141
|
+
<Text style={styles.label}>
|
|
142
|
+
{field.label}
|
|
143
|
+
{field.required ? <Text style={styles.required}> *</Text> : null}
|
|
144
|
+
</Text>
|
|
145
|
+
|
|
146
|
+
{field.type === 'select' ? (
|
|
147
|
+
<View style={styles.options}>
|
|
148
|
+
{(field.options ?? []).map((option) => {
|
|
149
|
+
const selected = values[field.name] === option;
|
|
150
|
+
return (
|
|
151
|
+
<Pressable
|
|
152
|
+
key={option}
|
|
153
|
+
onPress={() =>
|
|
154
|
+
setValues((current) => ({ ...current, [field.name]: option }))
|
|
155
|
+
}
|
|
156
|
+
accessibilityRole="button"
|
|
157
|
+
accessibilityState={{ selected }}
|
|
158
|
+
style={[
|
|
159
|
+
styles.option,
|
|
160
|
+
selected && { borderColor: color, backgroundColor: palette.surface },
|
|
161
|
+
]}>
|
|
162
|
+
<Text style={[styles.optionLabel, selected && { color }]}>{option}</Text>
|
|
163
|
+
{selected ? (
|
|
164
|
+
<ChevronIcon size={14} direction={forwardDirection()} color={color} />
|
|
165
|
+
) : null}
|
|
166
|
+
</Pressable>
|
|
167
|
+
);
|
|
168
|
+
})}
|
|
169
|
+
</View>
|
|
170
|
+
) : (
|
|
171
|
+
<TextInput
|
|
172
|
+
value={values[field.name] || ''}
|
|
173
|
+
onChangeText={(text) =>
|
|
174
|
+
setValues((current) => ({ ...current, [field.name]: text }))
|
|
175
|
+
}
|
|
176
|
+
placeholder={field.label}
|
|
177
|
+
placeholderTextColor={palette.textSubtle}
|
|
178
|
+
keyboardType={
|
|
179
|
+
field.type === 'email'
|
|
180
|
+
? 'email-address'
|
|
181
|
+
: field.type === 'phone'
|
|
182
|
+
? 'phone-pad'
|
|
183
|
+
: 'default'
|
|
184
|
+
}
|
|
185
|
+
autoCapitalize={field.type === 'email' ? 'none' : 'sentences'}
|
|
186
|
+
autoCorrect={field.type !== 'email'}
|
|
187
|
+
onFocus={() => {
|
|
188
|
+
focusedField.current = field.name;
|
|
189
|
+
revealFocusedField();
|
|
190
|
+
}}
|
|
191
|
+
onBlur={() => {
|
|
192
|
+
if (focusedField.current === field.name) focusedField.current = null;
|
|
193
|
+
}}
|
|
194
|
+
style={[styles.input, errors[field.name] ? styles.inputError : null]}
|
|
195
|
+
/>
|
|
196
|
+
)}
|
|
197
|
+
|
|
198
|
+
{errors[field.name] ? (
|
|
199
|
+
<Text style={styles.errorText}>{errors[field.name]}</Text>
|
|
200
|
+
) : null}
|
|
201
|
+
</View>
|
|
202
|
+
))}
|
|
203
|
+
</View>
|
|
204
|
+
|
|
205
|
+
<View style={styles.actions}>
|
|
206
|
+
{!hasRequired ? (
|
|
207
|
+
<Pressable onPress={onSkip} accessibilityRole="button" style={styles.skipButton}>
|
|
208
|
+
<Text style={styles.skipLabel}>{labels.skip}</Text>
|
|
209
|
+
</Pressable>
|
|
210
|
+
) : null}
|
|
211
|
+
<Pressable
|
|
212
|
+
onPress={handleSubmit}
|
|
213
|
+
accessibilityRole="button"
|
|
214
|
+
style={[styles.submitButton, { backgroundColor: color }]}>
|
|
215
|
+
<Text style={styles.submitLabel}>{labels.submit}</Text>
|
|
216
|
+
</Pressable>
|
|
217
|
+
</View>
|
|
218
|
+
</ScrollView>
|
|
219
|
+
</View>
|
|
220
|
+
);
|
|
221
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/** Props and label bundle for the pre-chat form. */
|
|
2
|
+
|
|
3
|
+
import type { PreChatField } from '../../../types';
|
|
4
|
+
|
|
5
|
+
export interface PreChatFormLabels {
|
|
6
|
+
title: string;
|
|
7
|
+
subtitle: string;
|
|
8
|
+
skip: string;
|
|
9
|
+
submit: string;
|
|
10
|
+
close: string;
|
|
11
|
+
fieldRequired: string;
|
|
12
|
+
invalidEmail: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface PreChatFormProps {
|
|
16
|
+
fields: PreChatField[];
|
|
17
|
+
color: string;
|
|
18
|
+
labels: PreChatFormLabels;
|
|
19
|
+
onSubmit: (data: Record<string, string>) => void;
|
|
20
|
+
onSkip: () => void;
|
|
21
|
+
onClose: () => void;
|
|
22
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Style rules shared by more than one screen or component, so a fingertip-sized
|
|
3
|
+
* icon button or a hairline divider is written once and looks the same
|
|
4
|
+
* everywhere. Screens layer their own sheet on top:
|
|
5
|
+
* `style={[globalStyles.divider, styles.inset]}`.
|
|
6
|
+
*
|
|
7
|
+
* Only rules that are identical at every call site belong here. A style that is
|
|
8
|
+
* "almost the same" stays with its screen: hoisting it would either fork it
|
|
9
|
+
* into variants or quietly change one screen to match another.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { StyleSheet } from 'react-native';
|
|
13
|
+
|
|
14
|
+
import { palette, radius } from './theme';
|
|
15
|
+
|
|
16
|
+
export const globalStyles = StyleSheet.create({
|
|
17
|
+
/** Full-height white surface every screen starts from. */
|
|
18
|
+
screen: {
|
|
19
|
+
flex: 1,
|
|
20
|
+
backgroundColor: palette.white,
|
|
21
|
+
},
|
|
22
|
+
/** Grows to take whatever space its parent has left. */
|
|
23
|
+
fill: {
|
|
24
|
+
flex: 1,
|
|
25
|
+
},
|
|
26
|
+
/** Round icon target in a header bar, sized for a fingertip. */
|
|
27
|
+
iconButton: {
|
|
28
|
+
width: 34,
|
|
29
|
+
height: 34,
|
|
30
|
+
borderRadius: 17,
|
|
31
|
+
alignItems: 'center',
|
|
32
|
+
justifyContent: 'center',
|
|
33
|
+
},
|
|
34
|
+
/** Pressed feedback for icon buttons and text links. */
|
|
35
|
+
pressed: {
|
|
36
|
+
opacity: 0.6,
|
|
37
|
+
},
|
|
38
|
+
/** Hairline between list rows; the caller adds the start inset. */
|
|
39
|
+
divider: {
|
|
40
|
+
height: StyleSheet.hairlineWidth,
|
|
41
|
+
backgroundColor: palette.borderSoft,
|
|
42
|
+
},
|
|
43
|
+
/** Bordered white card that lists and previews sit in. */
|
|
44
|
+
card: {
|
|
45
|
+
borderRadius: radius.lg,
|
|
46
|
+
borderWidth: StyleSheet.hairlineWidth,
|
|
47
|
+
borderColor: palette.border,
|
|
48
|
+
backgroundColor: palette.white,
|
|
49
|
+
},
|
|
50
|
+
});
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Maps the widget's `GET /config` theming fields onto React Native styles.
|
|
3
|
+
*
|
|
4
|
+
* The palette mirrors the web widget so a workspace looks the same on both
|
|
5
|
+
* surfaces; type scales are nudged up because 13px body copy is unreadable on
|
|
6
|
+
* a phone (minimum readable body size is 15–16px).
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { WidgetConfig } from '../../types';
|
|
10
|
+
|
|
11
|
+
export const palette = {
|
|
12
|
+
white: '#ffffff',
|
|
13
|
+
ink: '#1a1a1a',
|
|
14
|
+
text: '#111827',
|
|
15
|
+
textMuted: '#6b7280',
|
|
16
|
+
textSubtle: '#9ca3af',
|
|
17
|
+
textFaint: '#b0b0b0',
|
|
18
|
+
border: '#e5e7eb',
|
|
19
|
+
borderSoft: '#f3f4f6',
|
|
20
|
+
surface: '#f9fafb',
|
|
21
|
+
surfaceAlt: '#f3f4f6',
|
|
22
|
+
danger: '#ef4444',
|
|
23
|
+
warningBg: '#fef3c7',
|
|
24
|
+
warningBorder: '#fde68a',
|
|
25
|
+
warningText: '#92400e',
|
|
26
|
+
warningIcon: '#d97706',
|
|
27
|
+
online: '#22c55e',
|
|
28
|
+
disabled: '#d1d5db',
|
|
29
|
+
} as const;
|
|
30
|
+
|
|
31
|
+
export const radius = {
|
|
32
|
+
sm: 8,
|
|
33
|
+
md: 10,
|
|
34
|
+
lg: 12,
|
|
35
|
+
xl: 14,
|
|
36
|
+
pill: 999,
|
|
37
|
+
} as const;
|
|
38
|
+
|
|
39
|
+
export const spacing = {
|
|
40
|
+
xs: 4,
|
|
41
|
+
sm: 8,
|
|
42
|
+
md: 12,
|
|
43
|
+
lg: 16,
|
|
44
|
+
xl: 20,
|
|
45
|
+
xxl: 24,
|
|
46
|
+
} as const;
|
|
47
|
+
|
|
48
|
+
/** Mobile type scale — one step larger than the web widget's. */
|
|
49
|
+
export const fontSize = {
|
|
50
|
+
micro: 10,
|
|
51
|
+
caption: 12,
|
|
52
|
+
meta: 13,
|
|
53
|
+
body: 15,
|
|
54
|
+
input: 16,
|
|
55
|
+
title: 17,
|
|
56
|
+
heading: 22,
|
|
57
|
+
display: 28,
|
|
58
|
+
} as const;
|
|
59
|
+
|
|
60
|
+
export interface WidgetTheme {
|
|
61
|
+
primaryColor: string;
|
|
62
|
+
position: 'left' | 'right';
|
|
63
|
+
isOnline: boolean;
|
|
64
|
+
/** Only set when the widget is outside business hours and has a message. */
|
|
65
|
+
offlineMessage?: string;
|
|
66
|
+
startConversationLabel: string;
|
|
67
|
+
replyTimeLabel: string;
|
|
68
|
+
allowNewConversations: boolean;
|
|
69
|
+
showPreviousConversations: boolean;
|
|
70
|
+
attachmentsEnabled: boolean;
|
|
71
|
+
preChatEnabled: boolean;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export const DEFAULT_PRIMARY_COLOR = '#0d9488';
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* `override` supplies a translation for the active locale when one exists.
|
|
78
|
+
* Without it the workspace's single-language config fields are used, which is
|
|
79
|
+
* correct for the default locale and wrong for every other one.
|
|
80
|
+
*/
|
|
81
|
+
// Copy the dashboard owns — the greeting, the card labels — is rendered
|
|
82
|
+
// exactly as the workspace typed it. Translating it is the dashboard's job.
|
|
83
|
+
export function buildTheme(config: WidgetConfig | null): WidgetTheme {
|
|
84
|
+
return {
|
|
85
|
+
primaryColor: config?.primaryColor || DEFAULT_PRIMARY_COLOR,
|
|
86
|
+
position: config?.position || 'right',
|
|
87
|
+
isOnline: config?.isOnline ?? true,
|
|
88
|
+
offlineMessage:
|
|
89
|
+
config && !config.isOnline && config.businessHoursEnabled && config.offlineMessage
|
|
90
|
+
? config.offlineMessage
|
|
91
|
+
: undefined,
|
|
92
|
+
startConversationLabel: config?.startConversationLabel || 'Send us a message',
|
|
93
|
+
replyTimeLabel: config?.replyTimeLabel || 'We usually reply within a few minutes',
|
|
94
|
+
allowNewConversations: config?.allowNewConversations ?? true,
|
|
95
|
+
showPreviousConversations: config?.showPreviousConversations ?? true,
|
|
96
|
+
attachmentsEnabled: config?.attachmentsEnabled ?? true,
|
|
97
|
+
preChatEnabled: config?.preChatEnabled ?? false,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** `#rrggbb` → `rgba(r, g, b, alpha)`; passes non-hex colors straight through. */
|
|
102
|
+
export function withAlpha(color: string, alpha: number): string {
|
|
103
|
+
const rgb = hexToRgb(color);
|
|
104
|
+
if (!rgb) return color;
|
|
105
|
+
return `rgba(${rgb[0]}, ${rgb[1]}, ${rgb[2]}, ${alpha})`;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export function hexToRgb(color: string): [number, number, number] | null {
|
|
109
|
+
const match = /^#?([a-f\d]{3}|[a-f\d]{6})$/i.exec(color.trim());
|
|
110
|
+
if (!match) return null;
|
|
111
|
+
let hex = match[1] as string;
|
|
112
|
+
if (hex.length === 3) {
|
|
113
|
+
hex = hex
|
|
114
|
+
.split('')
|
|
115
|
+
.map((char) => char + char)
|
|
116
|
+
.join('');
|
|
117
|
+
}
|
|
118
|
+
const value = parseInt(hex, 16);
|
|
119
|
+
return [(value >> 16) & 255, (value >> 8) & 255, value & 255];
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** Linear blend between two hex colors, used to fake gradients without a native lib. */
|
|
123
|
+
export function mixHex(from: string, to: string, ratio: number): string {
|
|
124
|
+
const a = hexToRgb(from);
|
|
125
|
+
const b = hexToRgb(to);
|
|
126
|
+
if (!a || !b) return from;
|
|
127
|
+
const channel = (index: number) => Math.round(a[index] + (b[index] - a[index]) * ratio);
|
|
128
|
+
return `rgb(${channel(0)}, ${channel(1)}, ${channel(2)})`;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** Pick readable foreground text for an arbitrary brand color. */
|
|
132
|
+
export function contrastingTextColor(background: string): string {
|
|
133
|
+
const rgb = hexToRgb(background);
|
|
134
|
+
if (!rgb) return palette.white;
|
|
135
|
+
const [r, g, b] = rgb;
|
|
136
|
+
const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
|
|
137
|
+
return luminance > 0.7 ? palette.ink : palette.white;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export const shadows = {
|
|
141
|
+
card: {
|
|
142
|
+
shadowColor: '#0f172a',
|
|
143
|
+
shadowOffset: { width: 0, height: 4 },
|
|
144
|
+
shadowOpacity: 0.08,
|
|
145
|
+
shadowRadius: 14,
|
|
146
|
+
elevation: 3,
|
|
147
|
+
},
|
|
148
|
+
floating: {
|
|
149
|
+
shadowColor: '#000000',
|
|
150
|
+
shadowOffset: { width: 0, height: 4 },
|
|
151
|
+
shadowOpacity: 0.15,
|
|
152
|
+
shadowRadius: 12,
|
|
153
|
+
elevation: 6,
|
|
154
|
+
},
|
|
155
|
+
} as const;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Conversation selectors and formatting shared by the Home and Messages
|
|
3
|
+
* spaces, so the two can never disagree about ordering or wording.
|
|
4
|
+
* Pure and free of React so they stay trivial to test.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { formatLabel } from '../../i18n';
|
|
8
|
+
import type { Conversation } from '../../types';
|
|
9
|
+
|
|
10
|
+
export interface TeamAgent {
|
|
11
|
+
name: string | null;
|
|
12
|
+
avatar: string | null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const conversationTime = (conversation: Conversation): number => {
|
|
16
|
+
const parsed = Date.parse(conversation.lastMessageAt || conversation.createdAt || '');
|
|
17
|
+
return Number.isNaN(parsed) ? 0 : parsed;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Newest first. The store patches a conversation in place when a message
|
|
22
|
+
* arrives and never reorders the array, so position is not recency — every
|
|
23
|
+
* surface that lists conversations has to sort for itself.
|
|
24
|
+
*/
|
|
25
|
+
export function sortByRecency(conversations: Conversation[]): Conversation[] {
|
|
26
|
+
return [...conversations].sort((a, b) => conversationTime(b) - conversationTime(a));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function pickRecentConversations(conversations: Conversation[], limit = 2): Conversation[] {
|
|
30
|
+
return sortByRecency(conversations).slice(0, limit);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Distinct agents the visitor has spoken to, most recent conversation first. */
|
|
34
|
+
export function pickTeamAgents(conversations: Conversation[], limit = 3): TeamAgent[] {
|
|
35
|
+
const seen = new Set<string>();
|
|
36
|
+
const agents: TeamAgent[] = [];
|
|
37
|
+
|
|
38
|
+
for (const conversation of sortByRecency(conversations)) {
|
|
39
|
+
const name = conversation.agentName?.trim();
|
|
40
|
+
if (!name) continue;
|
|
41
|
+
const key = name.toLowerCase();
|
|
42
|
+
if (seen.has(key)) continue;
|
|
43
|
+
seen.add(key);
|
|
44
|
+
agents.push({ name, avatar: conversation.agentAvatar });
|
|
45
|
+
if (agents.length >= limit) break;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return agents;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Every unit is a translated template, so `2h` can become `منذ ساعتين`. */
|
|
52
|
+
export interface RelativeTimeLabels {
|
|
53
|
+
justNow: string;
|
|
54
|
+
minutes: string;
|
|
55
|
+
hours: string;
|
|
56
|
+
days: string;
|
|
57
|
+
months: string;
|
|
58
|
+
years: string;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function formatRelativeTime(dateStr: string, labels: RelativeTimeLabels): string {
|
|
62
|
+
const date = new Date(dateStr);
|
|
63
|
+
const diffMs = Date.now() - date.getTime();
|
|
64
|
+
const diffMin = Math.floor(diffMs / 60000);
|
|
65
|
+
|
|
66
|
+
if (diffMin < 1) return labels.justNow;
|
|
67
|
+
if (diffMin < 60) return formatLabel(labels.minutes, { count: diffMin });
|
|
68
|
+
const diffHrs = Math.floor(diffMin / 60);
|
|
69
|
+
if (diffHrs < 24) return formatLabel(labels.hours, { count: diffHrs });
|
|
70
|
+
const diffDays = Math.floor(diffHrs / 24);
|
|
71
|
+
if (diffDays < 30) return formatLabel(labels.days, { count: diffDays });
|
|
72
|
+
const diffMonths = Math.floor(diffDays / 30);
|
|
73
|
+
if (diffMonths < 12) return formatLabel(labels.months, { count: diffMonths });
|
|
74
|
+
return formatLabel(labels.years, { count: Math.floor(diffDays / 365) });
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const startOfDay = (date: Date): number =>
|
|
78
|
+
new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime();
|
|
79
|
+
|
|
80
|
+
export function isSameDay(a: string, b: string): boolean {
|
|
81
|
+
return startOfDay(new Date(a)) === startOfDay(new Date(b));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Clock time beside a message. Intl ships with Hermes but is guarded anyway —
|
|
86
|
+
* a missing implementation should not blank out every timestamp in the thread.
|
|
87
|
+
*/
|
|
88
|
+
export function formatClockTime(dateStr: string, locale: string): string {
|
|
89
|
+
const date = new Date(dateStr);
|
|
90
|
+
if (Number.isNaN(date.getTime())) return '';
|
|
91
|
+
try {
|
|
92
|
+
return new Intl.DateTimeFormat(locale, { hour: 'numeric', minute: '2-digit' }).format(date);
|
|
93
|
+
} catch {
|
|
94
|
+
return `${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}`;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** "Today", "Yesterday", then a real date once it is older than that. */
|
|
99
|
+
export function formatDayLabel(
|
|
100
|
+
dateStr: string,
|
|
101
|
+
locale: string,
|
|
102
|
+
labels: { today: string; yesterday: string }
|
|
103
|
+
): string {
|
|
104
|
+
const date = new Date(dateStr);
|
|
105
|
+
if (Number.isNaN(date.getTime())) return '';
|
|
106
|
+
|
|
107
|
+
const today = startOfDay(new Date());
|
|
108
|
+
const day = startOfDay(date);
|
|
109
|
+
if (day === today) return labels.today;
|
|
110
|
+
if (today - day === 86400000) return labels.yesterday;
|
|
111
|
+
|
|
112
|
+
const sameYear = date.getFullYear() === new Date().getFullYear();
|
|
113
|
+
try {
|
|
114
|
+
return new Intl.DateTimeFormat(locale, {
|
|
115
|
+
day: 'numeric',
|
|
116
|
+
month: 'short',
|
|
117
|
+
...(sameYear ? {} : { year: 'numeric' }),
|
|
118
|
+
}).format(date);
|
|
119
|
+
} catch {
|
|
120
|
+
return date.toDateString();
|
|
121
|
+
}
|
|
122
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTML → text helpers. The CRM stores message bodies as HTML and campaign
|
|
3
|
+
* payloads as rich text; React Native has no DOMParser, so these are the
|
|
4
|
+
* regex equivalents of the web widget's `stripHtml` / `htmlToText`.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const ENTITIES: Record<string, string> = {
|
|
8
|
+
'&': '&',
|
|
9
|
+
'<': '<',
|
|
10
|
+
'>': '>',
|
|
11
|
+
'"': '"',
|
|
12
|
+
''': "'",
|
|
13
|
+
''': "'",
|
|
14
|
+
' ': ' ',
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
function decodeEntities(text: string): string {
|
|
18
|
+
return text
|
|
19
|
+
.replace(/&(amp|lt|gt|quot|#39|apos|nbsp);/g, (match) => ENTITIES[match] ?? match)
|
|
20
|
+
.replace(/&#(\d+);/g, (_match, code) => String.fromCharCode(Number(code)));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Block-level tags become newlines so paragraphs survive the strip. */
|
|
24
|
+
export function stripHtml(html: string): string {
|
|
25
|
+
if (!html) return '';
|
|
26
|
+
return decodeEntities(
|
|
27
|
+
html
|
|
28
|
+
.replace(/<br\s*\/?>/gi, '\n')
|
|
29
|
+
.replace(/<\/(p|div|li|h[1-6]|blockquote|tr)>/gi, '\n')
|
|
30
|
+
.replace(/<li[^>]*>/gi, '• ')
|
|
31
|
+
.replace(/<[^>]+>/g, '')
|
|
32
|
+
)
|
|
33
|
+
.replace(/\n{3,}/g, '\n\n')
|
|
34
|
+
.trim();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Single-line flattening used for campaign cards and list snippets. */
|
|
38
|
+
export function htmlToText(html: string): string {
|
|
39
|
+
if (!html) return '';
|
|
40
|
+
const spaced = html
|
|
41
|
+
.replace(/<\/(p|div|li|h[1-6]|blockquote)>/gi, ' $&')
|
|
42
|
+
.replace(/<br\s*\/?>/gi, ' ');
|
|
43
|
+
return renderFallbackTokens(
|
|
44
|
+
decodeEntities(spaced.replace(/<[^>]+>/g, ' '))
|
|
45
|
+
.replace(/\s+/g, ' ')
|
|
46
|
+
.trim()
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Unresolved merge tags would otherwise leak `{{ contact.firstName }}` to visitors. */
|
|
51
|
+
function renderFallbackTokens(text: string): string {
|
|
52
|
+
return text
|
|
53
|
+
.replace(/\{\{\s*contact\.firstName\s*\}\}/g, 'there')
|
|
54
|
+
.replace(/\{\{\s*contact\.fullName\s*\}\}/g, 'there')
|
|
55
|
+
.replace(/\{\{\s*contact\.[^}]+\s*\}\}/g, '')
|
|
56
|
+
.replace(/\s+/g, ' ')
|
|
57
|
+
.trim();
|
|
58
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A real gradient when the host app happens to ship one, stacked bands when it
|
|
3
|
+
* does not.
|
|
4
|
+
*
|
|
5
|
+
* Stacked bands can only ever approximate a ramp: each strip is a solid fill,
|
|
6
|
+
* and once the strips are thin enough to hide the colour steps their heights
|
|
7
|
+
* start landing on fractional pixels, which shows up as faint seams. A native
|
|
8
|
+
* gradient has neither problem, so we use one where it exists — the same
|
|
9
|
+
* "borrow it from the host" approach as `safe-area.ts` and `storage.ts`.
|
|
10
|
+
*
|
|
11
|
+
* Resolution happens once at module load so component identity stays stable
|
|
12
|
+
* across renders.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import type { ComponentType, ReactNode } from 'react';
|
|
16
|
+
import type { StyleProp, ViewStyle } from 'react-native';
|
|
17
|
+
|
|
18
|
+
export interface NativeGradientProps {
|
|
19
|
+
colors: string[];
|
|
20
|
+
/** Stop positions in 0..1, matching `colors` one for one. */
|
|
21
|
+
locations?: number[];
|
|
22
|
+
start?: { x: number; y: number };
|
|
23
|
+
end?: { x: number; y: number };
|
|
24
|
+
style?: StyleProp<ViewStyle>;
|
|
25
|
+
pointerEvents?: 'none' | 'auto' | 'box-none' | 'box-only';
|
|
26
|
+
children?: ReactNode;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
let nativeGradient: ComponentType<NativeGradientProps> | null = null;
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
33
|
+
const mod = require('react-native-linear-gradient');
|
|
34
|
+
const component = mod?.default ?? mod?.LinearGradient;
|
|
35
|
+
if (component) nativeGradient = component as ComponentType<NativeGradientProps>;
|
|
36
|
+
} catch {
|
|
37
|
+
nativeGradient = null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Null when the host installed no gradient library; callers fall back to bands. */
|
|
41
|
+
export function getNativeGradient(): ComponentType<NativeGradientProps> | null {
|
|
42
|
+
return nativeGradient;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Top-to-bottom. The only direction the band fallback can draw. */
|
|
46
|
+
export const VERTICAL = {
|
|
47
|
+
start: { x: 0.5, y: 0 },
|
|
48
|
+
end: { x: 0.5, y: 1 },
|
|
49
|
+
} as const;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Top-left to bottom-right, the same way round in every language. A brand
|
|
53
|
+
* ramp is a visual, not a sentence, so it does not mirror with the reading
|
|
54
|
+
* direction. Needs a native gradient: stacked bands are horizontal strips and
|
|
55
|
+
* can only ever run top to bottom.
|
|
56
|
+
*/
|
|
57
|
+
export const DIAGONAL = {
|
|
58
|
+
start: { x: 0, y: 0 },
|
|
59
|
+
end: { x: 1, y: 1 },
|
|
60
|
+
} as const;
|