diff --git a/.babelrc b/.babelrc
deleted file mode 100644
index b005e8e6a..000000000
--- a/.babelrc
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "presets": [
- ["@babel/preset-env", {
- "targets": {
- "browsers": ["last 2 versions", "safari >= 7"]
- }
- }],
- ["@babel/preset-react", {
- "runtime": "automatic"
- }],
- "@babel/preset-typescript"
- ],
- "plugins": [
- "@babel/plugin-proposal-class-properties",
- "@babel/plugin-proposal-object-rest-spread"
- ]
-}
diff --git a/.eslintignore b/.eslintignore
deleted file mode 100644
index 4799c0828..000000000
--- a/.eslintignore
+++ /dev/null
@@ -1,3 +0,0 @@
-lib
-dev
-webpack.config*
diff --git a/.eslintrc b/.eslintrc
deleted file mode 100644
index 71e92eadb..000000000
--- a/.eslintrc
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "extends": "wolox",
- "rules": {
- "import/order": "off",
- "react/jsx-uses-react": "off",
- "react/react-in-jsx-scope": "off"
- }
-}
diff --git a/.gitignore b/.gitignore
index 0267dad17..2770e5579 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,10 +7,12 @@ yarn-error.log
.DS_Store
# Build files
-# lib
+lib
# Test files
coverage
# vscode
.vscode
+
+react-chat-widget-*.tgz
\ No newline at end of file
diff --git a/.npmignore b/.npmignore
deleted file mode 100644
index 7f86bbec5..000000000
--- a/.npmignore
+++ /dev/null
@@ -1,17 +0,0 @@
-/src
-/dev
-index.js
-
-assets
-
-mocks
-coverage
-
-circle.yml
-.babelrc
-.eslintrc.js
-.eslintignore
-webpack.config*
-
-package-lock.json
-yarn.lock
diff --git a/.storybook/main.js b/.storybook/main.js
new file mode 100644
index 000000000..a9d4f31ef
--- /dev/null
+++ b/.storybook/main.js
@@ -0,0 +1,69 @@
+const path = require('path');
+
+
+module.exports = {
+ stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|ts|tsx)"],
+
+ addons: [
+ "@storybook/addon-links",
+ "@storybook/addon-essentials",
+ "@storybook/addon-webpack5-compiler-babel",
+ "@chromatic-com/storybook",
+ {
+ name: '@storybook/addon-styling-webpack',
+ options: {
+ rules: [
+ // Replaces any existing Sass rules with given rules
+ {
+ test: /\.s[ac]ss$/i,
+ use: [
+ "style-loader",
+ "css-loader",
+ {
+ loader: "sass-loader",
+ options: {
+ implementation: require.resolve("sass"),
+ sassOptions: {
+ loadPaths: [path.resolve(__dirname, '../src/scss/')]
+ }
+ }
+ },
+ ],
+ },
+ ]
+ }
+ },
+ ],
+
+ webpackFinal: async (config, { configType }) => {
+ // config.module.rules.push({
+ // test: /\.scss$/,
+ // use: ["style-loader", "css-loader", "sass-loader"],
+ // include: path.resolve(__dirname, "../")
+ // });
+
+ config.module.rules.push({
+ test: /\.(ts|tsx)$/,
+ loader: require.resolve("babel-loader"),
+ options: {
+ presets: [["react-app", { flow: false, typescript: true }]]
+ }
+ });
+ config.resolve.extensions.push(".ts", ".tsx");
+
+ return config;
+ },
+
+ docs: {
+ autodocs: true
+ },
+
+ framework: {
+ name: "@storybook/react-webpack5",
+ options: {}
+ },
+
+ typescript: {
+ reactDocgen: "react-docgen-typescript"
+ }
+}
\ No newline at end of file
diff --git a/circle.yml b/circle.yml
deleted file mode 100644
index 39c7b1d7e..000000000
--- a/circle.yml
+++ /dev/null
@@ -1,10 +0,0 @@
-machine:
- node:
- version: 8.4.0
-
-dependencies:
- override:
- - npm i
-test:
- override:
- - npm run test
diff --git a/custom.d.ts b/custom.d.ts
deleted file mode 100644
index 1a3dd3c2a..000000000
--- a/custom.d.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-declare module "*.svg" {
- const content: any;
- export default content;
-}
diff --git a/dev/App.tsx b/dev/App.tsx
deleted file mode 100644
index d2b6eeee7..000000000
--- a/dev/App.tsx
+++ /dev/null
@@ -1,54 +0,0 @@
-import { Component } from 'react';
-
-import { Widget, addResponseMessage, setQuickButtons, toggleMsgLoader, addLinkSnippet } from '../index';
-import { addUserMessage } from '..';
-
-export default class App extends Component {
- componentDidMount() {
- addResponseMessage('Welcome to this awesome chat!');
- addLinkSnippet({ link: 'https://google.com', title: 'Google' });
- addResponseMessage('');
- addResponseMessage('');
- }
-
- handleNewUserMessage = (newMessage: any) => {
- toggleMsgLoader();
- setTimeout(() => {
- toggleMsgLoader();
- if (newMessage === 'fruits') {
- setQuickButtons([ { label: 'Apple', value: 'apple' }, { label: 'Orange', value: 'orange' }, { label: 'Pear', value: 'pear' }, { label: 'Banana', value: 'banana' } ]);
- } else {
- addResponseMessage(newMessage);
- }
- }, 2000);
- }
-
- handleQuickButtonClicked = (e: any) => {
- addResponseMessage('Selected ' + e);
- setQuickButtons([]);
- }
-
- handleSubmit = (msgText: string) => {
- if(msgText.length < 80) {
- addUserMessage("Uh oh, please write a bit more.");
- return false;
- }
- return true;
- }
-
- render() {
- return (
-
"+i(e[t].content)+"
\n"},a.fence=function(e,t,r,n,a){var s,u,c,l,f=e[t],d=f.info?o(f.info).trim():"",p="";return d&&(p=d.split(/\s+/g)[0]),0===(s=r.highlight&&r.highlight(f.content,p)||i(f.content)).indexOf(""+s+"
\n"):""+s+"
\n"},a.image=function(e,t,r,n,o){var i=e[t];return i.attrs[i.attrIndex("alt")][1]=o.renderInlineAsText(i.children,r,n),o.renderToken(e,t,r)},a.hardbreak=function(e,t,r){return r.xhtmlOut?"=0)M=l.charCodeAt(f.index-1);else for(j=r-1;j>=0&&("softbreak"!==e[j].type&&"hardbreak"!==e[j].type);j--)if("text"===e[j].type){M=e[j].content.charCodeAt(e[j].content.length-1);break}if(m=32,d
=48&&M<=57&&(D=w=!1),w&&D&&(w=!1,D=N),w||D){if(D)for(j=_.length-1;j>=0&&(g=_[j],!(_[j].level =4))break;o=++n}return e.line=o,(i=e.push("code_block","code",0)).content=e.getLines(t,o,4+e.blkIndent,!0),i.map=[t,e.line],!0}},function(e,t,r){"use strict";e.exports=function(e,t,r,n){var o,i,a,s,u,c,l,f=!1,d=e.bMarks[t]+e.tShift[t],p=e.eMarks[t];if(e.sCount[t]-e.blkIndent>=4)return!1;if(d+3>p)return!1;if(126!==(o=e.src.charCodeAt(d))&&96!==o)return!1;if(u=d,(i=(d=e.skipChars(d,o))-u)<3)return!1;if(l=e.src.slice(u,d),(a=e.src.slice(d,p)).indexOf(String.fromCharCode(o))>=0)return!1;if(n)return!0;for(s=t;!(++s>=r)&&!((d=u=e.bMarks[s]+e.tShift[s])<(p=e.eMarks[s])&&e.sCount[s] New message with Markdown! New message with Markdown! New message with Markdown! New message with Markdown!w((u-r)/(b=n+1))&&j("overflow"),r+=(s-t)*b,t=s,a=0;a]*src="[^"<>]*"[^<>]*)\\s?\\/?>',"i"),s=/^(?:https?:)?\/\//i,u=/^(?:https?:\/\/|ftp:\/\/|\/\/|mailto:|xmpp:)/i,c=void 0!==(t=t||{}).removeUnknown&&t.removeUnknown,l=void 0!==t.removeUnbalanced&&t.removeUnbalanced,f=void 0!==t.imageClass?t.imageClass:"",d=!1,p=["a","b","blockquote","code","em","h1","h2","h3","h4","h5","h6","li","ol","p","pre","s","sub","sup","strong","ul"],h=new Array(p.length),g=new Array(p.length);for(r=0;r
':'
':(y=p.indexOf("a"),(t=e.match(i))&&(n=M((r=t[1]).match(/href="([^"<>]*)"/i)[1]),m=(m=r.match(/title="([^"<>]*)"/i))&&void 0!==m[1]?m[1]:"",n&&u.test(n))?(d=!0,h[y]+=1,''):(t=/<\/a>/i.test(e))?(d=!0,h[y]-=1,h[y]<0&&(g[y]=!0),""):(t=e.match(/<(br|hr)\s?\/?>/i))?"<"+t[1].toLowerCase()+">":(t=e.match(/<(\/?)(b|blockquote|code|em|h[1-6]|li|ol(?: start="\d+")?|p|pre|s|sub|sup|strong|ul)>/i))&&!/<\/ol start="\d+"/i.test(e)?(d=!0,y=p.indexOf(t[2].toLowerCase().split(" ")[0]),"/"===t[1]?h[y]-=1:h[y]+=1,h[y]<0&&(g[y]=!0),"<"+t[1]+t[2].toLowerCase()+">"):!0===c?"":o(e))})}e.core.ruler.after("linkify","sanitize_inline",function(e){var t,n,o;for(r=0;r
/g:RegExp("<"+t+">","g"),n=RegExp(""+t+">","g"),e=!0===l?(e=e.replace(r,"")).replace(n,""):(e=e.replace(r,function(e){return o(e)})).replace(n,function(e){return o(e)})}function a(e){var t;for(t=0;t
diff --git a/src/components/Widget/components/Conversation/components/Header/style.scss b/src/components/Widget/components/Conversation/components/Header/style.scss
index 9688c89fd..848866ec9 100644
--- a/src/components/Widget/components/Conversation/components/Header/style.scss
+++ b/src/components/Widget/components/Conversation/components/Header/style.scss
@@ -1,12 +1,12 @@
-@import 'variables/colors';
-@import 'common';
+@use 'variables/colors';
+@use 'common';
.rcw-conversation-container {
.rcw-header {
- background-color: $turqois-1;
+ background-color: colors.$turqois-1;
border-radius: 10px 10px 0 0;
- color: $white;
+ color: colors.$white;
display: flex;
flex-direction: column;
text-align: center;
@@ -35,19 +35,19 @@
.rcw-full-screen {
.rcw-header {
- @include header-fs;
+ @include common.header-fs;
}
.rcw-title {
- @include title-fs;
+ @include common.title-fs;
}
.rcw-close-button {
- @include close-button-fs;
+ @include common.close-button-fs;
}
.rcw-close {
- @include close-fs;
+ @include common.close-fs;
}
}
@@ -56,19 +56,19 @@
.rcw-conversation-container {
.rcw-header {
- @include header-fs;
+ @include common.header-fs;
}
.rcw-title {
- @include title-fs;
+ @include common.title-fs;
}
.rcw-close-button {
- @include close-button-fs;
+ @include common.close-button-fs;
}
.rcw-close {
- @include close-fs;
+ @include common.close-fs;
}
}
}
diff --git a/src/components/Widget/components/Conversation/components/Messages/components/Loader/index.tsx b/src/components/Widget/components/Conversation/components/Messages/components/Loader/index.tsx
index 0e621ce41..e7ae301b5 100644
--- a/src/components/Widget/components/Conversation/components/Messages/components/Loader/index.tsx
+++ b/src/components/Widget/components/Conversation/components/Messages/components/Loader/index.tsx
@@ -1,7 +1,8 @@
import cn from 'classnames';
-
+import React from 'react';
import './styles.scss';
+
type Props = {
typing: boolean;
}
diff --git a/src/components/Widget/components/Conversation/components/Messages/components/Loader/styles.scss b/src/components/Widget/components/Conversation/components/Messages/components/Loader/styles.scss
index 49c6eee5a..a2374a394 100644
--- a/src/components/Widget/components/Conversation/components/Messages/components/Loader/styles.scss
+++ b/src/components/Widget/components/Conversation/components/Messages/components/Loader/styles.scss
@@ -1,4 +1,4 @@
-@import 'variables/colors';
+@use 'variables/colors';
.loader {
margin: 10px;
@@ -10,7 +10,7 @@
}
.loader-container {
- background-color: $grey-2;
+ background-color: colors.$grey-2;
border-radius: 10px;
padding: 15px;
max-width: 215px;
@@ -22,7 +22,7 @@
height: 4px;
width: 4px;
border-radius: 50%;
- background: $grey-0;
+ background: colors.$grey-0;
margin-right: 2px;
animation: bounce 0.5s ease infinite alternate;
diff --git a/src/components/Widget/components/Conversation/components/Messages/components/Message/index.tsx b/src/components/Widget/components/Conversation/components/Messages/components/Message/index.tsx
index a28f7031e..2af61c713 100644
--- a/src/components/Widget/components/Conversation/components/Messages/components/Message/index.tsx
+++ b/src/components/Widget/components/Conversation/components/Messages/components/Message/index.tsx
@@ -1,33 +1,29 @@
-import format from 'date-fns/format';
-import markdownIt from 'markdown-it';
-import markdownItSup from 'markdown-it-sup';
-import markdownItSanitizer from 'markdown-it-sanitizer';
-import markdownItClass from '@toycode/markdown-it-class';
-import markdownItLinkAttributes from 'markdown-it-link-attributes';
+import { format } from 'date-fns';
+import MarkdownIt from 'markdown-it';
+import React from 'react';
+import { MessageOrigin } from '../../../../../../../../constants';
+import { MessageTypes } from '../../../../../../../../store/types';
+import './styles.scss';
-import { MessageTypes } from 'src/store/types';
-import './styles.scss';
type Props = {
message: MessageTypes;
showTimeStamp: boolean;
+ timestampFormat: string;
}
-function Message({ message, showTimeStamp }: Props) {
- const sanitizedHTML = markdownIt({ break: true })
- .use(markdownItClass, {
- img: ['rcw-message-img']
- })
- .use(markdownItSup)
- .use(markdownItSanitizer)
- .use(markdownItLinkAttributes, { attrs: { target: '_blank', rel: 'noopener' } })
+function Message({ message, showTimeStamp, timestampFormat }: Props) {
+ const sanitizedHTML = new MarkdownIt("default", { linkify: false })
.render(message.text);
-
+ const isClient = (origin: MessageOrigin) => origin === MessageOrigin.client;
return (
-
}
diff --git a/src/components/Widget/components/Conversation/components/Messages/styles.scss b/src/components/Widget/components/Conversation/components/Messages/styles.scss
index da6eb3c60..aa9d22e6f 100644
--- a/src/components/Widget/components/Conversation/components/Messages/styles.scss
+++ b/src/components/Widget/components/Conversation/components/Messages/styles.scss
@@ -1,8 +1,8 @@
-@import 'variables/colors';
-@import 'common';
+@use 'variables/colors';
+@use 'common';
.rcw-messages-container {
- background-color: $white;
+ background-color: colors.$white;
height: 50vh;
max-height: 410px;
overflow-y: scroll;
@@ -13,12 +13,12 @@
.rcw-full-screen {
.rcw-messages-container {
- @include messages-container-fs;
+ @include common.messages-container-fs;
}
}
@media screen and (max-width: 800px) {
.rcw-messages-container {
- @include messages-container-fs;
+ @include common.messages-container-fs;
}
}
diff --git a/src/components/Widget/components/Conversation/components/Messages/test/index.test.js b/src/components/Widget/components/Conversation/components/Messages/test/index.test.tsx
similarity index 61%
rename from src/components/Widget/components/Conversation/components/Messages/test/index.test.js
rename to src/components/Widget/components/Conversation/components/Messages/test/index.test.tsx
index f2ada3f9e..ce83a764a 100644
--- a/src/components/Widget/components/Conversation/components/Messages/test/index.test.js
+++ b/src/components/Widget/components/Conversation/components/Messages/test/index.test.tsx
@@ -1,29 +1,30 @@
-import { mount, configure } from 'enzyme';
-import { Provider } from 'react-redux'
-import Adapter from '@wojtekmaj/enzyme-adapter-react-17';
-
-import { createNewMessage, createLinkSnippet, createComponentMessage } from '../../../../../../../utils/messages';
+import { configure, mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import { Provider } from 'react-redux';
+import { MessageOrigin } from '../../../../../../../constants';
+import { createComponentMessage, createLinkSnippet, createNewMessage } from '../../../../../../../utils/messages';
import { createMockStore } from '../../../../../../../utils/store';
-
-import Messages from '../index';
import Message from '../components/Message';
import Snippet from '../components/Snippet';
+import Messages from '../index';
+
configure({ adapter: new Adapter() });
describe('
/g;
-import './style.scss';
+
+interface EmojiFrag {
+ native: string;
+}
type Props = {
placeholder: string;
disabledInput: boolean;
autofocus: boolean;
- sendMessage: (event: any) => void;
+ sendMessage: (text: string) => void;
buttonAlt: string;
onPressEmoji: () => void;
onChangeSize: (event: any) => void;
onTextInputChange?: (event: any) => void;
}
-function Sender({ sendMessage, placeholder, disabledInput, autofocus, onTextInputChange, buttonAlt, onPressEmoji, onChangeSize }: Props, ref) {
+function Sender({ sendMessage, placeholder, disabledInput, autofocus, onTextInputChange, buttonAlt, onPressEmoji, onChangeSize }: Props, ref: Ref