@botonic/react 0.31.0-alpha.1 → 0.31.0-alpha.3
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/lib/cjs/components/element.js +6 -6
- package/lib/cjs/components/element.js.map +1 -1
- package/lib/cjs/components/index-types.d.ts +2 -0
- package/lib/cjs/components/multichannel/multichannel-button.js +2 -2
- package/lib/cjs/components/multichannel/multichannel-button.js.map +1 -1
- package/lib/cjs/components/multichannel/multichannel-carousel.js +4 -4
- package/lib/cjs/components/multichannel/multichannel-carousel.js.map +1 -1
- package/lib/cjs/components/multichannel/multichannel-text.js +12 -11
- package/lib/cjs/components/multichannel/multichannel-text.js.map +1 -1
- package/lib/cjs/components/multichannel/multichannel-utils.d.ts +9 -15
- package/lib/cjs/components/multichannel/multichannel-utils.js +48 -27
- package/lib/cjs/components/multichannel/multichannel-utils.js.map +1 -1
- package/lib/cjs/components/multichannel/multichannel.js +7 -7
- package/lib/cjs/components/multichannel/multichannel.js.map +1 -1
- package/lib/cjs/components/multichannel/whatsapp/constants.d.ts +11 -0
- package/lib/cjs/components/multichannel/whatsapp/constants.js +13 -0
- package/lib/cjs/components/multichannel/whatsapp/constants.js.map +1 -0
- package/lib/cjs/components/whatsapp-button-list.js +2 -2
- package/lib/cjs/components/whatsapp-button-list.js.map +1 -1
- package/lib/cjs/components/whatsapp-cta-url-button.js +5 -5
- package/lib/cjs/components/whatsapp-cta-url-button.js.map +1 -1
- package/lib/cjs/constants.d.ts +0 -6
- package/lib/cjs/constants.js +1 -7
- package/lib/cjs/constants.js.map +1 -1
- package/lib/cjs/contexts.js +6 -0
- package/lib/cjs/contexts.js.map +1 -1
- package/lib/cjs/dev-app.d.ts +7 -0
- package/lib/cjs/dev-app.js +5 -2
- package/lib/cjs/dev-app.js.map +1 -1
- package/lib/cjs/index-types.d.ts +4 -7
- package/lib/cjs/index-types.js.map +1 -1
- package/lib/cjs/index.d.ts +1 -1
- package/lib/cjs/index.js.map +1 -1
- package/lib/cjs/webchat/actions.d.ts +2 -1
- package/lib/cjs/webchat/actions.js +1 -0
- package/lib/cjs/webchat/actions.js.map +1 -1
- package/lib/cjs/webchat/cover-component/index.d.ts +6 -0
- package/lib/cjs/webchat/cover-component/index.js +21 -0
- package/lib/cjs/webchat/cover-component/index.js.map +1 -0
- package/lib/cjs/webchat/hooks/use-scroll-to-bottom.d.ts +6 -4
- package/lib/cjs/webchat/hooks/use-scroll-to-bottom.js.map +1 -1
- package/lib/cjs/webchat/hooks/use-webchat.d.ts +1 -0
- package/lib/cjs/webchat/hooks/use-webchat.js +8 -0
- package/lib/cjs/webchat/hooks/use-webchat.js.map +1 -1
- package/lib/cjs/webchat/index-types.d.ts +1 -0
- package/lib/cjs/webchat/input-panel/textarea.js +8 -2
- package/lib/cjs/webchat/input-panel/textarea.js.map +1 -1
- package/lib/cjs/webchat/message-list/index.js +63 -35
- package/lib/cjs/webchat/message-list/index.js.map +1 -1
- package/lib/cjs/webchat/message-list/styles.js +3 -3
- package/lib/cjs/webchat/typing-indicator/index.d.ts +3 -1
- package/lib/cjs/webchat/typing-indicator/index.js +4 -3
- package/lib/cjs/webchat/typing-indicator/index.js.map +1 -1
- package/lib/cjs/webchat/typing-indicator/styles.d.ts +3 -2
- package/lib/cjs/webchat/typing-indicator/styles.js +6 -3
- package/lib/cjs/webchat/typing-indicator/styles.js.map +1 -1
- package/lib/cjs/webchat/webchat-reducer.js +2 -0
- package/lib/cjs/webchat/webchat-reducer.js.map +1 -1
- package/lib/cjs/webchat/webchat-typed/styles.d.ts +7 -0
- package/lib/cjs/webchat/webchat-typed/styles.js +54 -0
- package/lib/cjs/webchat/webchat-typed/styles.js.map +1 -0
- package/lib/cjs/webchat/webchat-typed/webchat-typed.d.ts +0 -0
- package/lib/cjs/webchat/webchat-typed/webchat-typed.js +663 -0
- package/lib/cjs/webchat/webchat-typed/webchat-typed.js.map +1 -0
- package/lib/cjs/webchat/webchat.js +16 -18
- package/lib/cjs/webchat/webchat.js.map +1 -1
- package/lib/cjs/webchat-app.d.ts +119 -72
- package/lib/cjs/webchat-app.js +98 -53
- package/lib/cjs/webchat-app.js.map +1 -1
- package/lib/cjs/webview-app.js +5 -2
- package/lib/cjs/webview-app.js.map +1 -1
- package/lib/esm/components/element.js +6 -6
- package/lib/esm/components/element.js.map +1 -1
- package/lib/esm/components/index-types.d.ts +2 -0
- package/lib/esm/components/multichannel/multichannel-button.js +1 -1
- package/lib/esm/components/multichannel/multichannel-carousel.js +5 -5
- package/lib/esm/components/multichannel/multichannel-carousel.js.map +1 -1
- package/lib/esm/components/multichannel/multichannel-text.js +2 -1
- package/lib/esm/components/multichannel/multichannel-text.js.map +1 -1
- package/lib/esm/components/multichannel/multichannel-utils.d.ts +9 -15
- package/lib/esm/components/multichannel/multichannel-utils.js +40 -24
- package/lib/esm/components/multichannel/multichannel-utils.js.map +1 -1
- package/lib/esm/components/multichannel/multichannel.js +7 -7
- package/lib/esm/components/multichannel/multichannel.js.map +1 -1
- package/lib/esm/components/multichannel/whatsapp/constants.d.ts +11 -0
- package/lib/esm/components/multichannel/whatsapp/constants.js +10 -0
- package/lib/esm/components/multichannel/whatsapp/constants.js.map +1 -0
- package/lib/esm/components/whatsapp-button-list.js +1 -1
- package/lib/esm/components/whatsapp-cta-url-button.js +1 -1
- package/lib/esm/constants.d.ts +0 -6
- package/lib/esm/constants.js +0 -6
- package/lib/esm/constants.js.map +1 -1
- package/lib/esm/contexts.js +6 -0
- package/lib/esm/contexts.js.map +1 -1
- package/lib/esm/dev-app.d.ts +7 -0
- package/lib/esm/dev-app.js +5 -2
- package/lib/esm/dev-app.js.map +1 -1
- package/lib/esm/index-types.d.ts +4 -7
- package/lib/esm/index-types.js.map +1 -1
- package/lib/esm/index.d.ts +1 -1
- package/lib/esm/index.js.map +1 -1
- package/lib/esm/webchat/actions.d.ts +2 -1
- package/lib/esm/webchat/actions.js +1 -0
- package/lib/esm/webchat/actions.js.map +1 -1
- package/lib/esm/webchat/cover-component/index.d.ts +6 -0
- package/lib/esm/webchat/cover-component/index.js +17 -0
- package/lib/esm/webchat/cover-component/index.js.map +1 -0
- package/lib/esm/webchat/hooks/use-scroll-to-bottom.d.ts +6 -4
- package/lib/esm/webchat/hooks/use-scroll-to-bottom.js.map +1 -1
- package/lib/esm/webchat/hooks/use-webchat.d.ts +1 -0
- package/lib/esm/webchat/hooks/use-webchat.js +8 -0
- package/lib/esm/webchat/hooks/use-webchat.js.map +1 -1
- package/lib/esm/webchat/index-types.d.ts +1 -0
- package/lib/esm/webchat/input-panel/textarea.js +8 -2
- package/lib/esm/webchat/input-panel/textarea.js.map +1 -1
- package/lib/esm/webchat/message-list/index.js +62 -35
- package/lib/esm/webchat/message-list/index.js.map +1 -1
- package/lib/esm/webchat/message-list/styles.js +3 -3
- package/lib/esm/webchat/typing-indicator/index.d.ts +3 -1
- package/lib/esm/webchat/typing-indicator/index.js +5 -2
- package/lib/esm/webchat/typing-indicator/index.js.map +1 -1
- package/lib/esm/webchat/typing-indicator/styles.d.ts +3 -2
- package/lib/esm/webchat/typing-indicator/styles.js +5 -2
- package/lib/esm/webchat/typing-indicator/styles.js.map +1 -1
- package/lib/esm/webchat/webchat-reducer.js +2 -0
- package/lib/esm/webchat/webchat-reducer.js.map +1 -1
- package/lib/esm/webchat/webchat-typed/styles.d.ts +7 -0
- package/lib/esm/webchat/webchat-typed/styles.js +50 -0
- package/lib/esm/webchat/webchat-typed/styles.js.map +1 -0
- package/lib/esm/webchat/webchat-typed/webchat-typed.d.ts +0 -0
- package/lib/esm/webchat/webchat-typed/webchat-typed.js +663 -0
- package/lib/esm/webchat/webchat-typed/webchat-typed.js.map +1 -0
- package/lib/esm/webchat/webchat.js +16 -18
- package/lib/esm/webchat/webchat.js.map +1 -1
- package/lib/esm/webchat-app.d.ts +119 -72
- package/lib/esm/webchat-app.js +99 -54
- package/lib/esm/webchat-app.js.map +1 -1
- package/lib/esm/webview-app.js +5 -2
- package/lib/esm/webview-app.js.map +1 -1
- package/package.json +3 -2
- package/src/components/element.jsx +4 -11
- package/src/components/index-types.ts +4 -0
- package/src/components/multichannel/multichannel-button.jsx +1 -1
- package/src/components/multichannel/multichannel-carousel.jsx +7 -5
- package/src/components/multichannel/multichannel-text.jsx +4 -2
- package/src/components/multichannel/multichannel-utils.js +45 -27
- package/src/components/multichannel/multichannel.jsx +12 -7
- package/src/components/multichannel/whatsapp/constants.ts +10 -0
- package/src/components/whatsapp-button-list.tsx +1 -1
- package/src/components/whatsapp-cta-url-button.tsx +1 -1
- package/src/constants.js +0 -7
- package/src/contexts.tsx +6 -0
- package/src/dev-app.jsx +5 -5
- package/src/index-types.ts +4 -7
- package/src/index.ts +1 -1
- package/src/webchat/actions.ts +1 -0
- package/src/webchat/cover-component/index.tsx +31 -0
- package/src/webchat/hooks/use-scroll-to-bottom.ts +8 -2
- package/src/webchat/hooks/use-webchat.ts +9 -0
- package/src/webchat/index-types.ts +1 -0
- package/src/webchat/input-panel/textarea.tsx +12 -1
- package/src/webchat/message-list/index.tsx +79 -48
- package/src/webchat/message-list/styles.ts +3 -3
- package/src/webchat/typing-indicator/index.tsx +20 -12
- package/src/webchat/typing-indicator/styles.ts +7 -3
- package/src/webchat/webchat-reducer.ts +2 -0
- package/src/webchat/webchat-typed/styles.ts +54 -0
- package/src/webchat/webchat-typed/webchat-typed.tsx +728 -0
- package/src/webchat/webchat.jsx +48 -48
- package/src/webchat-app.tsx +546 -0
- package/src/webview-app.tsx +6 -4
- package/src/webchat-app.jsx +0 -389
|
@@ -1,45 +1,63 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
export const DEFAULT_WHATSAPP_MAX_BUTTON_SEPARATOR = 'More options:'
|
|
15
|
-
export const MENU_BUTTON_WHATSAPP_BUTTON_LIST = 'Show options'
|
|
1
|
+
import { Button } from '../button'
|
|
2
|
+
import { Carousel } from '../carousel'
|
|
3
|
+
import { Pic } from '../pic'
|
|
4
|
+
import { Reply } from '../reply'
|
|
5
|
+
import { Subtitle } from '../subtitle'
|
|
6
|
+
import { Text } from '../text'
|
|
7
|
+
import { Title } from '../title'
|
|
8
|
+
import { MultichannelButton } from './multichannel-button'
|
|
9
|
+
import { MultichannelReply } from './multichannel-reply'
|
|
10
|
+
|
|
11
|
+
function isNodeKind(node, kind) {
|
|
12
|
+
return node?.type?.name === kind
|
|
13
|
+
}
|
|
16
14
|
|
|
17
15
|
export function isMultichannelButton(node) {
|
|
18
|
-
return isNodeKind(node,
|
|
16
|
+
return isNodeKind(node, MultichannelButton.name)
|
|
19
17
|
}
|
|
20
18
|
|
|
21
19
|
export function isMultichannelReply(node) {
|
|
22
|
-
return isNodeKind(node,
|
|
20
|
+
return isNodeKind(node, MultichannelReply.name)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function isNodeText(node) {
|
|
24
|
+
return isNodeKind(node, Text.name)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function isNodeButton(node) {
|
|
28
|
+
return isNodeKind(node, Button.name)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function isNodeCarousel(node) {
|
|
32
|
+
return isNodeKind(node, Carousel.name)
|
|
23
33
|
}
|
|
24
34
|
|
|
25
|
-
export function
|
|
26
|
-
return isNodeKind(node,
|
|
35
|
+
export function isNodeReply(node) {
|
|
36
|
+
return isNodeKind(node, Reply.name)
|
|
27
37
|
}
|
|
28
38
|
|
|
29
|
-
export function
|
|
30
|
-
return node
|
|
39
|
+
export function isNodePic(node) {
|
|
40
|
+
return isNodeKind(node, Pic.name)
|
|
31
41
|
}
|
|
42
|
+
|
|
43
|
+
export function isNodeTitle(node) {
|
|
44
|
+
return isNodeKind(node, Title.name)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function isNodeSubtitle(node) {
|
|
48
|
+
return isNodeKind(node, Subtitle.name)
|
|
49
|
+
}
|
|
50
|
+
|
|
32
51
|
export function elementHasUrl(element) {
|
|
33
|
-
return element
|
|
52
|
+
return element?.props?.url
|
|
34
53
|
}
|
|
54
|
+
|
|
35
55
|
export function elementHasPostback(element) {
|
|
36
|
-
return
|
|
37
|
-
(element.props && element.props.payload) ||
|
|
38
|
-
(element.props && element.props.path)
|
|
39
|
-
)
|
|
56
|
+
return element?.props?.payload || element?.props?.path
|
|
40
57
|
}
|
|
58
|
+
|
|
41
59
|
export function elementHasWebview(element) {
|
|
42
|
-
return element
|
|
60
|
+
return element?.props?.webview
|
|
43
61
|
}
|
|
44
62
|
|
|
45
63
|
export const buttonTypes = {
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { isFacebook, isWhatsapp } from '@botonic/core'
|
|
2
2
|
import React, { useContext } from 'react'
|
|
3
3
|
|
|
4
|
-
import { COMPONENT_TYPE } from '../../constants'
|
|
5
4
|
import { RequestContext } from '../../contexts'
|
|
6
5
|
import { deepMapWithIndex } from '../../util/react'
|
|
7
6
|
import { Text } from '../text'
|
|
@@ -10,7 +9,13 @@ import { MultichannelCarousel } from './multichannel-carousel'
|
|
|
10
9
|
import { MultichannelContext } from './multichannel-context'
|
|
11
10
|
import { MultichannelReply } from './multichannel-reply'
|
|
12
11
|
import { MultichannelText } from './multichannel-text'
|
|
13
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
isNodeButton,
|
|
14
|
+
isNodeCarousel,
|
|
15
|
+
isNodeReply,
|
|
16
|
+
isNodeText,
|
|
17
|
+
} from './multichannel-utils'
|
|
18
|
+
import { MULTICHANNEL_WHATSAPP_PROPS } from './whatsapp/constants'
|
|
14
19
|
|
|
15
20
|
export const Multichannel = props => {
|
|
16
21
|
const requestContext = useContext(RequestContext)
|
|
@@ -22,7 +27,7 @@ export const Multichannel = props => {
|
|
|
22
27
|
}
|
|
23
28
|
if (isFacebook(requestContext.session)) {
|
|
24
29
|
const newChildren = deepMapWithIndex(props.children, child => {
|
|
25
|
-
if (child
|
|
30
|
+
if (isNodeText(child)) {
|
|
26
31
|
return (
|
|
27
32
|
<MultichannelText {...child.props} key={child.key}>
|
|
28
33
|
{child.props.children}
|
|
@@ -35,21 +40,21 @@ export const Multichannel = props => {
|
|
|
35
40
|
}
|
|
36
41
|
|
|
37
42
|
let newChildren = deepMapWithIndex(props.children, (child, index) => {
|
|
38
|
-
if (child
|
|
43
|
+
if (isNodeButton(child)) {
|
|
39
44
|
return (
|
|
40
45
|
<MultichannelButton {...child.props} key={child.key}>
|
|
41
46
|
{child.props.children}
|
|
42
47
|
</MultichannelButton>
|
|
43
48
|
)
|
|
44
49
|
}
|
|
45
|
-
if (child
|
|
50
|
+
if (isNodeReply(child)) {
|
|
46
51
|
return (
|
|
47
52
|
<MultichannelReply {...child.props} key={child.key}>
|
|
48
53
|
{child.props.children}
|
|
49
54
|
</MultichannelReply>
|
|
50
55
|
)
|
|
51
56
|
}
|
|
52
|
-
if (child
|
|
57
|
+
if (isNodeText(child)) {
|
|
53
58
|
return (
|
|
54
59
|
<MultichannelText
|
|
55
60
|
{...child.props}
|
|
@@ -62,7 +67,7 @@ export const Multichannel = props => {
|
|
|
62
67
|
</MultichannelText>
|
|
63
68
|
)
|
|
64
69
|
}
|
|
65
|
-
if (child
|
|
70
|
+
if (isNodeCarousel(child)) {
|
|
66
71
|
return (
|
|
67
72
|
<MultichannelCarousel
|
|
68
73
|
{...child.props}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export const MULTICHANNEL_WHATSAPP_PROPS = { markdown: false }
|
|
2
|
+
|
|
3
|
+
export const WHATSAPP_MAX_BUTTONS = 3
|
|
4
|
+
export const WHATSAPP_LIST_MAX_BUTTONS = 10
|
|
5
|
+
export const WHATSAPP_MAX_BUTTON_CHARS = 20
|
|
6
|
+
export const WHATSAPP_MAX_HEADER_CHARS = 60
|
|
7
|
+
export const WHATSAPP_MAX_BODY_CHARS = 1024
|
|
8
|
+
export const WHATSAPP_MAX_FOOTER_CHARS = 60
|
|
9
|
+
export const DEFAULT_WHATSAPP_MAX_BUTTON_SEPARATOR = 'More options:'
|
|
10
|
+
export const MENU_BUTTON_WHATSAPP_BUTTON_LIST = 'Show options'
|
|
@@ -4,7 +4,7 @@ import React from 'react'
|
|
|
4
4
|
import { truncateText } from '../util'
|
|
5
5
|
import { renderComponent } from '../util/react'
|
|
6
6
|
import { Message } from './message'
|
|
7
|
-
import { WHATSAPP_MAX_BUTTON_CHARS } from './multichannel/
|
|
7
|
+
import { WHATSAPP_MAX_BUTTON_CHARS } from './multichannel/whatsapp/constants'
|
|
8
8
|
import { convertToMarkdownMeta } from './multichannel/whatsapp/markdown-meta'
|
|
9
9
|
|
|
10
10
|
// TODO: Add validation in component
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
WHATSAPP_MAX_BUTTON_CHARS,
|
|
11
11
|
WHATSAPP_MAX_FOOTER_CHARS,
|
|
12
12
|
WHATSAPP_MAX_HEADER_CHARS,
|
|
13
|
-
} from './multichannel/
|
|
13
|
+
} from './multichannel/whatsapp/constants'
|
|
14
14
|
import { convertToMarkdownMeta } from './multichannel/whatsapp/markdown-meta'
|
|
15
15
|
|
|
16
16
|
export interface WhatsappCTAUrlButtonCommonProps {
|
package/src/constants.js
CHANGED
package/src/contexts.tsx
CHANGED
|
@@ -56,6 +56,9 @@ export const WebchatContext = createContext<WebchatContextProps>({
|
|
|
56
56
|
resetUnreadMessages: () => {
|
|
57
57
|
return
|
|
58
58
|
},
|
|
59
|
+
setIsInputFocused: () => {
|
|
60
|
+
return
|
|
61
|
+
},
|
|
59
62
|
setLastMessageVisible: () => {
|
|
60
63
|
return
|
|
61
64
|
},
|
|
@@ -72,6 +75,9 @@ export const WebchatContext = createContext<WebchatContextProps>({
|
|
|
72
75
|
return
|
|
73
76
|
},
|
|
74
77
|
theme: {},
|
|
78
|
+
toggleCoverComponent: () => {
|
|
79
|
+
return
|
|
80
|
+
},
|
|
75
81
|
toggleWebchat: () => {
|
|
76
82
|
return
|
|
77
83
|
},
|
package/src/dev-app.jsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import merge from 'lodash.merge'
|
|
2
2
|
import React from 'react'
|
|
3
|
-
import {
|
|
3
|
+
import { createRoot } from 'react-dom/client'
|
|
4
4
|
|
|
5
5
|
import { SENDERS } from './index-types'
|
|
6
6
|
import { ReactBot } from './react-bot'
|
|
@@ -119,10 +119,10 @@ export class DevApp extends WebchatApp {
|
|
|
119
119
|
|
|
120
120
|
render(dest, optionsAtRuntime = {}) {
|
|
121
121
|
onDOMLoaded(() => {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
)
|
|
122
|
+
const devAppComponent = this.getComponent(dest, optionsAtRuntime)
|
|
123
|
+
const container = this.getReactMountNode(dest)
|
|
124
|
+
const reactRoot = createRoot(container)
|
|
125
|
+
reactRoot.render(devAppComponent)
|
|
126
126
|
})
|
|
127
127
|
}
|
|
128
128
|
|
package/src/index-types.ts
CHANGED
|
@@ -79,18 +79,13 @@ export interface WebchatArgs {
|
|
|
79
79
|
theme?: ThemeProps
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
type EventArgs = { [key: string]: any }
|
|
83
|
-
type TrackEventFunction = (
|
|
82
|
+
export type EventArgs = { [key: string]: any }
|
|
83
|
+
export type TrackEventFunction = (
|
|
84
84
|
request: ActionRequest,
|
|
85
85
|
eventName: string,
|
|
86
86
|
args?: EventArgs
|
|
87
87
|
) => Promise<void>
|
|
88
88
|
|
|
89
|
-
export interface WebchatAppArgs {
|
|
90
|
-
appId?: string
|
|
91
|
-
visibility?: () => boolean
|
|
92
|
-
}
|
|
93
|
-
|
|
94
89
|
export enum SENDERS {
|
|
95
90
|
bot = 'bot',
|
|
96
91
|
user = 'user',
|
|
@@ -162,11 +157,13 @@ export interface WebchatContextProps {
|
|
|
162
157
|
sendInput: (input: ClientInput) => Promise<void>
|
|
163
158
|
sendPayload: (payload: string) => Promise<void>
|
|
164
159
|
sendText: (text: string, payload?: string) => Promise<void>
|
|
160
|
+
setIsInputFocused: (isInputFocused: boolean) => void
|
|
165
161
|
setLastMessageVisible: (isLastMessageVisible: boolean) => void
|
|
166
162
|
theme: ThemeProps
|
|
167
163
|
toggleWebchat: (toggle: boolean) => void
|
|
168
164
|
toggleEmojiPicker: (toggle: boolean) => void
|
|
169
165
|
togglePersistentMenu: (toggle: boolean) => void
|
|
166
|
+
toggleCoverComponent: (toggle: boolean) => void
|
|
170
167
|
updateLatestInput: (input: ClientInput) => void
|
|
171
168
|
updateMessage: (message: WebchatMessage) => void
|
|
172
169
|
updateReplies: (replies: boolean) => void
|
package/src/index.ts
CHANGED
|
@@ -11,5 +11,5 @@ export { msgsToBotonic, msgToBotonic } from './msg-to-botonic'
|
|
|
11
11
|
export { NodeApp } from './node-app'
|
|
12
12
|
export * from './util'
|
|
13
13
|
export * from './webchat'
|
|
14
|
-
export { WebchatApp } from './webchat-app'
|
|
14
|
+
export { WebchatApp, WebchatAppProps } from './webchat-app'
|
|
15
15
|
export { WebviewApp } from './webview-app'
|
package/src/webchat/actions.ts
CHANGED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import React, { useContext } from 'react'
|
|
2
|
+
|
|
3
|
+
import { WEBCHAT } from '../../constants'
|
|
4
|
+
import { WebchatContext } from '../../contexts'
|
|
5
|
+
|
|
6
|
+
interface Props {
|
|
7
|
+
component: any
|
|
8
|
+
componentProps: any
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const CoverComponent = ({ component, componentProps }: Props) => {
|
|
12
|
+
const { getThemeProperty, toggleCoverComponent, webchatState } =
|
|
13
|
+
useContext(WebchatContext)
|
|
14
|
+
|
|
15
|
+
const Cover = component
|
|
16
|
+
|
|
17
|
+
const coverComponentProps = getThemeProperty(
|
|
18
|
+
WEBCHAT.CUSTOM_PROPERTIES.coverComponentProps,
|
|
19
|
+
componentProps
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
const closeCoverComponent = () => {
|
|
23
|
+
toggleCoverComponent(false)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (!Cover || !webchatState.isCoverComponentOpen) {
|
|
27
|
+
return null
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return <Cover closeComponent={closeCoverComponent} {...coverComponentProps} />
|
|
31
|
+
}
|
|
@@ -3,11 +3,17 @@ import {
|
|
|
3
3
|
getWebchatElement,
|
|
4
4
|
} from '../../util/dom'
|
|
5
5
|
|
|
6
|
+
interface UseScrollToBottom {
|
|
7
|
+
host: any
|
|
8
|
+
behavior?: ScrollBehavior
|
|
9
|
+
timeout?: number
|
|
10
|
+
}
|
|
11
|
+
|
|
6
12
|
export const useScrollToBottom = ({
|
|
7
13
|
host,
|
|
8
14
|
behavior = 'smooth',
|
|
9
15
|
timeout = 200,
|
|
10
|
-
}) => {
|
|
16
|
+
}: UseScrollToBottom) => {
|
|
11
17
|
const scrollToBottom = () => {
|
|
12
18
|
const webchatElement = getWebchatElement(host)
|
|
13
19
|
if (!webchatElement) return
|
|
@@ -17,7 +23,7 @@ export const useScrollToBottom = ({
|
|
|
17
23
|
setTimeout(() => {
|
|
18
24
|
scrollableMessagesListElement.scrollTo({
|
|
19
25
|
top: scrollableMessagesListElement.scrollHeight,
|
|
20
|
-
behavior: behavior
|
|
26
|
+
behavior: behavior,
|
|
21
27
|
})
|
|
22
28
|
}, timeout)
|
|
23
29
|
}
|
|
@@ -44,6 +44,7 @@ export const webchatInitialState: WebchatState = {
|
|
|
44
44
|
currentAttachment: undefined,
|
|
45
45
|
numUnreadMessages: 0,
|
|
46
46
|
isLastMessageVisible: true,
|
|
47
|
+
isInputFocused: false,
|
|
47
48
|
}
|
|
48
49
|
|
|
49
50
|
export function useWebchat() {
|
|
@@ -196,6 +197,13 @@ export function useWebchat() {
|
|
|
196
197
|
})
|
|
197
198
|
}
|
|
198
199
|
|
|
200
|
+
const setIsInputFocused = (isInputFocused: boolean) => {
|
|
201
|
+
webchatDispatch({
|
|
202
|
+
type: WebchatAction.SET_IS_INPUT_FOCUSED,
|
|
203
|
+
payload: isInputFocused,
|
|
204
|
+
})
|
|
205
|
+
}
|
|
206
|
+
|
|
199
207
|
return {
|
|
200
208
|
addMessage,
|
|
201
209
|
addMessageComponent,
|
|
@@ -204,6 +212,7 @@ export function useWebchat() {
|
|
|
204
212
|
resetUnreadMessages,
|
|
205
213
|
setCurrentAttachment,
|
|
206
214
|
setError,
|
|
215
|
+
setIsInputFocused,
|
|
207
216
|
setLastMessageVisible,
|
|
208
217
|
setOnline,
|
|
209
218
|
toggleCoverComponent,
|
|
@@ -23,7 +23,8 @@ export const Textarea = ({
|
|
|
23
23
|
sendChatEvent,
|
|
24
24
|
sendTextAreaText,
|
|
25
25
|
}: TextareaProps) => {
|
|
26
|
-
const { getThemeProperty, webchatState } =
|
|
26
|
+
const { getThemeProperty, webchatState, setIsInputFocused } =
|
|
27
|
+
useContext(WebchatContext)
|
|
27
28
|
|
|
28
29
|
useDeviceAdapter(host, webchatState.isWebchatOpen)
|
|
29
30
|
|
|
@@ -71,10 +72,20 @@ export const Textarea = ({
|
|
|
71
72
|
sendChatEvent(Typing.Off)
|
|
72
73
|
}
|
|
73
74
|
|
|
75
|
+
const handleFocus = () => {
|
|
76
|
+
setIsInputFocused(true)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const handleBlur = () => {
|
|
80
|
+
setIsInputFocused(false)
|
|
81
|
+
}
|
|
82
|
+
|
|
74
83
|
return (
|
|
75
84
|
<TextAreaContainer>
|
|
76
85
|
<TextareaAutosize
|
|
77
86
|
ref={(ref: HTMLTextAreaElement) => (textareaRef.current = ref)}
|
|
87
|
+
onFocus={handleFocus}
|
|
88
|
+
onBlur={handleBlur}
|
|
78
89
|
name='text'
|
|
79
90
|
maxRows={4}
|
|
80
91
|
wrap='soft'
|
|
@@ -3,13 +3,23 @@ import React, { useContext, useEffect, useRef, useState } from 'react'
|
|
|
3
3
|
import { ROLES } from '../../constants'
|
|
4
4
|
import { WebchatContext } from '../../contexts'
|
|
5
5
|
import { BotonicContainerId } from '../constants'
|
|
6
|
-
import
|
|
6
|
+
import TypingIndicator from '../typing-indicator'
|
|
7
7
|
import { IntroMessage } from './intro-message'
|
|
8
8
|
import { ScrollButton } from './scroll-button'
|
|
9
9
|
import { ContainerMessage, ScrollableMessageList } from './styles'
|
|
10
10
|
import { UnreadMessagesBanner } from './unread-messages-banner'
|
|
11
11
|
import { useNotifications } from './use-notifications'
|
|
12
12
|
|
|
13
|
+
const SCROLL_TIMEOUT = 200
|
|
14
|
+
const scrollOptionsEnd: ScrollIntoViewOptions = {
|
|
15
|
+
behavior: 'smooth',
|
|
16
|
+
block: 'end',
|
|
17
|
+
}
|
|
18
|
+
const scrollOptionsCenter: ScrollIntoViewOptions = {
|
|
19
|
+
behavior: 'smooth',
|
|
20
|
+
block: 'center',
|
|
21
|
+
}
|
|
22
|
+
|
|
13
23
|
export const WebchatMessageList = () => {
|
|
14
24
|
const {
|
|
15
25
|
webchatState,
|
|
@@ -18,39 +28,50 @@ export const WebchatMessageList = () => {
|
|
|
18
28
|
scrollableMessagesListRef,
|
|
19
29
|
} = useContext(WebchatContext)
|
|
20
30
|
|
|
21
|
-
const
|
|
31
|
+
const { notificationsEnabled } = useNotifications()
|
|
22
32
|
|
|
23
|
-
const
|
|
33
|
+
const [firstUnreadMessageId, setFirstUnreadMessageId] = useState<string>()
|
|
24
34
|
|
|
25
|
-
const
|
|
35
|
+
const lastMessageRef = useRef<HTMLDivElement>(null)
|
|
36
|
+
const typingRef = useRef<HTMLDivElement>(null)
|
|
37
|
+
const unreadMessagesBannerRef = useRef<HTMLDivElement>(null)
|
|
38
|
+
|
|
39
|
+
const scrollToTyping = () => {
|
|
26
40
|
setTimeout(() => {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
block: 'end',
|
|
30
|
-
})
|
|
31
|
-
}, 100)
|
|
41
|
+
typingRef.current?.scrollIntoView(scrollOptionsEnd)
|
|
42
|
+
}, SCROLL_TIMEOUT)
|
|
32
43
|
}
|
|
33
44
|
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
45
|
+
const scrollToLastMessage = () => {
|
|
46
|
+
setTimeout(() => {
|
|
47
|
+
lastMessageRef.current?.scrollIntoView(scrollOptionsEnd)
|
|
48
|
+
}, SCROLL_TIMEOUT)
|
|
37
49
|
}
|
|
38
50
|
|
|
39
|
-
const unreadMessagesBannerRef = useRef<HTMLDivElement>(null)
|
|
40
|
-
|
|
41
51
|
const scrollToBanner = () => {
|
|
42
52
|
setTimeout(() => {
|
|
43
|
-
unreadMessagesBannerRef.current?.scrollIntoView(
|
|
44
|
-
|
|
45
|
-
block: 'center',
|
|
46
|
-
})
|
|
47
|
-
}, 100)
|
|
53
|
+
unreadMessagesBannerRef.current?.scrollIntoView(scrollOptionsCenter)
|
|
54
|
+
}, SCROLL_TIMEOUT)
|
|
48
55
|
}
|
|
49
56
|
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
57
|
+
const handleScrollToBottom = () => {
|
|
58
|
+
resetUnreadMessages()
|
|
59
|
+
if (webchatState.typing) {
|
|
60
|
+
scrollToTyping()
|
|
61
|
+
return
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
scrollToLastMessage()
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const showUnreadMessagesBanner = (messageComponentId: string) => {
|
|
68
|
+
return (
|
|
69
|
+
!webchatState.isInputFocused &&
|
|
70
|
+
firstUnreadMessageId &&
|
|
71
|
+
messageComponentId === firstUnreadMessageId &&
|
|
72
|
+
webchatState.numUnreadMessages > 0
|
|
73
|
+
)
|
|
74
|
+
}
|
|
54
75
|
|
|
55
76
|
useEffect(() => {
|
|
56
77
|
const firstUnreadMessage = webchatState.messagesComponents.find(
|
|
@@ -60,39 +81,47 @@ export const WebchatMessageList = () => {
|
|
|
60
81
|
}, [webchatState.messagesComponents])
|
|
61
82
|
|
|
62
83
|
useEffect(() => {
|
|
63
|
-
if (
|
|
64
|
-
webchatState.messagesComponents.length > 0 &&
|
|
65
|
-
lastMessageBottomRef.current
|
|
66
|
-
) {
|
|
84
|
+
if (webchatState.messagesComponents.length > 0 && lastMessageRef.current) {
|
|
67
85
|
const observer = new IntersectionObserver(entries => {
|
|
68
86
|
entries.forEach(entry => {
|
|
69
87
|
setLastMessageVisible(entry.isIntersecting)
|
|
70
88
|
})
|
|
71
89
|
})
|
|
72
|
-
observer.observe(
|
|
90
|
+
observer.observe(lastMessageRef.current)
|
|
73
91
|
}
|
|
74
92
|
}, [webchatState.messagesComponents])
|
|
75
93
|
|
|
76
|
-
const { notificationsEnabled } = useNotifications()
|
|
77
|
-
|
|
78
94
|
useEffect(() => {
|
|
79
95
|
if (!notificationsEnabled) {
|
|
80
|
-
|
|
81
|
-
|
|
96
|
+
if (webchatState.typing) {
|
|
97
|
+
scrollToTyping()
|
|
98
|
+
return
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
scrollToLastMessage()
|
|
82
102
|
}
|
|
83
|
-
}, [webchatState.typing])
|
|
103
|
+
}, [webchatState.typing, webchatState.messagesComponents])
|
|
84
104
|
|
|
85
105
|
useEffect(() => {
|
|
86
|
-
if (notificationsEnabled) {
|
|
87
|
-
if (
|
|
106
|
+
if (webchatState.isWebchatOpen && notificationsEnabled) {
|
|
107
|
+
if (unreadMessagesBannerRef.current) {
|
|
88
108
|
scrollToBanner()
|
|
89
109
|
return
|
|
90
110
|
}
|
|
91
111
|
|
|
92
|
-
|
|
93
|
-
|
|
112
|
+
if (webchatState.typing) {
|
|
113
|
+
scrollToTyping()
|
|
114
|
+
return
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
scrollToLastMessage()
|
|
94
118
|
}
|
|
95
|
-
}, [
|
|
119
|
+
}, [
|
|
120
|
+
firstUnreadMessageId,
|
|
121
|
+
webchatState.isWebchatOpen,
|
|
122
|
+
webchatState.typing,
|
|
123
|
+
webchatState.messagesComponents,
|
|
124
|
+
])
|
|
96
125
|
|
|
97
126
|
const showScrollButton =
|
|
98
127
|
webchatState.numUnreadMessages > 0 && !webchatState.isLastMessageVisible
|
|
@@ -107,25 +136,27 @@ export const WebchatMessageList = () => {
|
|
|
107
136
|
<IntroMessage />
|
|
108
137
|
{webchatState.messagesComponents.map((messageComponent, index) => {
|
|
109
138
|
return (
|
|
110
|
-
|
|
111
|
-
{
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
139
|
+
<>
|
|
140
|
+
<ContainerMessage role={ROLES.MESSAGE} key={index}>
|
|
141
|
+
{showUnreadMessagesBanner(messageComponent.props.id) && (
|
|
142
|
+
<UnreadMessagesBanner
|
|
143
|
+
unreadMessagesBannerRef={unreadMessagesBannerRef}
|
|
144
|
+
/>
|
|
145
|
+
)}
|
|
146
|
+
{messageComponent}
|
|
147
|
+
</ContainerMessage>
|
|
117
148
|
{index === webchatState.messagesComponents.length - 1 && (
|
|
118
149
|
<div
|
|
119
|
-
ref={
|
|
150
|
+
ref={lastMessageRef}
|
|
120
151
|
style={{
|
|
121
152
|
content: '',
|
|
122
153
|
}}
|
|
123
154
|
></div>
|
|
124
155
|
)}
|
|
125
|
-
|
|
156
|
+
</>
|
|
126
157
|
)
|
|
127
158
|
})}
|
|
128
|
-
{webchatState.typing && <TypingIndicator />}
|
|
159
|
+
{webchatState.typing && <TypingIndicator ref={typingRef} />}
|
|
129
160
|
</ScrollableMessageList>
|
|
130
161
|
{showScrollButton && <ScrollButton handleClick={handleScrollToBottom} />}
|
|
131
162
|
</>
|
|
@@ -15,9 +15,9 @@ export const DefaultIntroImage = styled.img`
|
|
|
15
15
|
`
|
|
16
16
|
|
|
17
17
|
export const ContainerScrollButton = styled.div`
|
|
18
|
-
position:
|
|
19
|
-
|
|
20
|
-
bottom:
|
|
18
|
+
position: sticky;
|
|
19
|
+
left: 85%;
|
|
20
|
+
bottom: 15px;
|
|
21
21
|
|
|
22
22
|
background-color: #6d6a78;
|
|
23
23
|
cursor: pointer;
|