Repository: andriiryzhkov/dash-chat-components (language: python)

Issue:
20 automate publish to pypi using GitHub actions



Discussion / hints:

Fix patch:
diff --git a/DESCRIPTION b/DESCRIPTION
deleted file mode 100644
index 73e6cad..0000000
--- a/DESCRIPTION
+++ /dev/null
@@ -1,13 +0,0 @@
-Package: dashChatComponents
-Title: Chat components for Plotly Dash
-Version: 0.0.3
-Description: Chat components for Plotly Dash
-Depends: R (>= 3.0.2)
-Imports: 
-Suggests: 
-License: MIT + file LICENSE
-URL: https://github.com/andriiryzhkov/dash-chat-components
-BugReports: https://github.com/andriiryzhkov/dash-chat-components/issues
-Encoding: UTF-8
-LazyData: true
-KeepSource: true
diff --git a/NAMESPACE b/NAMESPACE
deleted file mode 100644
index f502865..0000000
--- a/NAMESPACE
+++ /dev/null
@@ -1,12 +0,0 @@
-# AUTO GENERATED FILE - DO NOT EDIT
-
-export(Chat)
-export(ChatInput)
-export(ChatMessage)
-export(ChatMessageList)
-export(ChatMessageTyping)
-export(chat)
-export(chatMessage)
-export(chatMessageTyping)
-export(chatMessageList)
-export(chatInput)
\ No newline at end of file
diff --git a/Project.toml b/Project.toml
deleted file mode 100644
index 41ee6cb..0000000
--- a/Project.toml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-name = "DashChatComponents"
-uuid = "1b08a953-4be3-4667-9a23-ceccd6d32f49"
-authors = ["Andrii Ryzhkov <andrii.ryzhkov@gmail.com>"]
-version = "0.0.3"
-
-[deps]
-Dash = "1b08a953-4be3-4667-9a23-3db579824955"
-
-[compat]
-julia = "1.2"
-Dash = "0.1.3, 1.0"
diff --git a/R/chat.R b/R/chat.R
deleted file mode 100644
index 6c8a7e6..0000000
--- a/R/chat.R
+++ /dev/null
@@ -1,19 +0,0 @@
-# AUTO GENERATED FILE - DO NOT EDIT
-
-#' @export
-chat <- function(children=NULL, id=NULL, className=NULL, height=NULL, style=NULL, width=NULL) {
-    
-    props <- list(children=children, id=id, className=className, height=height, style=style, width=width)
-    if (length(props) > 0) {
-        props <- props[!vapply(props, is.null, logical(1))]
-    }
-    component <- list(
-        props = props,
-        type = 'Chat',
-        namespace = 'dash_chat_components',
-        propNames = c('children', 'id', 'className', 'height', 'style', 'width'),
-        package = 'dashChatComponents'
-        )
-
-    structure(component, class = c('dash_component', 'list'))
-}
diff --git a/R/chatInput.R b/R/chatInput.R
deleted file mode 100644
index 70ce43c..0000000
--- a/R/chatInput.R
+++ /dev/null
@@ -1,19 +0,0 @@
-# AUTO GENERATED FILE - DO NOT EDIT
-
-#' @export
-chatInput <- function(id=NULL, autofocus=NULL, className=NULL, debounce=NULL, disabled=NULL, maxlength=NULL, n_submit=NULL, n_submit_timestamp=NULL, persisted_props=NULL, persistence=NULL, persistence_type=NULL, placeholder=NULL, rows=NULL, style=NULL, value=NULL, value_on_submit=NULL) {
-    
-    props <- list(id=id, autofocus=autofocus, className=className, debounce=debounce, disabled=disabled, maxlength=maxlength, n_submit=n_submit, n_submit_timestamp=n_submit_timestamp, persisted_props=persisted_props, persistence=persistence, persistence_type=persistence_type, placeholder=placeholder, rows=rows, style=style, value=value, value_on_submit=value_on_submit)
-    if (length(props) > 0) {
-        props <- props[!vapply(props, is.null, logical(1))]
-    }
-    component <- list(
-        props = props,
-        type = 'ChatInput',
-        namespace = 'dash_chat_components',
-        propNames = c('id', 'autofocus', 'className', 'debounce', 'disabled', 'maxlength', 'n_submit', 'n_submit_timestamp', 'persisted_props', 'persistence', 'persistence_type', 'placeholder', 'rows', 'style', 'value', 'value_on_submit'),
-        package = 'dashChatComponents'
-        )
-
-    structure(component, class = c('dash_component', 'list'))
-}
diff --git a/R/chatMessage.R b/R/chatMessage.R
deleted file mode 100644
index 6621aa0..0000000
--- a/R/chatMessage.R
+++ /dev/null
@@ -1,19 +0,0 @@
-# AUTO GENERATED FILE - DO NOT EDIT
-
-#' @export
-chatMessage <- function(children=NULL, id=NULL, avatar=NULL, className=NULL, direction=NULL, style=NULL, timestamp=NULL) {
-    
-    props <- list(children=children, id=id, avatar=avatar, className=className, direction=direction, style=style, timestamp=timestamp)
-    if (length(props) > 0) {
-        props <- props[!vapply(props, is.null, logical(1))]
-    }
-    component <- list(
-        props = props,
-        type = 'ChatMessage',
-        namespace = 'dash_chat_components',
-        propNames = c('children', 'id', 'avatar', 'className', 'direction', 'style', 'timestamp'),
-        package = 'dashChatComponents'
-        )
-
-    structure(component, class = c('dash_component', 'list'))
-}
diff --git a/R/chatMessageList.R b/R/chatMessageList.R
deleted file mode 100644
index 91c45e0..0000000
--- a/R/chatMessageList.R
+++ /dev/null
@@ -1,19 +0,0 @@
-# AUTO GENERATED FILE - DO NOT EDIT
-
-#' @export
-chatMessageList <- function(children=NULL, id=NULL, avatarOutgoing=NULL, avatarReceived=NULL, className=NULL, style=NULL, timestamp=NULL) {
-    
-    props <- list(children=children, id=id, avatarOutgoing=avatarOutgoing, avatarReceived=avatarReceived, className=className, style=style, timestamp=timestamp)
-    if (length(props) > 0) {
-        props <- props[!vapply(props, is.null, logical(1))]
-    }
-    component <- list(
-        props = props,
-        type = 'ChatMessageList',
-        namespace = 'dash_chat_components',
-        propNames = c('children', 'id', 'avatarOutgoing', 'avatarReceived', 'className', 'style', 'timestamp'),
-        package = 'dashChatComponents'
-        )
-
-    structure(component, class = c('dash_component', 'list'))
-}
diff --git a/R/chatMessageTyping.R b/R/chatMessageTyping.R
deleted file mode 100644
index 92fe9d2..0000000
--- a/R/chatMessageTyping.R
+++ /dev/null
@@ -1,19 +0,0 @@
-# AUTO GENERATED FILE - DO NOT EDIT
-
-#' @export
-chatMessageTyping <- function(id=NULL, avatar=NULL, className=NULL, direction=NULL, style=NULL) {
-    
-    props <- list(id=id, avatar=avatar, className=className, direction=direction, style=style)
-    if (length(props) > 0) {
-        props <- props[!vapply(props, is.null, logical(1))]
-    }
-    component <- list(
-        props = props,
-        type = 'ChatMessageTyping',
-        namespace = 'dash_chat_components',
-        propNames = c('id', 'avatar', 'className', 'direction', 'style'),
-        package = 'dashChatComponents'
-        )
-
-    structure(component, class = c('dash_component', 'list'))
-}
diff --git a/R/internal.R b/R/internal.R
deleted file mode 100644
index d6b2e07..0000000
--- a/R/internal.R
+++ /dev/null
@@ -1,15 +0,0 @@
-.dashChatComponents_js_metadata <- function() {
-deps_metadata <- list(`dash_chat_components` = structure(list(name = "dash_chat_components",
-version = "0.0.3", src = list(href = NULL,
-file = "deps"), meta = NULL,
-script = 'dash_chat_components.js',
-stylesheet = NULL, head = NULL, attachment = NULL, package = "dashChatComponents",
-all_files = FALSE), class = "html_dependency"),
-`dash_chat_components` = structure(list(name = "dash_chat_components",
-version = "0.0.3", src = list(href = NULL,
-file = "deps"), meta = NULL,
-script = 'dash_chat_components.js.map',
-stylesheet = NULL, head = NULL, attachment = NULL, package = "dashChatComponents",
-all_files = FALSE, dynamic = TRUE), class = "html_dependency"))
-return(deps_metadata)
-}
diff --git a/dash_chat_components/Chat.py b/dash_chat_components/Chat.py
deleted file mode 100644
index 0e603ab..0000000
--- a/dash_chat_components/Chat.py
+++ /dev/null
@@ -1,44 +0,0 @@
-# AUTO GENERATED FILE - DO NOT EDIT
-
-from dash.development.base_component import Component, _explicitize_args
-
-
-class Chat(Component):
-    """A Chat component.
-Main chat container
-
-Keyword arguments:
-
-- children (a list of or a singular dash component, string or number; optional):
-    Content of the chat.
-
-- id (string; optional):
-    Unique ID to identify this component in Dash callbacks.
-
-- className (string; optional):
-    Often used with CSS to style elements with common properties.
-
-- height (number; optional):
-    Height of the chat container.
-
-- style (boolean | number | string | dict | list; optional):
-    Defines CSS styles which will override styles previously set.
-
-- width (number; optional):
-    Width of the chat container."""
-    _children_props = []
-    _base_nodes = ['children']
-    _namespace = 'dash_chat_components'
-    _type = 'Chat'
-    @_explicitize_args
-    def __init__(self, children=None, height=Component.UNDEFINED, width=Component.UNDEFINED, id=Component.UNDEFINED, className=Component.UNDEFINED, style=Component.UNDEFINED, **kwargs):
-        self._prop_names = ['children', 'id', 'className', 'height', 'style', 'width']
-        self._valid_wildcard_attributes =            []
-        self.available_properties = ['children', 'id', 'className', 'height', 'style', 'width']
-        self.available_wildcard_properties =            []
-        _explicit_args = kwargs.pop('_explicit_args')
-        _locals = locals()
-        _locals.update(kwargs)  # For wildcard attrs and excess named props
-        args = {k: _locals[k] for k in _explicit_args if k != 'children'}
-
-        super(Chat, self).__init__(children=children, **args)
diff --git a/dash_chat_components/ChatInput.py b/dash_chat_components/ChatInput.py
deleted file mode 100644
index c226207..0000000
--- a/dash_chat_components/ChatInput.py
+++ /dev/null
@@ -1,90 +0,0 @@
-# AUTO GENERATED FILE - DO NOT EDIT
-
-from dash.development.base_component import Component, _explicitize_args
-
-
-class ChatInput(Component):
-    """A ChatInput component.
-Capture chat input from user
-
-Keyword arguments:
-
-- id (string; optional):
-    Unique ID to identify this component in Dash callbacks.
-
-- autofocus (boolean; optional):
-    The element should be automatically focused after the page loaded.
-
-- className (string; optional):
-    Often used with CSS to style elements with common properties.
-
-- debounce (boolean; default False):
-    If True, changes to input will be sent back to the Dash server
-    only on enter or when losing focus. If it's False, it will sent
-    the value back on every change.
-
-- disabled (boolean; optional):
-    Indicates whether the user can interact with the element.
-
-- maxlength (number; default 4000):
-    Defines the maximum number of characters allowed in the input
-    element.
-
-- n_submit (number; default 0):
-    An integer that represents the number of times that the Enter key
-    was pressed while the input area had focus or submit button has
-    been clicked on.
-
-- n_submit_timestamp (number; default -1):
-    An integer that represents the time (in ms since 1970) at which
-    n_submit changed.
-
-- persisted_props (list of strings; default ["value"]):
-    Properties whose user interactions will persist after refreshing
-    the component or the page. Since only `value` is allowed this prop
-    can normally be ignored.
-
-- persistence (string | number; optional):
-    Used to allow user interactions in this component to be persisted
-    when the component - or the page - is refreshed. If `persisted` is
-    truthy and hasn't changed from its previous value, a `value` that
-    the user has changed while using the app will keep that change, as
-    long as the new `value` also matches what was given originally.
-    Used in conjunction with `persistence_type`.
-
-- persistence_type (a value equal to: 'local', 'session', 'memory'; default 'local'):
-    Where persisted user changes will be stored: memory: only kept in
-    memory, reset on page refresh. local: window.localStorage, data is
-    kept after the browser quit. session: window.sessionStorage, data
-    is cleared once the browser quit.
-
-- placeholder (string; default 'Type a message...'):
-    Provides a hint to the user of what can be entered in the field.
-
-- rows (number; default 2):
-    Defines the number of rows in a text input area.
-
-- style (boolean | number | string | dict | list; optional):
-    Defines CSS styles which will override styles previously set.
-
-- value (string; default ''):
-    Input value for controlled component.
-
-- value_on_submit (string; default ''):
-    Input value for controlled component after submit."""
-    _children_props = []
-    _base_nodes = ['children']
-    _namespace = 'dash_chat_components'
-    _type = 'ChatInput'
-    @_explicitize_args
-    def __init__(self, autofocus=Component.UNDEFINED, debounce=Component.UNDEFINED, disabled=Component.UNDEFINED, maxlength=Component.UNDEFINED, n_submit=Component.UNDEFINED, n_submit_timestamp=Component.UNDEFINED, placeholder=Component.UNDEFINED, rows=Component.UNDEFINED, value=Component.UNDEFINED, value_on_submit=Component.UNDEFINED, id=Component.UNDEFINED, className=Component.UNDEFINED, style=Component.UNDEFINED, persistence=Component.UNDEFINED, persisted_props=Component.UNDEFINED, persistence_type=Component.UNDEFINED, **kwargs):
-        self._prop_names = ['id', 'autofocus', 'className', 'debounce', 'disabled', 'maxlength', 'n_submit', 'n_submit_timestamp', 'persisted_props', 'persistence', 'persistence_type', 'placeholder', 'rows', 'style', 'value', 'value_on_submit']
-        self._valid_wildcard_attributes =            []
-        self.available_properties = ['id', 'autofocus', 'className', 'debounce', 'disabled', 'maxlength', 'n_submit', 'n_submit_timestamp', 'persisted_props', 'persistence', 'persistence_type', 'placeholder', 'rows', 'style', 'value', 'value_on_submit']
-        self.available_wildcard_properties =            []
-        _explicit_args = kwargs.pop('_explicit_args')
-        _locals = locals()
-        _locals.update(kwargs)  # For wildcard attrs and excess named props
-        args = {k: _locals[k] for k in _explicit_args}
-
-        super(ChatInput, self).__init__(**args)
diff --git a/dash_chat_components/ChatMessage.py b/dash_chat_components/ChatMessage.py
deleted file mode 100644
index be4fb0f..0000000
--- a/dash_chat_components/ChatMessage.py
+++ /dev/null
@@ -1,52 +0,0 @@
-# AUTO GENERATED FILE - DO NOT EDIT
-
-from dash.development.base_component import Component, _explicitize_args
-
-
-class ChatMessage(Component):
-    """A ChatMessage component.
-Display single chat message
-
-Keyword arguments:
-
-- children (a list of or a singular dash component, string or number; optional):
-    Content of the message.
-
-- id (string; optional):
-    Unique ID to identify this component in Dash callbacks.
-
-- avatar (string; default undefined):
-    Avatar.
-
-- className (string; optional):
-    Often used with CSS to style elements with common properties.
-
-- direction (string; required):
-    Direction of the mssage: received or outgoing.
-
-- style (boolean | number | string | dict | list; optional):
-    Defines CSS styles which will override styles previously set.
-
-- timestamp (number; default -1):
-    Time."""
-    _children_props = []
-    _base_nodes = ['children']
-    _namespace = 'dash_chat_components'
-    _type = 'ChatMessage'
-    @_explicitize_args
-    def __init__(self, children=None, avatar=Component.UNDEFINED, direction=Component.REQUIRED, timestamp=Component.UNDEFINED, id=Component.UNDEFINED, className=Component.UNDEFINED, style=Component.UNDEFINED, **kwargs):
-        self._prop_names = ['children', 'id', 'avatar', 'className', 'direction', 'style', 'timestamp']
-        self._valid_wildcard_attributes =            []
-        self.available_properties = ['children', 'id', 'avatar', 'className', 'direction', 'style', 'timestamp']
-        self.available_wildcard_properties =            []
-        _explicit_args = kwargs.pop('_explicit_args')
-        _locals = locals()
-        _locals.update(kwargs)  # For wildcard attrs and excess named props
-        args = {k: _locals[k] for k in _explicit_args if k != 'children'}
-
-        for k in ['direction']:
-            if k not in args:
-                raise TypeError(
-                    'Required argument `' + k + '` was not specified.')
-
-        super(ChatMessage, self).__init__(children=children, **args)
diff --git a/dash_chat_components/ChatMessageList.py b/dash_chat_components/ChatMessageList.py
deleted file mode 100644
index fdee11d..0000000
--- a/dash_chat_components/ChatMessageList.py
+++ /dev/null
@@ -1,47 +0,0 @@
-# AUTO GENERATED FILE - DO NOT EDIT
-
-from dash.development.base_component import Component, _explicitize_args
-
-
-class ChatMessageList(Component):
-    """A ChatMessageList component.
-Display list of chat messages
-
-Keyword arguments:
-
-- children (a list of or a singular dash component, string or number; optional):
-    ChatMessageList content.
-
-- id (string; optional):
-    Unique ID to identify this component in Dash callbacks.
-
-- avatarOutgoing (boolean; default False):
-    Indicates whether the outgoing message avatar should be displayed.
-
-- avatarReceived (boolean; default True):
-    Indicates whether the recieved message avatar should be displayed.
-
-- className (string; optional):
-    Often used with CSS to style elements with common properties.
-
-- style (boolean | number | string | dict | list; optional):
-    Defines CSS styles which will override styles previously set.
-
-- timestamp (boolean; default True):
-    Indicates whether the message timestamp should be displayed."""
-    _children_props = []
-    _base_nodes = ['children']
-    _namespace = 'dash_chat_components'
-    _type = 'ChatMessageList'
-    @_explicitize_args
-    def __init__(self, children=None, avatarReceived=Component.UNDEFINED, avatarOutgoing=Component.UNDEFINED, timestamp=Component.UNDEFINED, id=Component.UNDEFINED, className=Component.UNDEFINED, style=Component.UNDEFINED, **kwargs):
-        self._prop_names = ['children', 'id', 'avatarOutgoing', 'avatarReceived', 'className', 'style', 'timestamp']
-        self._valid_wildcard_attributes =            []
-        self.available_properties = ['children', 'id', 'avatarOutgoing', 'avatarReceived', 'className', 'style', 'timestamp']
-        self.available_wildcard_properties =            []
-        _explicit_args = kwargs.pop('_explicit_args')
-        _locals = locals()
-        _locals.update(kwargs)  # For wildcard attrs and excess named props
-        args = {k: _locals[k] for k in _explicit_args if k != 'children'}
-
-        super(ChatMessageList, self).__init__(children=children, **args)
diff --git a/dash_chat_components/ChatMessageTyping.py b/dash_chat_components/ChatMessageTyping.py
deleted file mode 100644
index 4c2709b..0000000
--- a/dash_chat_components/ChatMessageTyping.py
+++ /dev/null
@@ -1,46 +0,0 @@
-# AUTO GENERATED FILE - DO NOT EDIT
-
-from dash.development.base_component import Component, _explicitize_args
-
-
-class ChatMessageTyping(Component):
-    """A ChatMessageTyping component.
-Display user typing message
-
-Keyword arguments:
-
-- id (string; optional):
-    Unique ID to identify this component in Dash callbacks.
-
-- avatar (string; default undefined):
-    Avatar.
-
-- className (string; optional):
-    Often used with CSS to style elements with common properties.
-
-- direction (string; required):
-    Direction of the mssage: received or outgoing.
-
-- style (boolean | number | string | dict | list; optional):
-    Defines CSS styles which will override styles previously set."""
-    _children_props = []
-    _base_nodes = ['children']
-    _namespace = 'dash_chat_components'
-    _type = 'ChatMessageTyping'
-    @_explicitize_args
-    def __init__(self, avatar=Component.UNDEFINED, direction=Component.REQUIRED, id=Component.UNDEFINED, className=Component.UNDEFINED, style=Component.UNDEFINED, **kwargs):
-        self._prop_names = ['id', 'avatar', 'className', 'direction', 'style']
-        self._valid_wildcard_attributes =            []
-        self.available_properties = ['id', 'avatar', 'className', 'direction', 'style']
-        self.available_wildcard_properties =            []
-        _explicit_args = kwargs.pop('_explicit_args')
-        _locals = locals()
-        _locals.update(kwargs)  # For wildcard attrs and excess named props
-        args = {k: _locals[k] for k in _explicit_args}
-
-        for k in ['direction']:
-            if k not in args:
-                raise TypeError(
-                    'Required argument `' + k + '` was not specified.')
-
-        super(ChatMessageTyping, self).__init__(**args)
diff --git a/dash_chat_components/_imports_.py b/dash_chat_components/_imports_.py
deleted file mode 100644
index 6c91599..0000000
--- a/dash_chat_components/_imports_.py
+++ /dev/null
@@ -1,13 +0,0 @@
-from .Chat import Chat
-from .ChatInput import ChatInput
-from .ChatMessage import ChatMessage
-from .ChatMessageList import ChatMessageList
-from .ChatMessageTyping import ChatMessageTyping
-
-__all__ = [
-    "Chat",
-    "ChatInput",
-    "ChatMessage",
-    "ChatMessageList",
-    "ChatMessageTyping"
-]
\ No newline at end of file
diff --git a/dash_chat_components/dash_chat_components.js b/dash_chat_components/dash_chat_components.js
deleted file mode 100644
index b548a29..0000000
--- a/dash_chat_components/dash_chat_components.js
+++ /dev/null
@@ -1,2 +0,0 @@
-/*! For license information please see dash_chat_components.js.LICENSE.txt */
-!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("react")):"function"==typeof define&&define.amd?define(["react"],t):"object"==typeof exports?exports.dash_chat_components=t(require("react")):e.dash_chat_components=t(e.React)}(self,(e=>(()=>{var t={184:(e,t)=>{var n;!function(){"use strict";var a={}.hasOwnProperty;function r(){for(var e=[],t=0;t<arguments.length;t++){var n=arguments[t];if(n){var i=typeof n;if("string"===i||"number"===i)e.push(n);else if(Array.isArray(n)){if(n.length){var o=r.apply(null,n);o&&e.push(o)}}else if("object"===i){if(n.toString!==Object.prototype.toString&&!n.toString.toString().includes("[native code]")){e.push(n.toString());continue}for(var s in n)a.call(n,s)&&n[s]&&e.push(s)}}}return e.join(" ")}e.exports?(r.default=r,e.exports=r):void 0===(n=function(){return r}.apply(t,[]))||(e.exports=n)}()},588:(e,t,n)=>{"use strict";n.d(t,{Z:()=>s});var a=n(81),r=n.n(a),i=n(645),o=n.n(i)()(r());o.push([e.id,".chat-message-received + .chat-message-outgoing,\n.chat-message-outgoing + .chat-message-received {\n  margin-top: 10px;\n}\n\n.chat-message-received + .chat-message-received .chat-message-avatar,\n.chat-message-outgoing + .chat-message-outgoing .chat-message-avatar {\n  visibility: collapse;\n}\n\n.chat-message-received:has(+ .chat-message-received) .chat-message-time,\n.chat-message-outgoing:has(+ .chat-message-outgoing) .chat-message-time {\n  display: none;\n}\n\n.avatar-received-none .chat-message-avatar-container-received {\n  display: none;\n}\n\n.avatar-outgoing-none .chat-message-avatar-container-outgoing {\n  display: none;\n}\n\n.timestamp-none .chat-message-time {\n  display: none;\n}\n",""]);const s=o},26:(e,t,n)=>{"use strict";n.d(t,{Z:()=>s});var a=n(81),r=n.n(a),i=n(645),o=n.n(i)()(r());o.push([e.id,".typing {\n    height: 16px;\n    position: relative;\n    padding: 4px;\n}\n\n.typing__dot {\n    float: left;\n    width: 8px;\n    height: 8px;\n    margin: 0 4px;\n    background: #8d8c91;\n    border-radius: 50%;\n    opacity: 0;\n    animation: loadingFade 1s infinite;\n}\n\n.typing__dot:nth-child(1) {\n    animation-delay: 0s;\n}\n\n.typing__dot:nth-child(2) {\n    animation-delay: 0.2s;\n}\n\n.typing__dot:nth-child(3) {\n    animation-delay: 0.4s;\n}\n\n@keyframes loadingFade {\n    0% {\n        opacity: 0;\n    }\n\n    50% {\n        opacity: 0.8;\n    }\n\n    100% {\n        opacity: 0;\n    }\n}",""]);const s=o},645:e=>{"use strict";e.exports=function(e){var t=[];return t.toString=function(){return this.map((function(t){var n="",a=void 0!==t[5];return t[4]&&(n+="@supports (".concat(t[4],") {")),t[2]&&(n+="@media ".concat(t[2]," {")),a&&(n+="@layer".concat(t[5].length>0?" ".concat(t[5]):""," {")),n+=e(t),a&&(n+="}"),t[2]&&(n+="}"),t[4]&&(n+="}"),n})).join("")},t.i=function(e,n,a,r,i){"string"==typeof e&&(e=[[null,e,void 0]]);var o={};if(a)for(var s=0;s<this.length;s++){var c=this[s][0];null!=c&&(o[c]=!0)}for(var l=0;l<e.length;l++){var u=[].concat(e[l]);a&&o[u[0]]||(void 0!==i&&(void 0===u[5]||(u[1]="@layer".concat(u[5].length>0?" ".concat(u[5]):""," {").concat(u[1],"}")),u[5]=i),n&&(u[2]?(u[1]="@media ".concat(u[2]," {").concat(u[1],"}"),u[2]=n):u[2]=n),r&&(u[4]?(u[1]="@supports (".concat(u[4],") {").concat(u[1],"}"),u[4]=r):u[4]="".concat(r)),t.push(u))}},t}},81:e=>{"use strict";e.exports=function(e){return e[1]}},713:(e,t,n)=>{"use strict";n.r(t),n.d(t,{default:()=>v});var a=n(379),r=n.n(a),i=n(795),o=n.n(i),s=n(565),c=n.n(s),l=n(216),u=n.n(l),d=n(589),f=n.n(d),p=n(588),m={};m.styleTagTransform=f(),m.setAttributes=c(),m.insert=function(e){var t=document.querySelector("head"),n=window._lastElementInsertedByStyleLoader;n?n.nextSibling?t.insertBefore(e,n.nextSibling):t.appendChild(e):t.insertBefore(e,t.firstChild),window._lastElementInsertedByStyleLoader=e},m.domAPI=o(),m.insertStyleElement=u(),r()(p.Z,m);const v=p.Z&&p.Z.locals?p.Z.locals:void 0},811:(e,t,n)=>{"use strict";n.r(t),n.d(t,{default:()=>v});var a=n(379),r=n.n(a),i=n(795),o=n.n(i),s=n(565),c=n.n(s),l=n(216),u=n.n(l),d=n(589),f=n.n(d),p=n(26),m={};m.styleTagTransform=f(),m.setAttributes=c(),m.insert=function(e){var t=document.querySelector("head"),n=window._lastElementInsertedByStyleLoader;n?n.nextSibling?t.insertBefore(e,n.nextSibling):t.appendChild(e):t.insertBefore(e,t.firstChild),window._lastElementInsertedByStyleLoader=e},m.domAPI=o(),m.insertStyleElement=u(),r()(p.Z,m);const v=p.Z&&p.Z.locals?p.Z.locals:void 0},379:e=>{"use strict";var t=[];function n(e){for(var n=-1,a=0;a<t.length;a++)if(t[a].identifier===e){n=a;break}return n}function a(e,a){for(var i={},o=[],s=0;s<e.length;s++){var c=e[s],l=a.base?c[0]+a.base:c[0],u=i[l]||0,d="".concat(l," ").concat(u);i[l]=u+1;var f=n(d),p={css:c[1],media:c[2],sourceMap:c[3],supports:c[4],layer:c[5]};if(-1!==f)t[f].references++,t[f].updater(p);else{var m=r(p,a);a.byIndex=s,t.splice(s,0,{identifier:d,updater:m,references:1})}o.push(d)}return o}function r(e,t){var n=t.domAPI(t);return n.update(e),function(t){if(t){if(t.css===e.css&&t.media===e.media&&t.sourceMap===e.sourceMap&&t.supports===e.supports&&t.layer===e.layer)return;n.update(e=t)}else n.remove()}}e.exports=function(e,r){var i=a(e=e||[],r=r||{});return function(e){e=e||[];for(var o=0;o<i.length;o++){var s=n(i[o]);t[s].references--}for(var c=a(e,r),l=0;l<i.length;l++){var u=n(i[l]);0===t[u].references&&(t[u].updater(),t.splice(u,1))}i=c}}},216:e=>{"use strict";e.exports=function(e){var t=document.createElement("style");return e.setAttributes(t,e.attributes),e.insert(t,e.options),t}},565:(e,t,n)=>{"use strict";e.exports=function(e){var t=n.nc;t&&e.setAttribute("nonce",t)}},795:e=>{"use strict";e.exports=function(e){if("undefined"==typeof document)return{update:function(){},remove:function(){}};var t=e.insertStyleElement(e);return{update:function(n){!function(e,t,n){var a="";n.supports&&(a+="@supports (".concat(n.supports,") {")),n.media&&(a+="@media ".concat(n.media," {"));var r=void 0!==n.layer;r&&(a+="@layer".concat(n.layer.length>0?" ".concat(n.layer):""," {")),a+=n.css,r&&(a+="}"),n.media&&(a+="}"),n.supports&&(a+="}");var i=n.sourceMap;i&&"undefined"!=typeof btoa&&(a+="\n/*# sourceMappingURL=data:application/json;base64,".concat(btoa(unescape(encodeURIComponent(JSON.stringify(i))))," */")),t.styleTagTransform(a,e,t.options)}(t,e,n)},remove:function(){!function(e){if(null===e.parentNode)return!1;e.parentNode.removeChild(e)}(t)}}}},589:e=>{"use strict";e.exports=function(e,t){if(t.styleSheet)t.styleSheet.cssText=e;else{for(;t.firstChild;)t.removeChild(t.firstChild);t.appendChild(document.createTextNode(e))}}},91:function(e,t,n){"use strict";var a=this&&this.__assign||function(){return a=Object.assign||function(e){for(var t,n=1,a=arguments.length;n<a;n++)for(var r in t=arguments[n])Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r]);return e},a.apply(this,arguments)},r=this&&this.__rest||function(e,t){var n={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&t.indexOf(a)<0&&(n[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var r=0;for(a=Object.getOwnPropertySymbols(e);r<a.length;r++)t.indexOf(a[r])<0&&Object.prototype.propertyIsEnumerable.call(e,a[r])&&(n[a[r]]=e[a[r]])}return n},i=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};t.__esModule=!0;var o=i(n(812)),s=function(e){e.setProps;var t=e.id,n=e.children,i=e.height,s=(e.width,r(e,["setProps","id","children","height","width"]));return o.default.createElement("div",a({id:t,style:{height:i}},s),n)};s.defaultProps={},t.default=s},806:function(e,t,n){"use strict";var a=this&&this.__assign||function(){return a=Object.assign||function(e){for(var t,n=1,a=arguments.length;n<a;n++)for(var r in t=arguments[n])Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r]);return e},a.apply(this,arguments)},r=this&&this.__createBinding||(Object.create?function(e,t,n,a){void 0===a&&(a=n);var r=Object.getOwnPropertyDescriptor(t,n);r&&!("get"in r?!t.__esModule:r.writable||r.configurable)||(r={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,a,r)}:function(e,t,n,a){void 0===a&&(a=n),e[a]=t[n]}),i=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),o=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)"default"!==n&&Object.prototype.hasOwnProperty.call(e,n)&&r(t,e,n);return i(t,e),t},s=this&&this.__rest||function(e,t){var n={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&t.indexOf(a)<0&&(n[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var r=0;for(a=Object.getOwnPropertySymbols(e);r<a.length;r++)t.indexOf(a[r])<0&&Object.prototype.propertyIsEnumerable.call(e,a[r])&&(n[a[r]]=e[a[r]])}return n},c=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};t.__esModule=!0;var l=o(n(812)),u=c(n(184)),d=function(e){var t=e.setProps,n=e.id,r=e.className,i=e.value,o=e.autofocus,c=e.debounce,d=e.disabled,f=e.maxlength,p=e.n_submit,m=(e.n_submit_timestamp,e.value_on_submit,e.placeholder),v=(e.persistence,e.persisted_props,e.persistence_type,e.rows),h=s(e,["setProps","id","className","value","autofocus","debounce","disabled","maxlength","n_submit","n_submit_timestamp","value_on_submit","placeholder","persistence","persisted_props","persistence_type","rows"]),g=(0,l.useRef)(null),y=(0,l.useState)(i||void 0),_=y[0],b=y[1],O=(0,u.default)("position-relative",r),w=(0,u.default)("form-control"),x=(0,u.default)("btn btn-outline-primary border-0 position-absolute bottom-0 end-0 m-1 rounded-4");return(0,l.useEffect)((function(){o&&g.current.focus()}),[d]),(0,l.useEffect)((function(){i!==_&&b(i||void 0)}),[i]),l.default.createElement("div",a({id:n,className:O},h),l.default.createElement("textarea",{ref:g,className:w,onChange:function(e){var n=e.target.value;b(n),!c&&t&&t({value:n})},onBlur:function(){c&&t&&t({value:g.current.value})},onKeyDown:function(e){if(t&&"Enter"===e.key&&!1===e.altKey&&!1===e.shiftKey){e.preventDefault();var n={n_submit:p+1,n_submit_timestamp:Date.now(),value_on_submit:g.current.value,value:void 0};b(void 0),t(n)}},autoFocus:o,disabled:d,maxLength:f,rows:v,placeholder:m,style:{paddingRight:"50px"},value:i}),l.default.createElement("button",{type:"button",onClick:function(){if(t){var e={n_submit:p+1,n_submit_timestamp:Date.now(),value_on_submit:g.current.value,value:void 0};b(void 0),t(e)}},disabled:d,className:x},l.default.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",width:"16",height:"16",fill:"currentColor",viewBox:"0 0 16 16"},l.default.createElement("path",{d:"M15.964.686a.5.5 0 0 0-.65-.65L.767 5.855H.766l-.452.18a.5.5 0 0 0-.082.887l.41.26.001.002 4.995 3.178 3.178 4.995.002.002.26.41a.5.5 0 0 0 .886-.083l6-15Zm-1.833 1.89L6.637 10.07l-.215-.338a.5.5 0 0 0-.154-.154l-.338-.215 7.494-7.494 1.178-.471-.47 1.178Z"}))))};d.defaultProps={value:"",placeholder:"Type a message...",debounce:!1,maxlength:4e3,n_clicks:0,n_clicks_timestamp:-1,n_submit:0,n_submit_timestamp:-1,value_on_submit:"",persisted_props:["value"],persistence_type:"local",rows:2},t.default=d},472:function(e,t,n){"use strict";var a=this&&this.__assign||function(){return a=Object.assign||function(e){for(var t,n=1,a=arguments.length;n<a;n++)for(var r in t=arguments[n])Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r]);return e},a.apply(this,arguments)},r=this&&this.__createBinding||(Object.create?function(e,t,n,a){void 0===a&&(a=n);var r=Object.getOwnPropertyDescriptor(t,n);r&&!("get"in r?!t.__esModule:r.writable||r.configurable)||(r={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,a,r)}:function(e,t,n,a){void 0===a&&(a=n),e[a]=t[n]}),i=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),o=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)"default"!==n&&Object.prototype.hasOwnProperty.call(e,n)&&r(t,e,n);return i(t,e),t},s=this&&this.__rest||function(e,t){var n={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&t.indexOf(a)<0&&(n[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var r=0;for(a=Object.getOwnPropertySymbols(e);r<a.length;r++)t.indexOf(a[r])<0&&Object.prototype.propertyIsEnumerable.call(e,a[r])&&(n[a[r]]=e[a[r]])}return n},c=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};t.__esModule=!0;var l=o(n(812));n(713);var u=c(n(184)),d=n(605),f=function(e){var t=e.src,n=e.direction,a=e.className,r=(0,l.useState)(!1),i=r[0],o=r[1],s=(0,u.default)("rounded-circle","bg-light","d-flex","justify-content-center","align-items-center",a),c=(0,u.default)("rounded-circle",a);return i?l.default.createElement("div",{style:{width:45,height:45},className:s},l.default.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",width:"25",height:"25",fill:"currentColor",viewBox:"0 0 16 16"},"received"===n?l.default.createElement(l.default.Fragment,null,l.default.createElement("path",{d:"M6 12.5a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1-.5-.5ZM3 8.062C3 6.76 4.235 5.765 5.53 5.886a26.58 26.58 0 0 0 4.94 0C11.765 5.765 13 6.76 13 8.062v1.157a.933.933 0 0 1-.765.935c-.845.147-2.34.346-4.235.346-1.895 0-3.39-.2-4.235-.346A.933.933 0 0 1 3 9.219V8.062Zm4.542-.827a.25.25 0 0 0-.217.068l-.92.9a24.767 24.767 0 0 1-1.871-.183.25.25 0 0 0-.068.495c.55.076 1.232.149 2.02.193a.25.25 0 0 0 .189-.071l.754-.736.847 1.71a.25.25 0 0 0 .404.062l.932-.97a25.286 25.286 0 0 0 1.922-.188.25.25 0 0 0-.068-.495c-.538.074-1.207.145-1.98.189a.25.25 0 0 0-.166.076l-.754.785-.842-1.7a.25.25 0 0 0-.182-.135Z"}),l.default.createElement("path",{d:"M8.5 1.866a1 1 0 1 0-1 0V3h-2A4.5 4.5 0 0 0 1 7.5V8a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1v1a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2v-1a1 1 0 0 0 1-1V9a1 1 0 0 0-1-1v-.5A4.5 4.5 0 0 0 10.5 3h-2V1.866ZM14 7.5V13a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V7.5A3.5 3.5 0 0 1 5.5 4h5A3.5 3.5 0 0 1 14 7.5Z"})):l.default.createElement("path",{d:"M8 8a3 3 0 1 0 0-6 3 3 0 0 0 0 6Zm2-3a2 2 0 1 1-4 0 2 2 0 0 1 4 0Zm4 8c0 1-1 1-1 1H3s-1 0-1-1 1-4 6-4 6 3 6 4Zm-1-.004c-.001-.246-.154-.986-.832-1.664C11.516 10.68 10.289 10 8 10c-2.29 0-3.516.68-4.168 1.332-.678.678-.83 1.418-.832 1.664h10Z"}))):l.default.createElement("img",{src:t,width:45,height:45,className:c,onError:function(){o(!0)}})},p=function(e){e.setProps;var t=e.children,n=e.id,r=e.avatar,i=e.className,o=e.direction,c=e.timestamp,p=s(e,["setProps","children","id","avatar","className","direction","timestamp"]),m=(0,u.default)("chat-message","chat-message-".concat(o),"d-flex","justify-content-end",i,{"flex-row-reverse":"received"===o,"flex-row":"outgoing"===o}),v=(0,u.default)("mb-1","mw-75","d-flex","flex-column",{"align-items-start":"received"===o,"align-items-end":"outgoing"===o}),h=(0,u.default)("chat-message-content","small","rounded-3","p-3","mb-1","text-break",i,{"bg-secondary-subtle":"received"===o,"bg-primary text-white":"outgoing"===o}),g=(0,u.default)("chat-message-time","small","mb-2","text-muted",i,{"text-start":"received"===o,"text-end":"outgoing"===o,"d-none":-1===c}),y=(0,u.default)({"chat-message-avatar-container-received":"received"===o,"chat-message-avatar-container-outgoing":"outgoing"===o}),_=(0,u.default)("chat-message-avatar","chat-message-avatar-".concat(o),"mb-2","text-muted",i,{"d-none":void 0===r,"float-start":"received"===o,"float-end":"outgoing"===o});return l.default.createElement("div",a({id:n,className:m},p),l.default.createElement("div",{className:v,style:{maxWidth:"75%"}},l.default.createElement("div",{className:h},t),l.default.createElement("p",{className:g},(0,d.formatTimestamp)(c))),l.default.createElement("div",{className:y,style:void 0!==r?{width:"53px"}:{}},l.default.createElement(f,{src:r,direction:o,className:_})))};p.defaultProps={avatar:void 0,timestamp:-1},t.default=p},777:function(e,t,n){"use strict";var a=this&&this.__assign||function(){return a=Object.assign||function(e){for(var t,n=1,a=arguments.length;n<a;n++)for(var r in t=arguments[n])Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r]);return e},a.apply(this,arguments)},r=this&&this.__createBinding||(Object.create?function(e,t,n,a){void 0===a&&(a=n);var r=Object.getOwnPropertyDescriptor(t,n);r&&!("get"in r?!t.__esModule:r.writable||r.configurable)||(r={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,a,r)}:function(e,t,n,a){void 0===a&&(a=n),e[a]=t[n]}),i=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),o=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)"default"!==n&&Object.prototype.hasOwnProperty.call(e,n)&&r(t,e,n);return i(t,e),t},s=this&&this.__rest||function(e,t){var n={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&t.indexOf(a)<0&&(n[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var r=0;for(a=Object.getOwnPropertySymbols(e);r<a.length;r++)t.indexOf(a[r])<0&&Object.prototype.propertyIsEnumerable.call(e,a[r])&&(n[a[r]]=e[a[r]])}return n},c=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};t.__esModule=!0;var l=o(n(812)),u=c(n(184)),d=function(e){e.setProps;var t=e.children,n=e.id,r=e.className,i=e.avatarReceived,o=e.avatarOutgoing,c=e.timestamp,d=s(e,["setProps","children","id","className","avatarReceived","avatarOutgoing","timestamp"]),f=(0,l.useRef)(null),p=(0,u.default)("vstack","w-100","position-relative","overflow-auto",r,{"avatar-received-none":!i,"avatar-outgoing-none":!o,"timestamp-none":!c});return(0,l.useEffect)((function(){var e,t;null==(t=null===(e=f.current)||void 0===e?void 0:e.lastElementChild)||t.scrollIntoView({behavior:"instant"})}),[t]),l.default.createElement("div",a({id:n,ref:f,className:p},d),t)};d.defaultProps={avatarReceived:!0,avatarOutgoing:!1,timestamp:!0},t.default=d},991:function(e,t,n){"use strict";var a=this&&this.__rest||function(e,t){var n={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&t.indexOf(a)<0&&(n[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var r=0;for(a=Object.getOwnPropertySymbols(e);r<a.length;r++)t.indexOf(a[r])<0&&Object.prototype.propertyIsEnumerable.call(e,a[r])&&(n[a[r]]=e[a[r]])}return n},r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};t.__esModule=!0;var i=r(n(812));n(713),n(811);var o=r(n(472)),s=function(e){var t=e.setProps,n=(e.id,e.avatar),r=e.className,s=e.direction;return a(e,["setProps","id","avatar","className","direction"]),i.default.createElement(o.default,{setProps:t,avatar:n,direction:s,className:r},i.default.createElement("div",{className:"typing"},i.default.createElement("div",{className:"typing__dot"}),i.default.createElement("div",{className:"typing__dot"}),i.default.createElement("div",{className:"typing__dot"})))};s.defaultProps={avatar:void 0,timestamp:-1},t.default=s},294:function(e,t,n){"use strict";var a=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};t.__esModule=!0,t.ChatMessageTyping=t.ChatMessageList=t.ChatMessage=t.ChatInput=t.Chat=void 0;var r=a(n(91));t.Chat=r.default;var i=a(n(806));t.ChatInput=i.default;var o=a(n(472));t.ChatMessage=o.default;var s=a(n(777));t.ChatMessageList=s.default;var c=a(n(991));t.ChatMessageTyping=c.default},605:(e,t)=>{"use strict";t.__esModule=!0,t.formatTimestamp=void 0,t.formatTimestamp=function(e,t){void 0===t&&(t="en-GB");var n=new Date(e),a={year:"numeric",month:"numeric",day:"numeric"};return new Intl.DateTimeFormat(t,a).format(n)===new Intl.DateTimeFormat(t,a).format(new Date)?new Intl.DateTimeFormat(t,{hour:"numeric",minute:"numeric"}).format(n):new Intl.DateTimeFormat(t,{year:"numeric",month:"short",day:"numeric",hour:"numeric",minute:"numeric"}).format(n)}},812:t=>{"use strict";t.exports=e}},n={};function a(e){var r=n[e];if(void 0!==r)return r.exports;var i=n[e]={id:e,exports:{}};return t[e].call(i.exports,i,i.exports,a),i.exports}return a.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return a.d(t,{a:t}),t},a.d=(e,t)=>{for(var n in t)a.o(t,n)&&!a.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},a.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),a.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},a.nc=void 0,a(294)})()));
\ No newline at end of file
diff --git a/dash_chat_components/dash_chat_components.js.LICENSE.txt b/dash_chat_components/dash_chat_components.js.LICENSE.txt
deleted file mode 100644
index 827f273..0000000
--- a/dash_chat_components/dash_chat_components.js.LICENSE.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-/*!
-	Copyright (c) 2018 Jed Watson.
-	Licensed under the MIT License (MIT), see
-	http://jedwatson.github.io/classnames
-*/
diff --git a/dash_chat_components/metadata.json b/dash_chat_components/metadata.json
deleted file mode 100644
index 9b0b7d1..0000000
--- a/dash_chat_components/metadata.json
+++ /dev/null
@@ -1,497 +0,0 @@
-{
-  "src/ts/components/Chat.tsx": {
-    "displayName": "Chat",
-    "description": "Main chat container",
-    "props": {
-      "children": {
-        "description": "Content of the chat",
-        "required": false,
-        "type": {
-          "name": "node",
-          "raw": "ReactNode"
-        }
-      },
-      "height": {
-        "description": "Height of the chat container",
-        "required": false,
-        "type": {
-          "name": "number",
-          "raw": "number"
-        }
-      },
-      "width": {
-        "description": "Width of the chat container",
-        "required": false,
-        "type": {
-          "name": "number",
-          "raw": "number"
-        }
-      },
-      "id": {
-        "description": "Unique ID to identify this component in Dash callbacks.",
-        "required": false,
-        "type": {
-          "name": "string",
-          "raw": "string"
-        }
-      },
-      "className": {
-        "description": "Often used with CSS to style elements with common properties.",
-        "required": false,
-        "type": {
-          "name": "string",
-          "raw": "string"
-        }
-      },
-      "style": {
-        "description": "Defines CSS styles which will override styles previously set.",
-        "required": false,
-        "type": {
-          "name": "any",
-          "raw": "any"
-        }
-      },
-      "setProps": {
-        "description": "Update props to trigger callbacks.",
-        "required": true,
-        "type": {
-          "name": "func",
-          "raw": "(props: Record<string, any>) => void"
-        }
-      }
-    },
-    "isContext": false
-  },
-  "src/ts/components/ChatInput.tsx": {
-    "displayName": "ChatInput",
-    "description": "Capture chat input from user",
-    "props": {
-      "autofocus": {
-        "description": "The element should be automatically focused after the page loaded.",
-        "required": false,
-        "type": {
-          "name": "bool",
-          "raw": "boolean"
-        }
-      },
-      "debounce": {
-        "description": "If True, changes to input will be sent back to the Dash server only\non enter or when losing focus. If it's False, it will sent the value\nback on every change.",
-        "required": false,
-        "defaultValue": {
-          "value": "false",
-          "computed": false
-        },
-        "type": {
-          "name": "bool",
-          "raw": "boolean"
-        }
-      },
-      "disabled": {
-        "description": "Indicates whether the user can interact with the element.",
-        "required": false,
-        "type": {
-          "name": "bool",
-          "raw": "boolean"
-        }
-      },
-      "maxlength": {
-        "description": "Defines the maximum number of characters allowed in the input element.",
-        "required": false,
-        "defaultValue": {
-          "value": "4000",
-          "computed": false
-        },
-        "type": {
-          "name": "number",
-          "raw": "number"
-        }
-      },
-      "n_submit": {
-        "description": "An integer that represents the number of times that the Enter key was\npressed while the input area had focus or submit button has been clicked on.",
-        "required": false,
-        "defaultValue": {
-          "value": "0",
-          "computed": false
-        },
-        "type": {
-          "name": "number",
-          "raw": "number"
-        }
-      },
-      "n_submit_timestamp": {
-        "description": "An integer that represents the time (in ms since 1970) at which n_submit\nchanged.",
-        "required": false,
-        "defaultValue": {
-          "value": "-1",
-          "computed": false
-        },
-        "type": {
-          "name": "number",
-          "raw": "number"
-        }
-      },
-      "placeholder": {
-        "description": "Provides a hint to the user of what can be entered in the field.",
-        "required": false,
-        "defaultValue": {
-          "value": "'Type a message...'",
-          "computed": false
-        },
-        "type": {
-          "name": "string",
-          "raw": "string"
-        }
-      },
-      "rows": {
-        "description": "Defines the number of rows in a text input area.",
-        "required": false,
-        "defaultValue": {
-          "value": "2",
-          "computed": false
-        },
-        "type": {
-          "name": "number",
-          "raw": "number"
-        }
-      },
-      "value": {
-        "description": "Input value for controlled component.",
-        "required": false,
-        "defaultValue": {
-          "value": "''",
-          "computed": false
-        },
-        "type": {
-          "name": "string",
-          "raw": "string"
-        }
-      },
-      "value_on_submit": {
-        "description": "Input value for controlled component after submit.",
-        "required": false,
-        "defaultValue": {
-          "value": "''",
-          "computed": false
-        },
-        "type": {
-          "name": "string",
-          "raw": "string"
-        }
-      },
-      "id": {
-        "description": "Unique ID to identify this component in Dash callbacks.",
-        "required": false,
-        "type": {
-          "name": "string",
-          "raw": "string"
-        }
-      },
-      "className": {
-        "description": "Often used with CSS to style elements with common properties.",
-        "required": false,
-        "type": {
-          "name": "string",
-          "raw": "string"
-        }
-      },
-      "style": {
-        "description": "Defines CSS styles which will override styles previously set.",
-        "required": false,
-        "type": {
-          "name": "any",
-          "raw": "any"
-        }
-      },
-      "setProps": {
-        "description": "Update props to trigger callbacks.",
-        "required": true,
-        "type": {
-          "name": "func",
-          "raw": "(props: Record<string, any>) => void"
-        }
-      },
-      "persistence": {
-        "description": "Used to allow user interactions in this component to be persisted when\nthe component - or the page - is refreshed. If `persisted` is truthy and\nhasn't changed from its previous value, a `value` that the user has\nchanged while using the app will keep that change, as long as\nthe new `value` also matches what was given originally.\nUsed in conjunction with `persistence_type`.",
-        "required": false,
-        "type": {
-          "name": "union",
-          "value": [
-            {
-              "name": "string",
-              "raw": "string"
-            },
-            {
-              "name": "number",
-              "raw": "number"
-            }
-          ],
-          "raw": "string | number | boolean"
-        }
-      },
-      "persisted_props": {
-        "description": "Properties whose user interactions will persist after refreshing the\ncomponent or the page. Since only `value` is allowed this prop can\nnormally be ignored.",
-        "required": false,
-        "defaultValue": {
-          "value": "[\"value\"]",
-          "computed": false
-        },
-        "type": {
-          "name": "arrayOf",
-          "value": {
-            "name": "string",
-            "raw": "string"
-          },
-          "raw": "string[]"
-        }
-      },
-      "persistence_type": {
-        "description": "Where persisted user changes will be stored:\nmemory: only kept in memory, reset on page refresh.\nlocal: window.localStorage, data is kept after the browser quit.\nsession: window.sessionStorage, data is cleared once the browser quit.",
-        "required": false,
-        "defaultValue": {
-          "value": "'local'",
-          "computed": false
-        },
-        "type": {
-          "name": "enum",
-          "value": [
-            {
-              "value": "'local'",
-              "computed": false
-            },
-            {
-              "value": "'session'",
-              "computed": false
-            },
-            {
-              "value": "'memory'",
-              "computed": false
-            }
-          ],
-          "raw": "\"local\" | \"session\" | \"memory\""
-        }
-      }
-    },
-    "isContext": false
-  },
-  "src/ts/components/ChatMessage.tsx": {
-    "displayName": "ChatMessage",
-    "description": "Display single chat message",
-    "props": {
-      "avatar": {
-        "description": "Avatar",
-        "required": false,
-        "defaultValue": {
-          "value": "undefined",
-          "computed": false
-        },
-        "type": {
-          "name": "string",
-          "raw": "string"
-        }
-      },
-      "children": {
-        "description": "Content of the message",
-        "required": false,
-        "type": {
-          "name": "node",
-          "raw": "ReactNode"
-        }
-      },
-      "direction": {
-        "description": "Direction of the mssage: received or outgoing",
-        "required": true,
-        "type": {
-          "name": "string",
-          "raw": "string"
-        }
-      },
-      "timestamp": {
-        "description": "Time",
-        "required": false,
-        "defaultValue": {
-          "value": "-1",
-          "computed": false
-        },
-        "type": {
-          "name": "number",
-          "raw": "number"
-        }
-      },
-      "id": {
-        "description": "Unique ID to identify this component in Dash callbacks.",
-        "required": false,
-        "type": {
-          "name": "string",
-          "raw": "string"
-        }
-      },
-      "className": {
-        "description": "Often used with CSS to style elements with common properties.",
-        "required": false,
-        "type": {
-          "name": "string",
-          "raw": "string"
-        }
-      },
-      "style": {
-        "description": "Defines CSS styles which will override styles previously set.",
-        "required": false,
-        "type": {
-          "name": "any",
-          "raw": "any"
-        }
-      },
-      "setProps": {
-        "description": "Update props to trigger callbacks.",
-        "required": true,
-        "type": {
-          "name": "func",
-          "raw": "(props: Record<string, any>) => void"
-        }
-      }
-    },
-    "isContext": false
-  },
-  "src/ts/components/ChatMessageList.tsx": {
-    "displayName": "ChatMessageList",
-    "description": "Display list of chat messages",
-    "props": {
-      "children": {
-        "description": "ChatMessageList content",
-        "required": false,
-        "type": {
-          "name": "node",
-          "raw": "ReactNode"
-        }
-      },
-      "avatarReceived": {
-        "description": "Indicates whether the recieved message avatar should be displayed.",
-        "required": false,
-        "defaultValue": {
-          "value": "true",
-          "computed": false
-        },
-        "type": {
-          "name": "bool",
-          "raw": "boolean"
-        }
-      },
-      "avatarOutgoing": {
-        "description": "Indicates whether the outgoing message avatar should be displayed.",
-        "required": false,
-        "defaultValue": {
-          "value": "false",
-          "computed": false
-        },
-        "type": {
-          "name": "bool",
-          "raw": "boolean"
-        }
-      },
-      "timestamp": {
-        "description": "Indicates whether the message timestamp should be displayed.",
-        "required": false,
-        "defaultValue": {
-          "value": "true",
-          "computed": false
-        },
-        "type": {
-          "name": "bool",
-          "raw": "boolean"
-        }
-      },
-      "id": {
-        "description": "Unique ID to identify this component in Dash callbacks.",
-        "required": false,
-        "type": {
-          "name": "string",
-          "raw": "string"
-        }
-      },
-      "className": {
-        "description": "Often used with CSS to style elements with common properties.",
-        "required": false,
-        "type": {
-          "name": "string",
-          "raw": "string"
-        }
-      },
-      "style": {
-        "description": "Defines CSS styles which will override styles previously set.",
-        "required": false,
-        "type": {
-          "name": "any",
-          "raw": "any"
-        }
-      },
-      "setProps": {
-        "description": "Update props to trigger callbacks.",
-        "required": true,
-        "type": {
-          "name": "func",
-          "raw": "(props: Record<string, any>) => void"
-        }
-      }
-    },
-    "isContext": false
-  },
-  "src/ts/components/ChatMessageTyping.tsx": {
-    "displayName": "ChatMessageTyping",
-    "description": "Display user typing message",
-    "props": {
-      "avatar": {
-        "description": "Avatar",
-        "required": false,
-        "defaultValue": {
-          "value": "undefined",
-          "computed": false
-        },
-        "type": {
-          "name": "string",
-          "raw": "string"
-        }
-      },
-      "direction": {
-        "description": "Direction of the mssage: received or outgoing",
-        "required": true,
-        "type": {
-          "name": "string",
-          "raw": "string"
-        }
-      },
-      "id": {
-        "description": "Unique ID to identify this component in Dash callbacks.",
-        "required": false,
-        "type": {
-          "name": "string",
-          "raw": "string"
-        }
-      },
-      "className": {
-        "description": "Often used with CSS to style elements with common properties.",
-        "required": false,
-        "type": {
-          "name": "string",
-          "raw": "string"
-        }
-      },
-      "style": {
-        "description": "Defines CSS styles which will override styles previously set.",
-        "required": false,
-        "type": {
-          "name": "any",
-          "raw": "any"
-        }
-      },
-      "setProps": {
-        "description": "Update props to trigger callbacks.",
-        "required": true,
-        "type": {
-          "name": "func",
-          "raw": "(props: Record<string, any>) => void"
-        }
-      }
-    },
-    "isContext": false
-  }
-}
\ No newline at end of file
diff --git a/dash_chat_components/package-info.json b/dash_chat_components/package-info.json
deleted file mode 100644
index ae9a027..0000000
--- a/dash_chat_components/package-info.json
+++ /dev/null
@@ -1,47 +0,0 @@
-{
-  "name": "dash-chat-components",
-  "version": "0.0.3",
-  "description": "Chat components for Plotly Dash",
-  "main": "index.ts",
-  "repository": {
-    "type": "git",
-    "url": "https://github.com/andriiryzhkov/dash-chat-components.git"
-  },
-  "bugs": {
-    "url": "https://github.com/andriiryzhkov/dash-chat-components/issues"
-  },
-  "homepage": "https://github.com/andriiryzhkov/dash-chat-components",
-  "scripts": {
-    "build:js::dev": "webpack --mode development",
-    "build:js": "webpack",
-    "build:backends": "dash-generate-components ./src/ts/components dash_chat_components -p package-info.json --r-prefix '' --jl-prefix '' --ignore \\.test\\.",
-    "build": "npm run build:js && npm run build:backends",
-    "watch": "npm run build:js::dev -- --watch"
-  },
-  "devDependencies": {
-    "@types/react": "^17.0.39",
-    "css-loader": "^6.7.1",
-    "npm-run-all": "^4.1.5",
-    "ramda": "^0.28.0",
-    "react": "16.14.0",
-    "react-docgen": "^5.4.0",
-    "react-dom": "16.14.0",
-    "style-loader": "^3.3.1",
-    "ts-loader": "^9.3.1",
-    "typescript": "^4.7.4",
-    "webpack": "^5.73.0",
-    "webpack-cli": "^4.10.0"
-  },
-  "peerDependencies": {
-    "react": "^16.14.0",
-    "react-dom": "^16.14.0",
-    "classnames": "^2.3.2"
-  },
-  "author": "Andrii Ryzhkov <andrii.ryzhkov@gmail.com>",
-  "license": "MIT",
-  "files": [
-    "/dash_chat_components/*{.js,.map}",
-    "/dash_chat_components/metadata.json",
-    "LICENSE"
-  ]
-}
\ No newline at end of file
diff --git a/deps/dash_chat_components.js b/deps/dash_chat_components.js
deleted file mode 100644
index b548a29..0000000
--- a/deps/dash_chat_components.js
+++ /dev/null
@@ -1,2 +0,0 @@
-/*! For license information please see dash_chat_components.js.LICENSE.txt */
-!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("react")):"function"==typeof define&&define.amd?define(["react"],t):"object"==typeof exports?exports.dash_chat_components=t(require("react")):e.dash_chat_components=t(e.React)}(self,(e=>(()=>{var t={184:(e,t)=>{var n;!function(){"use strict";var a={}.hasOwnProperty;function r(){for(var e=[],t=0;t<arguments.length;t++){var n=arguments[t];if(n){var i=typeof n;if("string"===i||"number"===i)e.push(n);else if(Array.isArray(n)){if(n.length){var o=r.apply(null,n);o&&e.push(o)}}else if("object"===i){if(n.toString!==Object.prototype.toString&&!n.toString.toString().includes("[native code]")){e.push(n.toString());continue}for(var s in n)a.call(n,s)&&n[s]&&e.push(s)}}}return e.join(" ")}e.exports?(r.default=r,e.exports=r):void 0===(n=function(){return r}.apply(t,[]))||(e.exports=n)}()},588:(e,t,n)=>{"use strict";n.d(t,{Z:()=>s});var a=n(81),r=n.n(a),i=n(645),o=n.n(i)()(r());o.push([e.id,".chat-message-received + .chat-message-outgoing,\n.chat-message-outgoing + .chat-message-received {\n  margin-top: 10px;\n}\n\n.chat-message-received + .chat-message-received .chat-message-avatar,\n.chat-message-outgoing + .chat-message-outgoing .chat-message-avatar {\n  visibility: collapse;\n}\n\n.chat-message-received:has(+ .chat-message-received) .chat-message-time,\n.chat-message-outgoing:has(+ .chat-message-outgoing) .chat-message-time {\n  display: none;\n}\n\n.avatar-received-none .chat-message-avatar-container-received {\n  display: none;\n}\n\n.avatar-outgoing-none .chat-message-avatar-container-outgoing {\n  display: none;\n}\n\n.timestamp-none .chat-message-time {\n  display: none;\n}\n",""]);const s=o},26:(e,t,n)=>{"use strict";n.d(t,{Z:()=>s});var a=n(81),r=n.n(a),i=n(645),o=n.n(i)()(r());o.push([e.id,".typing {\n    height: 16px;\n    position: relative;\n    padding: 4px;\n}\n\n.typing__dot {\n    float: left;\n    width: 8px;\n    height: 8px;\n    margin: 0 4px;\n    background: #8d8c91;\n    border-radius: 50%;\n    opacity: 0;\n    animation: loadingFade 1s infinite;\n}\n\n.typing__dot:nth-child(1) {\n    animation-delay: 0s;\n}\n\n.typing__dot:nth-child(2) {\n    animation-delay: 0.2s;\n}\n\n.typing__dot:nth-child(3) {\n    animation-delay: 0.4s;\n}\n\n@keyframes loadingFade {\n    0% {\n        opacity: 0;\n    }\n\n    50% {\n        opacity: 0.8;\n    }\n\n    100% {\n        opacity: 0;\n    }\n}",""]);const s=o},645:e=>{"use strict";e.exports=function(e){var t=[];return t.toString=function(){return this.map((function(t){var n="",a=void 0!==t[5];return t[4]&&(n+="@supports (".concat(t[4],") {")),t[2]&&(n+="@media ".concat(t[2]," {")),a&&(n+="@layer".concat(t[5].length>0?" ".concat(t[5]):""," {")),n+=e(t),a&&(n+="}"),t[2]&&(n+="}"),t[4]&&(n+="}"),n})).join("")},t.i=function(e,n,a,r,i){"string"==typeof e&&(e=[[null,e,void 0]]);var o={};if(a)for(var s=0;s<this.length;s++){var c=this[s][0];null!=c&&(o[c]=!0)}for(var l=0;l<e.length;l++){var u=[].concat(e[l]);a&&o[u[0]]||(void 0!==i&&(void 0===u[5]||(u[1]="@layer".concat(u[5].length>0?" ".concat(u[5]):""," {").concat(u[1],"}")),u[5]=i),n&&(u[2]?(u[1]="@media ".concat(u[2]," {").concat(u[1],"}"),u[2]=n):u[2]=n),r&&(u[4]?(u[1]="@supports (".concat(u[4],") {").concat(u[1],"}"),u[4]=r):u[4]="".concat(r)),t.push(u))}},t}},81:e=>{"use strict";e.exports=function(e){return e[1]}},713:(e,t,n)=>{"use strict";n.r(t),n.d(t,{default:()=>v});var a=n(379),r=n.n(a),i=n(795),o=n.n(i),s=n(565),c=n.n(s),l=n(216),u=n.n(l),d=n(589),f=n.n(d),p=n(588),m={};m.styleTagTransform=f(),m.setAttributes=c(),m.insert=function(e){var t=document.querySelector("head"),n=window._lastElementInsertedByStyleLoader;n?n.nextSibling?t.insertBefore(e,n.nextSibling):t.appendChild(e):t.insertBefore(e,t.firstChild),window._lastElementInsertedByStyleLoader=e},m.domAPI=o(),m.insertStyleElement=u(),r()(p.Z,m);const v=p.Z&&p.Z.locals?p.Z.locals:void 0},811:(e,t,n)=>{"use strict";n.r(t),n.d(t,{default:()=>v});var a=n(379),r=n.n(a),i=n(795),o=n.n(i),s=n(565),c=n.n(s),l=n(216),u=n.n(l),d=n(589),f=n.n(d),p=n(26),m={};m.styleTagTransform=f(),m.setAttributes=c(),m.insert=function(e){var t=document.querySelector("head"),n=window._lastElementInsertedByStyleLoader;n?n.nextSibling?t.insertBefore(e,n.nextSibling):t.appendChild(e):t.insertBefore(e,t.firstChild),window._lastElementInsertedByStyleLoader=e},m.domAPI=o(),m.insertStyleElement=u(),r()(p.Z,m);const v=p.Z&&p.Z.locals?p.Z.locals:void 0},379:e=>{"use strict";var t=[];function n(e){for(var n=-1,a=0;a<t.length;a++)if(t[a].identifier===e){n=a;break}return n}function a(e,a){for(var i={},o=[],s=0;s<e.length;s++){var c=e[s],l=a.base?c[0]+a.base:c[0],u=i[l]||0,d="".concat(l," ").concat(u);i[l]=u+1;var f=n(d),p={css:c[1],media:c[2],sourceMap:c[3],supports:c[4],layer:c[5]};if(-1!==f)t[f].references++,t[f].updater(p);else{var m=r(p,a);a.byIndex=s,t.splice(s,0,{identifier:d,updater:m,references:1})}o.push(d)}return o}function r(e,t){var n=t.domAPI(t);return n.update(e),function(t){if(t){if(t.css===e.css&&t.media===e.media&&t.sourceMap===e.sourceMap&&t.supports===e.supports&&t.layer===e.layer)return;n.update(e=t)}else n.remove()}}e.exports=function(e,r){var i=a(e=e||[],r=r||{});return function(e){e=e||[];for(var o=0;o<i.length;o++){var s=n(i[o]);t[s].references--}for(var c=a(e,r),l=0;l<i.length;l++){var u=n(i[l]);0===t[u].references&&(t[u].updater(),t.splice(u,1))}i=c}}},216:e=>{"use strict";e.exports=function(e){var t=document.createElement("style");return e.setAttributes(t,e.attributes),e.insert(t,e.options),t}},565:(e,t,n)=>{"use strict";e.exports=function(e){var t=n.nc;t&&e.setAttribute("nonce",t)}},795:e=>{"use strict";e.exports=function(e){if("undefined"==typeof document)return{update:function(){},remove:function(){}};var t=e.insertStyleElement(e);return{update:function(n){!function(e,t,n){var a="";n.supports&&(a+="@supports (".concat(n.supports,") {")),n.media&&(a+="@media ".concat(n.media," {"));var r=void 0!==n.layer;r&&(a+="@layer".concat(n.layer.length>0?" ".concat(n.layer):""," {")),a+=n.css,r&&(a+="}"),n.media&&(a+="}"),n.supports&&(a+="}");var i=n.sourceMap;i&&"undefined"!=typeof btoa&&(a+="\n/*# sourceMappingURL=data:application/json;base64,".concat(btoa(unescape(encodeURIComponent(JSON.stringify(i))))," */")),t.styleTagTransform(a,e,t.options)}(t,e,n)},remove:function(){!function(e){if(null===e.parentNode)return!1;e.parentNode.removeChild(e)}(t)}}}},589:e=>{"use strict";e.exports=function(e,t){if(t.styleSheet)t.styleSheet.cssText=e;else{for(;t.firstChild;)t.removeChild(t.firstChild);t.appendChild(document.createTextNode(e))}}},91:function(e,t,n){"use strict";var a=this&&this.__assign||function(){return a=Object.assign||function(e){for(var t,n=1,a=arguments.length;n<a;n++)for(var r in t=arguments[n])Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r]);return e},a.apply(this,arguments)},r=this&&this.__rest||function(e,t){var n={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&t.indexOf(a)<0&&(n[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var r=0;for(a=Object.getOwnPropertySymbols(e);r<a.length;r++)t.indexOf(a[r])<0&&Object.prototype.propertyIsEnumerable.call(e,a[r])&&(n[a[r]]=e[a[r]])}return n},i=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};t.__esModule=!0;var o=i(n(812)),s=function(e){e.setProps;var t=e.id,n=e.children,i=e.height,s=(e.width,r(e,["setProps","id","children","height","width"]));return o.default.createElement("div",a({id:t,style:{height:i}},s),n)};s.defaultProps={},t.default=s},806:function(e,t,n){"use strict";var a=this&&this.__assign||function(){return a=Object.assign||function(e){for(var t,n=1,a=arguments.length;n<a;n++)for(var r in t=arguments[n])Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r]);return e},a.apply(this,arguments)},r=this&&this.__createBinding||(Object.create?function(e,t,n,a){void 0===a&&(a=n);var r=Object.getOwnPropertyDescriptor(t,n);r&&!("get"in r?!t.__esModule:r.writable||r.configurable)||(r={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,a,r)}:function(e,t,n,a){void 0===a&&(a=n),e[a]=t[n]}),i=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),o=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)"default"!==n&&Object.prototype.hasOwnProperty.call(e,n)&&r(t,e,n);return i(t,e),t},s=this&&this.__rest||function(e,t){var n={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&t.indexOf(a)<0&&(n[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var r=0;for(a=Object.getOwnPropertySymbols(e);r<a.length;r++)t.indexOf(a[r])<0&&Object.prototype.propertyIsEnumerable.call(e,a[r])&&(n[a[r]]=e[a[r]])}return n},c=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};t.__esModule=!0;var l=o(n(812)),u=c(n(184)),d=function(e){var t=e.setProps,n=e.id,r=e.className,i=e.value,o=e.autofocus,c=e.debounce,d=e.disabled,f=e.maxlength,p=e.n_submit,m=(e.n_submit_timestamp,e.value_on_submit,e.placeholder),v=(e.persistence,e.persisted_props,e.persistence_type,e.rows),h=s(e,["setProps","id","className","value","autofocus","debounce","disabled","maxlength","n_submit","n_submit_timestamp","value_on_submit","placeholder","persistence","persisted_props","persistence_type","rows"]),g=(0,l.useRef)(null),y=(0,l.useState)(i||void 0),_=y[0],b=y[1],O=(0,u.default)("position-relative",r),w=(0,u.default)("form-control"),x=(0,u.default)("btn btn-outline-primary border-0 position-absolute bottom-0 end-0 m-1 rounded-4");return(0,l.useEffect)((function(){o&&g.current.focus()}),[d]),(0,l.useEffect)((function(){i!==_&&b(i||void 0)}),[i]),l.default.createElement("div",a({id:n,className:O},h),l.default.createElement("textarea",{ref:g,className:w,onChange:function(e){var n=e.target.value;b(n),!c&&t&&t({value:n})},onBlur:function(){c&&t&&t({value:g.current.value})},onKeyDown:function(e){if(t&&"Enter"===e.key&&!1===e.altKey&&!1===e.shiftKey){e.preventDefault();var n={n_submit:p+1,n_submit_timestamp:Date.now(),value_on_submit:g.current.value,value:void 0};b(void 0),t(n)}},autoFocus:o,disabled:d,maxLength:f,rows:v,placeholder:m,style:{paddingRight:"50px"},value:i}),l.default.createElement("button",{type:"button",onClick:function(){if(t){var e={n_submit:p+1,n_submit_timestamp:Date.now(),value_on_submit:g.current.value,value:void 0};b(void 0),t(e)}},disabled:d,className:x},l.default.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",width:"16",height:"16",fill:"currentColor",viewBox:"0 0 16 16"},l.default.createElement("path",{d:"M15.964.686a.5.5 0 0 0-.65-.65L.767 5.855H.766l-.452.18a.5.5 0 0 0-.082.887l.41.26.001.002 4.995 3.178 3.178 4.995.002.002.26.41a.5.5 0 0 0 .886-.083l6-15Zm-1.833 1.89L6.637 10.07l-.215-.338a.5.5 0 0 0-.154-.154l-.338-.215 7.494-7.494 1.178-.471-.47 1.178Z"}))))};d.defaultProps={value:"",placeholder:"Type a message...",debounce:!1,maxlength:4e3,n_clicks:0,n_clicks_timestamp:-1,n_submit:0,n_submit_timestamp:-1,value_on_submit:"",persisted_props:["value"],persistence_type:"local",rows:2},t.default=d},472:function(e,t,n){"use strict";var a=this&&this.__assign||function(){return a=Object.assign||function(e){for(var t,n=1,a=arguments.length;n<a;n++)for(var r in t=arguments[n])Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r]);return e},a.apply(this,arguments)},r=this&&this.__createBinding||(Object.create?function(e,t,n,a){void 0===a&&(a=n);var r=Object.getOwnPropertyDescriptor(t,n);r&&!("get"in r?!t.__esModule:r.writable||r.configurable)||(r={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,a,r)}:function(e,t,n,a){void 0===a&&(a=n),e[a]=t[n]}),i=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),o=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)"default"!==n&&Object.prototype.hasOwnProperty.call(e,n)&&r(t,e,n);return i(t,e),t},s=this&&this.__rest||function(e,t){var n={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&t.indexOf(a)<0&&(n[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var r=0;for(a=Object.getOwnPropertySymbols(e);r<a.length;r++)t.indexOf(a[r])<0&&Object.prototype.propertyIsEnumerable.call(e,a[r])&&(n[a[r]]=e[a[r]])}return n},c=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};t.__esModule=!0;var l=o(n(812));n(713);var u=c(n(184)),d=n(605),f=function(e){var t=e.src,n=e.direction,a=e.className,r=(0,l.useState)(!1),i=r[0],o=r[1],s=(0,u.default)("rounded-circle","bg-light","d-flex","justify-content-center","align-items-center",a),c=(0,u.default)("rounded-circle",a);return i?l.default.createElement("div",{style:{width:45,height:45},className:s},l.default.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",width:"25",height:"25",fill:"currentColor",viewBox:"0 0 16 16"},"received"===n?l.default.createElement(l.default.Fragment,null,l.default.createElement("path",{d:"M6 12.5a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1-.5-.5ZM3 8.062C3 6.76 4.235 5.765 5.53 5.886a26.58 26.58 0 0 0 4.94 0C11.765 5.765 13 6.76 13 8.062v1.157a.933.933 0 0 1-.765.935c-.845.147-2.34.346-4.235.346-1.895 0-3.39-.2-4.235-.346A.933.933 0 0 1 3 9.219V8.062Zm4.542-.827a.25.25 0 0 0-.217.068l-.92.9a24.767 24.767 0 0 1-1.871-.183.25.25 0 0 0-.068.495c.55.076 1.232.149 2.02.193a.25.25 0 0 0 .189-.071l.754-.736.847 1.71a.25.25 0 0 0 .404.062l.932-.97a25.286 25.286 0 0 0 1.922-.188.25.25 0 0 0-.068-.495c-.538.074-1.207.145-1.98.189a.25.25 0 0 0-.166.076l-.754.785-.842-1.7a.25.25 0 0 0-.182-.135Z"}),l.default.createElement("path",{d:"M8.5 1.866a1 1 0 1 0-1 0V3h-2A4.5 4.5 0 0 0 1 7.5V8a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1v1a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2v-1a1 1 0 0 0 1-1V9a1 1 0 0 0-1-1v-.5A4.5 4.5 0 0 0 10.5 3h-2V1.866ZM14 7.5V13a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V7.5A3.5 3.5 0 0 1 5.5 4h5A3.5 3.5 0 0 1 14 7.5Z"})):l.default.createElement("path",{d:"M8 8a3 3 0 1 0 0-6 3 3 0 0 0 0 6Zm2-3a2 2 0 1 1-4 0 2 2 0 0 1 4 0Zm4 8c0 1-1 1-1 1H3s-1 0-1-1 1-4 6-4 6 3 6 4Zm-1-.004c-.001-.246-.154-.986-.832-1.664C11.516 10.68 10.289 10 8 10c-2.29 0-3.516.68-4.168 1.332-.678.678-.83 1.418-.832 1.664h10Z"}))):l.default.createElement("img",{src:t,width:45,height:45,className:c,onError:function(){o(!0)}})},p=function(e){e.setProps;var t=e.children,n=e.id,r=e.avatar,i=e.className,o=e.direction,c=e.timestamp,p=s(e,["setProps","children","id","avatar","className","direction","timestamp"]),m=(0,u.default)("chat-message","chat-message-".concat(o),"d-flex","justify-content-end",i,{"flex-row-reverse":"received"===o,"flex-row":"outgoing"===o}),v=(0,u.default)("mb-1","mw-75","d-flex","flex-column",{"align-items-start":"received"===o,"align-items-end":"outgoing"===o}),h=(0,u.default)("chat-message-content","small","rounded-3","p-3","mb-1","text-break",i,{"bg-secondary-subtle":"received"===o,"bg-primary text-white":"outgoing"===o}),g=(0,u.default)("chat-message-time","small","mb-2","text-muted",i,{"text-start":"received"===o,"text-end":"outgoing"===o,"d-none":-1===c}),y=(0,u.default)({"chat-message-avatar-container-received":"received"===o,"chat-message-avatar-container-outgoing":"outgoing"===o}),_=(0,u.default)("chat-message-avatar","chat-message-avatar-".concat(o),"mb-2","text-muted",i,{"d-none":void 0===r,"float-start":"received"===o,"float-end":"outgoing"===o});return l.default.createElement("div",a({id:n,className:m},p),l.default.createElement("div",{className:v,style:{maxWidth:"75%"}},l.default.createElement("div",{className:h},t),l.default.createElement("p",{className:g},(0,d.formatTimestamp)(c))),l.default.createElement("div",{className:y,style:void 0!==r?{width:"53px"}:{}},l.default.createElement(f,{src:r,direction:o,className:_})))};p.defaultProps={avatar:void 0,timestamp:-1},t.default=p},777:function(e,t,n){"use strict";var a=this&&this.__assign||function(){return a=Object.assign||function(e){for(var t,n=1,a=arguments.length;n<a;n++)for(var r in t=arguments[n])Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r]);return e},a.apply(this,arguments)},r=this&&this.__createBinding||(Object.create?function(e,t,n,a){void 0===a&&(a=n);var r=Object.getOwnPropertyDescriptor(t,n);r&&!("get"in r?!t.__esModule:r.writable||r.configurable)||(r={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,a,r)}:function(e,t,n,a){void 0===a&&(a=n),e[a]=t[n]}),i=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),o=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)"default"!==n&&Object.prototype.hasOwnProperty.call(e,n)&&r(t,e,n);return i(t,e),t},s=this&&this.__rest||function(e,t){var n={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&t.indexOf(a)<0&&(n[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var r=0;for(a=Object.getOwnPropertySymbols(e);r<a.length;r++)t.indexOf(a[r])<0&&Object.prototype.propertyIsEnumerable.call(e,a[r])&&(n[a[r]]=e[a[r]])}return n},c=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};t.__esModule=!0;var l=o(n(812)),u=c(n(184)),d=function(e){e.setProps;var t=e.children,n=e.id,r=e.className,i=e.avatarReceived,o=e.avatarOutgoing,c=e.timestamp,d=s(e,["setProps","children","id","className","avatarReceived","avatarOutgoing","timestamp"]),f=(0,l.useRef)(null),p=(0,u.default)("vstack","w-100","position-relative","overflow-auto",r,{"avatar-received-none":!i,"avatar-outgoing-none":!o,"timestamp-none":!c});return(0,l.useEffect)((function(){var e,t;null==(t=null===(e=f.current)||void 0===e?void 0:e.lastElementChild)||t.scrollIntoView({behavior:"instant"})}),[t]),l.default.createElement("div",a({id:n,ref:f,className:p},d),t)};d.defaultProps={avatarReceived:!0,avatarOutgoing:!1,timestamp:!0},t.default=d},991:function(e,t,n){"use strict";var a=this&&this.__rest||function(e,t){var n={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&t.indexOf(a)<0&&(n[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var r=0;for(a=Object.getOwnPropertySymbols(e);r<a.length;r++)t.indexOf(a[r])<0&&Object.prototype.propertyIsEnumerable.call(e,a[r])&&(n[a[r]]=e[a[r]])}return n},r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};t.__esModule=!0;var i=r(n(812));n(713),n(811);var o=r(n(472)),s=function(e){var t=e.setProps,n=(e.id,e.avatar),r=e.className,s=e.direction;return a(e,["setProps","id","avatar","className","direction"]),i.default.createElement(o.default,{setProps:t,avatar:n,direction:s,className:r},i.default.createElement("div",{className:"typing"},i.default.createElement("div",{className:"typing__dot"}),i.default.createElement("div",{className:"typing__dot"}),i.default.createElement("div",{className:"typing__dot"})))};s.defaultProps={avatar:void 0,timestamp:-1},t.default=s},294:function(e,t,n){"use strict";var a=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};t.__esModule=!0,t.ChatMessageTyping=t.ChatMessageList=t.ChatMessage=t.ChatInput=t.Chat=void 0;var r=a(n(91));t.Chat=r.default;var i=a(n(806));t.ChatInput=i.default;var o=a(n(472));t.ChatMessage=o.default;var s=a(n(777));t.ChatMessageList=s.default;var c=a(n(991));t.ChatMessageTyping=c.default},605:(e,t)=>{"use strict";t.__esModule=!0,t.formatTimestamp=void 0,t.formatTimestamp=function(e,t){void 0===t&&(t="en-GB");var n=new Date(e),a={year:"numeric",month:"numeric",day:"numeric"};return new Intl.DateTimeFormat(t,a).format(n)===new Intl.DateTimeFormat(t,a).format(new Date)?new Intl.DateTimeFormat(t,{hour:"numeric",minute:"numeric"}).format(n):new Intl.DateTimeFormat(t,{year:"numeric",month:"short",day:"numeric",hour:"numeric",minute:"numeric"}).format(n)}},812:t=>{"use strict";t.exports=e}},n={};function a(e){var r=n[e];if(void 0!==r)return r.exports;var i=n[e]={id:e,exports:{}};return t[e].call(i.exports,i,i.exports,a),i.exports}return a.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return a.d(t,{a:t}),t},a.d=(e,t)=>{for(var n in t)a.o(t,n)&&!a.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},a.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),a.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},a.nc=void 0,a(294)})()));
\ No newline at end of file
diff --git a/deps/dash_chat_components.js.LICENSE.txt b/deps/dash_chat_components.js.LICENSE.txt
deleted file mode 100644
index 827f273..0000000
--- a/deps/dash_chat_components.js.LICENSE.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-/*!
-	Copyright (c) 2018 Jed Watson.
-	Licensed under the MIT License (MIT), see
-	http://jedwatson.github.io/classnames
-*/
diff --git a/inst/deps/dash_chat_components.js b/inst/deps/dash_chat_components.js
deleted file mode 100644
index b548a29..0000000
--- a/inst/deps/dash_chat_components.js
+++ /dev/null
@@ -1,2 +0,0 @@
-/*! For license information please see dash_chat_components.js.LICENSE.txt */
-!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("react")):"function"==typeof define&&define.amd?define(["react"],t):"object"==typeof exports?exports.dash_chat_components=t(require("react")):e.dash_chat_components=t(e.React)}(self,(e=>(()=>{var t={184:(e,t)=>{var n;!function(){"use strict";var a={}.hasOwnProperty;function r(){for(var e=[],t=0;t<arguments.length;t++){var n=arguments[t];if(n){var i=typeof n;if("string"===i||"number"===i)e.push(n);else if(Array.isArray(n)){if(n.length){var o=r.apply(null,n);o&&e.push(o)}}else if("object"===i){if(n.toString!==Object.prototype.toString&&!n.toString.toString().includes("[native code]")){e.push(n.toString());continue}for(var s in n)a.call(n,s)&&n[s]&&e.push(s)}}}return e.join(" ")}e.exports?(r.default=r,e.exports=r):void 0===(n=function(){return r}.apply(t,[]))||(e.exports=n)}()},588:(e,t,n)=>{"use strict";n.d(t,{Z:()=>s});var a=n(81),r=n.n(a),i=n(645),o=n.n(i)()(r());o.push([e.id,".chat-message-received + .chat-message-outgoing,\n.chat-message-outgoing + .chat-message-received {\n  margin-top: 10px;\n}\n\n.chat-message-received + .chat-message-received .chat-message-avatar,\n.chat-message-outgoing + .chat-message-outgoing .chat-message-avatar {\n  visibility: collapse;\n}\n\n.chat-message-received:has(+ .chat-message-received) .chat-message-time,\n.chat-message-outgoing:has(+ .chat-message-outgoing) .chat-message-time {\n  display: none;\n}\n\n.avatar-received-none .chat-message-avatar-container-received {\n  display: none;\n}\n\n.avatar-outgoing-none .chat-message-avatar-container-outgoing {\n  display: none;\n}\n\n.timestamp-none .chat-message-time {\n  display: none;\n}\n",""]);const s=o},26:(e,t,n)=>{"use strict";n.d(t,{Z:()=>s});var a=n(81),r=n.n(a),i=n(645),o=n.n(i)()(r());o.push([e.id,".typing {\n    height: 16px;\n    position: relative;\n    padding: 4px;\n}\n\n.typing__dot {\n    float: left;\n    width: 8px;\n    height: 8px;\n    margin: 0 4px;\n    background: #8d8c91;\n    border-radius: 50%;\n    opacity: 0;\n    animation: loadingFade 1s infinite;\n}\n\n.typing__dot:nth-child(1) {\n    animation-delay: 0s;\n}\n\n.typing__dot:nth-child(2) {\n    animation-delay: 0.2s;\n}\n\n.typing__dot:nth-child(3) {\n    animation-delay: 0.4s;\n}\n\n@keyframes loadingFade {\n    0% {\n        opacity: 0;\n    }\n\n    50% {\n        opacity: 0.8;\n    }\n\n    100% {\n        opacity: 0;\n    }\n}",""]);const s=o},645:e=>{"use strict";e.exports=function(e){var t=[];return t.toString=function(){return this.map((function(t){var n="",a=void 0!==t[5];return t[4]&&(n+="@supports (".concat(t[4],") {")),t[2]&&(n+="@media ".concat(t[2]," {")),a&&(n+="@layer".concat(t[5].length>0?" ".concat(t[5]):""," {")),n+=e(t),a&&(n+="}"),t[2]&&(n+="}"),t[4]&&(n+="}"),n})).join("")},t.i=function(e,n,a,r,i){"string"==typeof e&&(e=[[null,e,void 0]]);var o={};if(a)for(var s=0;s<this.length;s++){var c=this[s][0];null!=c&&(o[c]=!0)}for(var l=0;l<e.length;l++){var u=[].concat(e[l]);a&&o[u[0]]||(void 0!==i&&(void 0===u[5]||(u[1]="@layer".concat(u[5].length>0?" ".concat(u[5]):""," {").concat(u[1],"}")),u[5]=i),n&&(u[2]?(u[1]="@media ".concat(u[2]," {").concat(u[1],"}"),u[2]=n):u[2]=n),r&&(u[4]?(u[1]="@supports (".concat(u[4],") {").concat(u[1],"}"),u[4]=r):u[4]="".concat(r)),t.push(u))}},t}},81:e=>{"use strict";e.exports=function(e){return e[1]}},713:(e,t,n)=>{"use strict";n.r(t),n.d(t,{default:()=>v});var a=n(379),r=n.n(a),i=n(795),o=n.n(i),s=n(565),c=n.n(s),l=n(216),u=n.n(l),d=n(589),f=n.n(d),p=n(588),m={};m.styleTagTransform=f(),m.setAttributes=c(),m.insert=function(e){var t=document.querySelector("head"),n=window._lastElementInsertedByStyleLoader;n?n.nextSibling?t.insertBefore(e,n.nextSibling):t.appendChild(e):t.insertBefore(e,t.firstChild),window._lastElementInsertedByStyleLoader=e},m.domAPI=o(),m.insertStyleElement=u(),r()(p.Z,m);const v=p.Z&&p.Z.locals?p.Z.locals:void 0},811:(e,t,n)=>{"use strict";n.r(t),n.d(t,{default:()=>v});var a=n(379),r=n.n(a),i=n(795),o=n.n(i),s=n(565),c=n.n(s),l=n(216),u=n.n(l),d=n(589),f=n.n(d),p=n(26),m={};m.styleTagTransform=f(),m.setAttributes=c(),m.insert=function(e){var t=document.querySelector("head"),n=window._lastElementInsertedByStyleLoader;n?n.nextSibling?t.insertBefore(e,n.nextSibling):t.appendChild(e):t.insertBefore(e,t.firstChild),window._lastElementInsertedByStyleLoader=e},m.domAPI=o(),m.insertStyleElement=u(),r()(p.Z,m);const v=p.Z&&p.Z.locals?p.Z.locals:void 0},379:e=>{"use strict";var t=[];function n(e){for(var n=-1,a=0;a<t.length;a++)if(t[a].identifier===e){n=a;break}return n}function a(e,a){for(var i={},o=[],s=0;s<e.length;s++){var c=e[s],l=a.base?c[0]+a.base:c[0],u=i[l]||0,d="".concat(l," ").concat(u);i[l]=u+1;var f=n(d),p={css:c[1],media:c[2],sourceMap:c[3],supports:c[4],layer:c[5]};if(-1!==f)t[f].references++,t[f].updater(p);else{var m=r(p,a);a.byIndex=s,t.splice(s,0,{identifier:d,updater:m,references:1})}o.push(d)}return o}function r(e,t){var n=t.domAPI(t);return n.update(e),function(t){if(t){if(t.css===e.css&&t.media===e.media&&t.sourceMap===e.sourceMap&&t.supports===e.supports&&t.layer===e.layer)return;n.update(e=t)}else n.remove()}}e.exports=function(e,r){var i=a(e=e||[],r=r||{});return function(e){e=e||[];for(var o=0;o<i.length;o++){var s=n(i[o]);t[s].references--}for(var c=a(e,r),l=0;l<i.length;l++){var u=n(i[l]);0===t[u].references&&(t[u].updater(),t.splice(u,1))}i=c}}},216:e=>{"use strict";e.exports=function(e){var t=document.createElement("style");return e.setAttributes(t,e.attributes),e.insert(t,e.options),t}},565:(e,t,n)=>{"use strict";e.exports=function(e){var t=n.nc;t&&e.setAttribute("nonce",t)}},795:e=>{"use strict";e.exports=function(e){if("undefined"==typeof document)return{update:function(){},remove:function(){}};var t=e.insertStyleElement(e);return{update:function(n){!function(e,t,n){var a="";n.supports&&(a+="@supports (".concat(n.supports,") {")),n.media&&(a+="@media ".concat(n.media," {"));var r=void 0!==n.layer;r&&(a+="@layer".concat(n.layer.length>0?" ".concat(n.layer):""," {")),a+=n.css,r&&(a+="}"),n.media&&(a+="}"),n.supports&&(a+="}");var i=n.sourceMap;i&&"undefined"!=typeof btoa&&(a+="\n/*# sourceMappingURL=data:application/json;base64,".concat(btoa(unescape(encodeURIComponent(JSON.stringify(i))))," */")),t.styleTagTransform(a,e,t.options)}(t,e,n)},remove:function(){!function(e){if(null===e.parentNode)return!1;e.parentNode.removeChild(e)}(t)}}}},589:e=>{"use strict";e.exports=function(e,t){if(t.styleSheet)t.styleSheet.cssText=e;else{for(;t.firstChild;)t.removeChild(t.firstChild);t.appendChild(document.createTextNode(e))}}},91:function(e,t,n){"use strict";var a=this&&this.__assign||function(){return a=Object.assign||function(e){for(var t,n=1,a=arguments.length;n<a;n++)for(var r in t=arguments[n])Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r]);return e},a.apply(this,arguments)},r=this&&this.__rest||function(e,t){var n={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&t.indexOf(a)<0&&(n[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var r=0;for(a=Object.getOwnPropertySymbols(e);r<a.length;r++)t.indexOf(a[r])<0&&Object.prototype.propertyIsEnumerable.call(e,a[r])&&(n[a[r]]=e[a[r]])}return n},i=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};t.__esModule=!0;var o=i(n(812)),s=function(e){e.setProps;var t=e.id,n=e.children,i=e.height,s=(e.width,r(e,["setProps","id","children","height","width"]));return o.default.createElement("div",a({id:t,style:{height:i}},s),n)};s.defaultProps={},t.default=s},806:function(e,t,n){"use strict";var a=this&&this.__assign||function(){return a=Object.assign||function(e){for(var t,n=1,a=arguments.length;n<a;n++)for(var r in t=arguments[n])Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r]);return e},a.apply(this,arguments)},r=this&&this.__createBinding||(Object.create?function(e,t,n,a){void 0===a&&(a=n);var r=Object.getOwnPropertyDescriptor(t,n);r&&!("get"in r?!t.__esModule:r.writable||r.configurable)||(r={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,a,r)}:function(e,t,n,a){void 0===a&&(a=n),e[a]=t[n]}),i=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),o=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)"default"!==n&&Object.prototype.hasOwnProperty.call(e,n)&&r(t,e,n);return i(t,e),t},s=this&&this.__rest||function(e,t){var n={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&t.indexOf(a)<0&&(n[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var r=0;for(a=Object.getOwnPropertySymbols(e);r<a.length;r++)t.indexOf(a[r])<0&&Object.prototype.propertyIsEnumerable.call(e,a[r])&&(n[a[r]]=e[a[r]])}return n},c=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};t.__esModule=!0;var l=o(n(812)),u=c(n(184)),d=function(e){var t=e.setProps,n=e.id,r=e.className,i=e.value,o=e.autofocus,c=e.debounce,d=e.disabled,f=e.maxlength,p=e.n_submit,m=(e.n_submit_timestamp,e.value_on_submit,e.placeholder),v=(e.persistence,e.persisted_props,e.persistence_type,e.rows),h=s(e,["setProps","id","className","value","autofocus","debounce","disabled","maxlength","n_submit","n_submit_timestamp","value_on_submit","placeholder","persistence","persisted_props","persistence_type","rows"]),g=(0,l.useRef)(null),y=(0,l.useState)(i||void 0),_=y[0],b=y[1],O=(0,u.default)("position-relative",r),w=(0,u.default)("form-control"),x=(0,u.default)("btn btn-outline-primary border-0 position-absolute bottom-0 end-0 m-1 rounded-4");return(0,l.useEffect)((function(){o&&g.current.focus()}),[d]),(0,l.useEffect)((function(){i!==_&&b(i||void 0)}),[i]),l.default.createElement("div",a({id:n,className:O},h),l.default.createElement("textarea",{ref:g,className:w,onChange:function(e){var n=e.target.value;b(n),!c&&t&&t({value:n})},onBlur:function(){c&&t&&t({value:g.current.value})},onKeyDown:function(e){if(t&&"Enter"===e.key&&!1===e.altKey&&!1===e.shiftKey){e.preventDefault();var n={n_submit:p+1,n_submit_timestamp:Date.now(),value_on_submit:g.current.value,value:void 0};b(void 0),t(n)}},autoFocus:o,disabled:d,maxLength:f,rows:v,placeholder:m,style:{paddingRight:"50px"},value:i}),l.default.createElement("button",{type:"button",onClick:function(){if(t){var e={n_submit:p+1,n_submit_timestamp:Date.now(),value_on_submit:g.current.value,value:void 0};b(void 0),t(e)}},disabled:d,className:x},l.default.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",width:"16",height:"16",fill:"currentColor",viewBox:"0 0 16 16"},l.default.createElement("path",{d:"M15.964.686a.5.5 0 0 0-.65-.65L.767 5.855H.766l-.452.18a.5.5 0 0 0-.082.887l.41.26.001.002 4.995 3.178 3.178 4.995.002.002.26.41a.5.5 0 0 0 .886-.083l6-15Zm-1.833 1.89L6.637 10.07l-.215-.338a.5.5 0 0 0-.154-.154l-.338-.215 7.494-7.494 1.178-.471-.47 1.178Z"}))))};d.defaultProps={value:"",placeholder:"Type a message...",debounce:!1,maxlength:4e3,n_clicks:0,n_clicks_timestamp:-1,n_submit:0,n_submit_timestamp:-1,value_on_submit:"",persisted_props:["value"],persistence_type:"local",rows:2},t.default=d},472:function(e,t,n){"use strict";var a=this&&this.__assign||function(){return a=Object.assign||function(e){for(var t,n=1,a=arguments.length;n<a;n++)for(var r in t=arguments[n])Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r]);return e},a.apply(this,arguments)},r=this&&this.__createBinding||(Object.create?function(e,t,n,a){void 0===a&&(a=n);var r=Object.getOwnPropertyDescriptor(t,n);r&&!("get"in r?!t.__esModule:r.writable||r.configurable)||(r={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,a,r)}:function(e,t,n,a){void 0===a&&(a=n),e[a]=t[n]}),i=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),o=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)"default"!==n&&Object.prototype.hasOwnProperty.call(e,n)&&r(t,e,n);return i(t,e),t},s=this&&this.__rest||function(e,t){var n={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&t.indexOf(a)<0&&(n[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var r=0;for(a=Object.getOwnPropertySymbols(e);r<a.length;r++)t.indexOf(a[r])<0&&Object.prototype.propertyIsEnumerable.call(e,a[r])&&(n[a[r]]=e[a[r]])}return n},c=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};t.__esModule=!0;var l=o(n(812));n(713);var u=c(n(184)),d=n(605),f=function(e){var t=e.src,n=e.direction,a=e.className,r=(0,l.useState)(!1),i=r[0],o=r[1],s=(0,u.default)("rounded-circle","bg-light","d-flex","justify-content-center","align-items-center",a),c=(0,u.default)("rounded-circle",a);return i?l.default.createElement("div",{style:{width:45,height:45},className:s},l.default.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",width:"25",height:"25",fill:"currentColor",viewBox:"0 0 16 16"},"received"===n?l.default.createElement(l.default.Fragment,null,l.default.createElement("path",{d:"M6 12.5a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1-.5-.5ZM3 8.062C3 6.76 4.235 5.765 5.53 5.886a26.58 26.58 0 0 0 4.94 0C11.765 5.765 13 6.76 13 8.062v1.157a.933.933 0 0 1-.765.935c-.845.147-2.34.346-4.235.346-1.895 0-3.39-.2-4.235-.346A.933.933 0 0 1 3 9.219V8.062Zm4.542-.827a.25.25 0 0 0-.217.068l-.92.9a24.767 24.767 0 0 1-1.871-.183.25.25 0 0 0-.068.495c.55.076 1.232.149 2.02.193a.25.25 0 0 0 .189-.071l.754-.736.847 1.71a.25.25 0 0 0 .404.062l.932-.97a25.286 25.286 0 0 0 1.922-.188.25.25 0 0 0-.068-.495c-.538.074-1.207.145-1.98.189a.25.25 0 0 0-.166.076l-.754.785-.842-1.7a.25.25 0 0 0-.182-.135Z"}),l.default.createElement("path",{d:"M8.5 1.866a1 1 0 1 0-1 0V3h-2A4.5 4.5 0 0 0 1 7.5V8a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1v1a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2v-1a1 1 0 0 0 1-1V9a1 1 0 0 0-1-1v-.5A4.5 4.5 0 0 0 10.5 3h-2V1.866ZM14 7.5V13a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V7.5A3.5 3.5 0 0 1 5.5 4h5A3.5 3.5 0 0 1 14 7.5Z"})):l.default.createElement("path",{d:"M8 8a3 3 0 1 0 0-6 3 3 0 0 0 0 6Zm2-3a2 2 0 1 1-4 0 2 2 0 0 1 4 0Zm4 8c0 1-1 1-1 1H3s-1 0-1-1 1-4 6-4 6 3 6 4Zm-1-.004c-.001-.246-.154-.986-.832-1.664C11.516 10.68 10.289 10 8 10c-2.29 0-3.516.68-4.168 1.332-.678.678-.83 1.418-.832 1.664h10Z"}))):l.default.createElement("img",{src:t,width:45,height:45,className:c,onError:function(){o(!0)}})},p=function(e){e.setProps;var t=e.children,n=e.id,r=e.avatar,i=e.className,o=e.direction,c=e.timestamp,p=s(e,["setProps","children","id","avatar","className","direction","timestamp"]),m=(0,u.default)("chat-message","chat-message-".concat(o),"d-flex","justify-content-end",i,{"flex-row-reverse":"received"===o,"flex-row":"outgoing"===o}),v=(0,u.default)("mb-1","mw-75","d-flex","flex-column",{"align-items-start":"received"===o,"align-items-end":"outgoing"===o}),h=(0,u.default)("chat-message-content","small","rounded-3","p-3","mb-1","text-break",i,{"bg-secondary-subtle":"received"===o,"bg-primary text-white":"outgoing"===o}),g=(0,u.default)("chat-message-time","small","mb-2","text-muted",i,{"text-start":"received"===o,"text-end":"outgoing"===o,"d-none":-1===c}),y=(0,u.default)({"chat-message-avatar-container-received":"received"===o,"chat-message-avatar-container-outgoing":"outgoing"===o}),_=(0,u.default)("chat-message-avatar","chat-message-avatar-".concat(o),"mb-2","text-muted",i,{"d-none":void 0===r,"float-start":"received"===o,"float-end":"outgoing"===o});return l.default.createElement("div",a({id:n,className:m},p),l.default.createElement("div",{className:v,style:{maxWidth:"75%"}},l.default.createElement("div",{className:h},t),l.default.createElement("p",{className:g},(0,d.formatTimestamp)(c))),l.default.createElement("div",{className:y,style:void 0!==r?{width:"53px"}:{}},l.default.createElement(f,{src:r,direction:o,className:_})))};p.defaultProps={avatar:void 0,timestamp:-1},t.default=p},777:function(e,t,n){"use strict";var a=this&&this.__assign||function(){return a=Object.assign||function(e){for(var t,n=1,a=arguments.length;n<a;n++)for(var r in t=arguments[n])Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r]);return e},a.apply(this,arguments)},r=this&&this.__createBinding||(Object.create?function(e,t,n,a){void 0===a&&(a=n);var r=Object.getOwnPropertyDescriptor(t,n);r&&!("get"in r?!t.__esModule:r.writable||r.configurable)||(r={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,a,r)}:function(e,t,n,a){void 0===a&&(a=n),e[a]=t[n]}),i=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),o=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)"default"!==n&&Object.prototype.hasOwnProperty.call(e,n)&&r(t,e,n);return i(t,e),t},s=this&&this.__rest||function(e,t){var n={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&t.indexOf(a)<0&&(n[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var r=0;for(a=Object.getOwnPropertySymbols(e);r<a.length;r++)t.indexOf(a[r])<0&&Object.prototype.propertyIsEnumerable.call(e,a[r])&&(n[a[r]]=e[a[r]])}return n},c=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};t.__esModule=!0;var l=o(n(812)),u=c(n(184)),d=function(e){e.setProps;var t=e.children,n=e.id,r=e.className,i=e.avatarReceived,o=e.avatarOutgoing,c=e.timestamp,d=s(e,["setProps","children","id","className","avatarReceived","avatarOutgoing","timestamp"]),f=(0,l.useRef)(null),p=(0,u.default)("vstack","w-100","position-relative","overflow-auto",r,{"avatar-received-none":!i,"avatar-outgoing-none":!o,"timestamp-none":!c});return(0,l.useEffect)((function(){var e,t;null==(t=null===(e=f.current)||void 0===e?void 0:e.lastElementChild)||t.scrollIntoView({behavior:"instant"})}),[t]),l.default.createElement("div",a({id:n,ref:f,className:p},d),t)};d.defaultProps={avatarReceived:!0,avatarOutgoing:!1,timestamp:!0},t.default=d},991:function(e,t,n){"use strict";var a=this&&this.__rest||function(e,t){var n={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&t.indexOf(a)<0&&(n[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var r=0;for(a=Object.getOwnPropertySymbols(e);r<a.length;r++)t.indexOf(a[r])<0&&Object.prototype.propertyIsEnumerable.call(e,a[r])&&(n[a[r]]=e[a[r]])}return n},r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};t.__esModule=!0;var i=r(n(812));n(713),n(811);var o=r(n(472)),s=function(e){var t=e.setProps,n=(e.id,e.avatar),r=e.className,s=e.direction;return a(e,["setProps","id","avatar","className","direction"]),i.default.createElement(o.default,{setProps:t,avatar:n,direction:s,className:r},i.default.createElement("div",{className:"typing"},i.default.createElement("div",{className:"typing__dot"}),i.default.createElement("div",{className:"typing__dot"}),i.default.createElement("div",{className:"typing__dot"})))};s.defaultProps={avatar:void 0,timestamp:-1},t.default=s},294:function(e,t,n){"use strict";var a=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};t.__esModule=!0,t.ChatMessageTyping=t.ChatMessageList=t.ChatMessage=t.ChatInput=t.Chat=void 0;var r=a(n(91));t.Chat=r.default;var i=a(n(806));t.ChatInput=i.default;var o=a(n(472));t.ChatMessage=o.default;var s=a(n(777));t.ChatMessageList=s.default;var c=a(n(991));t.ChatMessageTyping=c.default},605:(e,t)=>{"use strict";t.__esModule=!0,t.formatTimestamp=void 0,t.formatTimestamp=function(e,t){void 0===t&&(t="en-GB");var n=new Date(e),a={year:"numeric",month:"numeric",day:"numeric"};return new Intl.DateTimeFormat(t,a).format(n)===new Intl.DateTimeFormat(t,a).format(new Date)?new Intl.DateTimeFormat(t,{hour:"numeric",minute:"numeric"}).format(n):new Intl.DateTimeFormat(t,{year:"numeric",month:"short",day:"numeric",hour:"numeric",minute:"numeric"}).format(n)}},812:t=>{"use strict";t.exports=e}},n={};function a(e){var r=n[e];if(void 0!==r)return r.exports;var i=n[e]={id:e,exports:{}};return t[e].call(i.exports,i,i.exports,a),i.exports}return a.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return a.d(t,{a:t}),t},a.d=(e,t)=>{for(var n in t)a.o(t,n)&&!a.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},a.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),a.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},a.nc=void 0,a(294)})()));
\ No newline at end of file
diff --git a/inst/deps/dash_chat_components.js.LICENSE.txt b/inst/deps/dash_chat_components.js.LICENSE.txt
deleted file mode 100644
index 827f273..0000000
--- a/inst/deps/dash_chat_components.js.LICENSE.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-/*!
-	Copyright (c) 2018 Jed Watson.
-	Licensed under the MIT License (MIT), see
-	http://jedwatson.github.io/classnames
-*/
diff --git a/justfile b/justfile
index 614e941..fdb8c58 100644
--- a/justfile
+++ b/justfile
@@ -40,6 +40,23 @@ clean:
     rm -rf dist
     rm -rf build
 
+# Remove generated code
+clean-gen:
+    rm -f Manifest.toml
+    rm -f JuliaManifest.toml
+    rm -rf inst
+    rm -rf man
+    rm -rf R
+    rm -f DESCRIPTION
+    rm -f NAMESPACE
+    rm -rf deps
+    rm -rf src/*.jl
+    rm -rf src/jl
+    rm -f Project.toml
+    find dash_chat_components -type f -not -name '__init__.py' -delete
+    rm -rf dash_chat_components/__pycache__
+    rm -rf dash_chat_components.egg-info
+
 # Format source code
 format:
     npx prettier --write src/ts/
\ No newline at end of file
diff --git a/man/chat.Rd b/man/chat.Rd
deleted file mode 100644
index 40a4e40..0000000
--- a/man/chat.Rd
+++ /dev/null
@@ -1,32 +0,0 @@
-% Auto-generated: do not edit by hand
-\name{chat}
-
-\alias{chat}
-
-\title{Chat component}
-
-\description{
-Main chat container
-}
-
-\usage{
-chat(children=NULL, id=NULL, className=NULL, height=NULL,
-style=NULL, width=NULL)
-}
-
-\arguments{
-\item{children}{A list of or a singular dash component, string or number. Content of the chat}
-
-\item{id}{Character. Unique ID to identify this component in Dash callbacks.}
-
-\item{className}{Character. Often used with CSS to style elements with common properties.}
-
-\item{height}{Numeric. Height of the chat container}
-
-\item{style}{Logical | numeric | character | named list | unnamed list. Defines CSS styles which will override styles previously set.}
-
-\item{width}{Numeric. Width of the chat container}
-}
-
-\value{named list of JSON elements corresponding to React.js properties and their values}
-
diff --git a/man/chatInput.Rd b/man/chatInput.Rd
deleted file mode 100644
index 161bd70..0000000
--- a/man/chatInput.Rd
+++ /dev/null
@@ -1,69 +0,0 @@
-% Auto-generated: do not edit by hand
-\name{chatInput}
-
-\alias{chatInput}
-
-\title{ChatInput component}
-
-\description{
-Capture chat input from user
-}
-
-\usage{
-chatInput(id=NULL, autofocus=NULL, className=NULL, debounce=NULL,
-disabled=NULL, maxlength=NULL, n_submit=NULL,
-n_submit_timestamp=NULL, persisted_props=NULL,
-persistence=NULL, persistence_type=NULL, placeholder=NULL,
-rows=NULL, style=NULL, value=NULL, value_on_submit=NULL)
-}
-
-\arguments{
-\item{id}{Character. Unique ID to identify this component in Dash callbacks.}
-
-\item{autofocus}{Logical. The element should be automatically focused after the page loaded.}
-
-\item{className}{Character. Often used with CSS to style elements with common properties.}
-
-\item{debounce}{Logical. If True, changes to input will be sent back to the Dash server only
-on enter or when losing focus. If it's False, it will sent the value
-back on every change.}
-
-\item{disabled}{Logical. Indicates whether the user can interact with the element.}
-
-\item{maxlength}{Numeric. Defines the maximum number of characters allowed in the input element.}
-
-\item{n_submit}{Numeric. An integer that represents the number of times that the Enter key was
-pressed while the input area had focus or submit button has been clicked on.}
-
-\item{n_submit_timestamp}{Numeric. An integer that represents the time (in ms since 1970) at which n_submit
-changed.}
-
-\item{persisted_props}{List of characters. Properties whose user interactions will persist after refreshing the
-component or the page. Since only `value` is allowed this prop can
-normally be ignored.}
-
-\item{persistence}{Character | numeric. Used to allow user interactions in this component to be persisted when
-the component - or the page - is refreshed. If `persisted` is truthy and
-hasn't changed from its previous value, a `value` that the user has
-changed while using the app will keep that change, as long as
-the new `value` also matches what was given originally.
-Used in conjunction with `persistence_type`.}
-
-\item{persistence_type}{A value equal to: 'local', 'session', 'memory'. Where persisted user changes will be stored:
-memory: only kept in memory, reset on page refresh.
-local: window.localStorage, data is kept after the browser quit.
-session: window.sessionStorage, data is cleared once the browser quit.}
-
-\item{placeholder}{Character. Provides a hint to the user of what can be entered in the field.}
-
-\item{rows}{Numeric. Defines the number of rows in a text input area.}
-
-\item{style}{Logical | numeric | character | named list | unnamed list. Defines CSS styles which will override styles previously set.}
-
-\item{value}{Character. Input value for controlled component.}
-
-\item{value_on_submit}{Character. Input value for controlled component after submit.}
-}
-
-\value{named list of JSON elements corresponding to React.js properties and their values}
-
diff --git a/man/chatMessage.Rd b/man/chatMessage.Rd
deleted file mode 100644
index b2daed9..0000000
--- a/man/chatMessage.Rd
+++ /dev/null
@@ -1,34 +0,0 @@
-% Auto-generated: do not edit by hand
-\name{chatMessage}
-
-\alias{chatMessage}
-
-\title{ChatMessage component}
-
-\description{
-Display single chat message
-}
-
-\usage{
-chatMessage(children=NULL, id=NULL, avatar=NULL, className=NULL,
-direction=NULL, style=NULL, timestamp=NULL)
-}
-
-\arguments{
-\item{children}{A list of or a singular dash component, string or number. Content of the message}
-
-\item{id}{Character. Unique ID to identify this component in Dash callbacks.}
-
-\item{avatar}{Character. Avatar}
-
-\item{className}{Character. Often used with CSS to style elements with common properties.}
-
-\item{direction}{Character. Direction of the mssage: received or outgoing}
-
-\item{style}{Logical | numeric | character | named list | unnamed list. Defines CSS styles which will override styles previously set.}
-
-\item{timestamp}{Numeric. Time}
-}
-
-\value{named list of JSON elements corresponding to React.js properties and their values}
-
diff --git a/man/chatMessageList.Rd b/man/chatMessageList.Rd
deleted file mode 100644
index a43ca61..0000000
--- a/man/chatMessageList.Rd
+++ /dev/null
@@ -1,35 +0,0 @@
-% Auto-generated: do not edit by hand
-\name{chatMessageList}
-
-\alias{chatMessageList}
-
-\title{ChatMessageList component}
-
-\description{
-Display list of chat messages
-}
-
-\usage{
-chatMessageList(children=NULL, id=NULL, avatarOutgoing=NULL,
-avatarReceived=NULL, className=NULL, style=NULL,
-timestamp=NULL)
-}
-
-\arguments{
-\item{children}{A list of or a singular dash component, string or number. ChatMessageList content}
-
-\item{id}{Character. Unique ID to identify this component in Dash callbacks.}
-
-\item{avatarOutgoing}{Logical. Indicates whether the outgoing message avatar should be displayed.}
-
-\item{avatarReceived}{Logical. Indicates whether the recieved message avatar should be displayed.}
-
-\item{className}{Character. Often used with CSS to style elements with common properties.}
-
-\item{style}{Logical | numeric | character | named list | unnamed list. Defines CSS styles which will override styles previously set.}
-
-\item{timestamp}{Logical. Indicates whether the message timestamp should be displayed.}
-}
-
-\value{named list of JSON elements corresponding to React.js properties and their values}
-
diff --git a/man/chatMessageTyping.Rd b/man/chatMessageTyping.Rd
deleted file mode 100644
index 998eeb3..0000000
--- a/man/chatMessageTyping.Rd
+++ /dev/null
@@ -1,30 +0,0 @@
-% Auto-generated: do not edit by hand
-\name{chatMessageTyping}
-
-\alias{chatMessageTyping}
-
-\title{ChatMessageTyping component}
-
-\description{
-Display user typing message
-}
-
-\usage{
-chatMessageTyping(id=NULL, avatar=NULL, className=NULL, direction=NULL,
-style=NULL)
-}
-
-\arguments{
-\item{id}{Character. Unique ID to identify this component in Dash callbacks.}
-
-\item{avatar}{Character. Avatar}
-
-\item{className}{Character. Often used with CSS to style elements with common properties.}
-
-\item{direction}{Character. Direction of the mssage: received or outgoing}
-
-\item{style}{Logical | numeric | character | named list | unnamed list. Defines CSS styles which will override styles previously set.}
-}
-
-\value{named list of JSON elements corresponding to React.js properties and their values}
-
diff --git a/package.json b/package.json
index ae9a027..430c634 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "dash-chat-components",
-  "version": "0.0.3",
+  "version": "{{VERSION_PLACEHOLDER}}",
   "description": "Chat components for Plotly Dash",
   "main": "index.ts",
   "repository": {
diff --git a/src/DashChatComponents.jl b/src/DashChatComponents.jl
deleted file mode 100644
index b2e4790..0000000
--- a/src/DashChatComponents.jl
+++ /dev/null
@@ -1,40 +0,0 @@
-
-module DashChatComponents
-using Dash
-
-const resources_path = realpath(joinpath( @__DIR__, "..", "deps"))
-const version = "0.0.3"
-
-include("jl/chat.jl")
-include("jl/chatinput.jl")
-include("jl/chatmessage.jl")
-include("jl/chatmessagelist.jl")
-include("jl/chatmessagetyping.jl")
-
-function __init__()
-    DashBase.register_package(
-        DashBase.ResourcePkg(
-            "dash_chat_components",
-            resources_path,
-            version = version,
-            [
-                DashBase.Resource(
-    relative_package_path = "dash_chat_components.js",
-    external_url = nothing,
-    dynamic = nothing,
-    async = nothing,
-    type = :js
-),
-DashBase.Resource(
-    relative_package_path = "dash_chat_components.js.map",
-    external_url = nothing,
-    dynamic = true,
-    async = nothing,
-    type = :js
-)
-            ]
-        )
-
-    )
-end
-end
diff --git a/src/jl/chat.jl b/src/jl/chat.jl
deleted file mode 100644
index 1759221..0000000
--- a/src/jl/chat.jl
+++ /dev/null
@@ -1,29 +0,0 @@
-# AUTO GENERATED FILE - DO NOT EDIT
-
-export chat
-
-"""
-    chat(;kwargs...)
-    chat(children::Any;kwargs...)
-    chat(children_maker::Function;kwargs...)
-
-
-A Chat component.
-Main chat container
-Keyword arguments:
-- `children` (a list of or a singular dash component, string or number; optional): Content of the chat
-- `id` (String; optional): Unique ID to identify this component in Dash callbacks.
-- `className` (String; optional): Often used with CSS to style elements with common properties.
-- `height` (Real; optional): Height of the chat container
-- `style` (Bool | Real | String | Dict | Array; optional): Defines CSS styles which will override styles previously set.
-- `width` (Real; optional): Width of the chat container
-"""
-function chat(; kwargs...)
-        available_props = Symbol[:children, :id, :className, :height, :style, :width]
-        wild_props = Symbol[]
-        return Component("chat", "Chat", "dash_chat_components", available_props, wild_props; kwargs...)
-end
-
-chat(children::Any; kwargs...) = chat(;kwargs..., children = children)
-chat(children_maker::Function; kwargs...) = chat(children_maker(); kwargs...)
-
diff --git a/src/jl/chatinput.jl b/src/jl/chatinput.jl
deleted file mode 100644
index d616407..0000000
--- a/src/jl/chatinput.jl
+++ /dev/null
@@ -1,47 +0,0 @@
-# AUTO GENERATED FILE - DO NOT EDIT
-
-export chatinput
-
-"""
-    chatinput(;kwargs...)
-
-A ChatInput component.
-Capture chat input from user
-Keyword arguments:
-- `id` (String; optional): Unique ID to identify this component in Dash callbacks.
-- `autofocus` (Bool; optional): The element should be automatically focused after the page loaded.
-- `className` (String; optional): Often used with CSS to style elements with common properties.
-- `debounce` (Bool; optional): If True, changes to input will be sent back to the Dash server only
-on enter or when losing focus. If it's False, it will sent the value
-back on every change.
-- `disabled` (Bool; optional): Indicates whether the user can interact with the element.
-- `maxlength` (Real; optional): Defines the maximum number of characters allowed in the input element.
-- `n_submit` (Real; optional): An integer that represents the number of times that the Enter key was
-pressed while the input area had focus or submit button has been clicked on.
-- `n_submit_timestamp` (Real; optional): An integer that represents the time (in ms since 1970) at which n_submit
-changed.
-- `persisted_props` (Array of Strings; optional): Properties whose user interactions will persist after refreshing the
-component or the page. Since only `value` is allowed this prop can
-normally be ignored.
-- `persistence` (String | Real; optional): Used to allow user interactions in this component to be persisted when
-the component - or the page - is refreshed. If `persisted` is truthy and
-hasn't changed from its previous value, a `value` that the user has
-changed while using the app will keep that change, as long as
-the new `value` also matches what was given originally.
-Used in conjunction with `persistence_type`.
-- `persistence_type` (a value equal to: 'local', 'session', 'memory'; optional): Where persisted user changes will be stored:
-memory: only kept in memory, reset on page refresh.
-local: window.localStorage, data is kept after the browser quit.
-session: window.sessionStorage, data is cleared once the browser quit.
-- `placeholder` (String; optional): Provides a hint to the user of what can be entered in the field.
-- `rows` (Real; optional): Defines the number of rows in a text input area.
-- `style` (Bool | Real | String | Dict | Array; optional): Defines CSS styles which will override styles previously set.
-- `value` (String; optional): Input value for controlled component.
-- `value_on_submit` (String; optional): Input value for controlled component after submit.
-"""
-function chatinput(; kwargs...)
-        available_props = Symbol[:id, :autofocus, :className, :debounce, :disabled, :maxlength, :n_submit, :n_submit_timestamp, :persisted_props, :persistence, :persistence_type, :placeholder, :rows, :style, :value, :value_on_submit]
-        wild_props = Symbol[]
-        return Component("chatinput", "ChatInput", "dash_chat_components", available_props, wild_props; kwargs...)
-end
-
diff --git a/src/jl/chatmessage.jl b/src/jl/chatmessage.jl
deleted file mode 100644
index 11d0683..0000000
--- a/src/jl/chatmessage.jl
+++ /dev/null
@@ -1,30 +0,0 @@
-# AUTO GENERATED FILE - DO NOT EDIT
-
-export chatmessage
-
-"""
-    chatmessage(;kwargs...)
-    chatmessage(children::Any;kwargs...)
-    chatmessage(children_maker::Function;kwargs...)
-
-
-A ChatMessage component.
-Display single chat message
-Keyword arguments:
-- `children` (a list of or a singular dash component, string or number; optional): Content of the message
-- `id` (String; optional): Unique ID to identify this component in Dash callbacks.
-- `avatar` (String; optional): Avatar
-- `className` (String; optional): Often used with CSS to style elements with common properties.
-- `direction` (String; required): Direction of the mssage: received or outgoing
-- `style` (Bool | Real | String | Dict | Array; optional): Defines CSS styles which will override styles previously set.
-- `timestamp` (Real; optional): Time
-"""
-function chatmessage(; kwargs...)
-        available_props = Symbol[:children, :id, :avatar, :className, :direction, :style, :timestamp]
-        wild_props = Symbol[]
-        return Component("chatmessage", "ChatMessage", "dash_chat_components", available_props, wild_props; kwargs...)
-end
-
-chatmessage(children::Any; kwargs...) = chatmessage(;kwargs..., children = children)
-chatmessage(children_maker::Function; kwargs...) = chatmessage(children_maker(); kwargs...)
-
diff --git a/src/jl/chatmessagelist.jl b/src/jl/chatmessagelist.jl
deleted file mode 100644
index b302170..0000000
--- a/src/jl/chatmessagelist.jl
+++ /dev/null
@@ -1,30 +0,0 @@
-# AUTO GENERATED FILE - DO NOT EDIT
-
-export chatmessagelist
-
-"""
-    chatmessagelist(;kwargs...)
-    chatmessagelist(children::Any;kwargs...)
-    chatmessagelist(children_maker::Function;kwargs...)
-
-
-A ChatMessageList component.
-Display list of chat messages
-Keyword arguments:
-- `children` (a list of or a singular dash component, string or number; optional): ChatMessageList content
-- `id` (String; optional): Unique ID to identify this component in Dash callbacks.
-- `avatarOutgoing` (Bool; optional): Indicates whether the outgoing message avatar should be displayed.
-- `avatarReceived` (Bool; optional): Indicates whether the recieved message avatar should be displayed.
-- `className` (String; optional): Often used with CSS to style elements with common properties.
-- `style` (Bool | Real | String | Dict | Array; optional): Defines CSS styles which will override styles previously set.
-- `timestamp` (Bool; optional): Indicates whether the message timestamp should be displayed.
-"""
-function chatmessagelist(; kwargs...)
-        available_props = Symbol[:children, :id, :avatarOutgoing, :avatarReceived, :className, :style, :timestamp]
-        wild_props = Symbol[]
-        return Component("chatmessagelist", "ChatMessageList", "dash_chat_components", available_props, wild_props; kwargs...)
-end
-
-chatmessagelist(children::Any; kwargs...) = chatmessagelist(;kwargs..., children = children)
-chatmessagelist(children_maker::Function; kwargs...) = chatmessagelist(children_maker(); kwargs...)
-
diff --git a/src/jl/chatmessagetyping.jl b/src/jl/chatmessagetyping.jl
deleted file mode 100644
index 3647b4d..0000000
--- a/src/jl/chatmessagetyping.jl
+++ /dev/null
@@ -1,22 +0,0 @@
-# AUTO GENERATED FILE - DO NOT EDIT
-
-export chatmessagetyping
-
-"""
-    chatmessagetyping(;kwargs...)
-
-A ChatMessageTyping component.
-Display user typing message
-Keyword arguments:
-- `id` (String; optional): Unique ID to identify this component in Dash callbacks.
-- `avatar` (String; optional): Avatar
-- `className` (String; optional): Often used with CSS to style elements with common properties.
-- `direction` (String; required): Direction of the mssage: received or outgoing
-- `style` (Bool | Real | String | Dict | Array; optional): Defines CSS styles which will override styles previously set.
-"""
-function chatmessagetyping(; kwargs...)
-        available_props = Symbol[:id, :avatar, :className, :direction, :style]
-        wild_props = Symbol[]
-        return Component("chatmessagetyping", "ChatMessageTyping", "dash_chat_components", available_props, wild_props; kwargs...)
-end
-
diff --git a/src/ts/components/Chat.tsx b/src/ts/components/Chat.tsx
index 2e5febe..d46d026 100644
--- a/src/ts/components/Chat.tsx
+++ b/src/ts/components/Chat.tsx
@@ -6,24 +6,16 @@ type Props = {
    * Content of the chat
    */
   children?: React.ReactNode;
-  /**
-   * Height of the chat container
-   */
-  height?: number;
-  /**
-   * Width of the chat container
-   */
-  width?: number;
 } & DashComponentProps;
 
 /**
  * Main chat container
  */
 const Chat = (props: Props) => {
-  const { setProps, id, children, height, width, ...other } = props;
+  const { setProps, id, children, ...other } = props;
 
   return (
-    <div id={id} style={{ height: height }} {...other}>
+    <div id={id} {...other}>
       {children}
     </div>
   );
diff --git a/src/ts/components/ChatInput.tsx b/src/ts/components/ChatInput.tsx
index 72774f5..9ef787b 100644
--- a/src/ts/components/ChatInput.tsx
+++ b/src/ts/components/ChatInput.tsx
@@ -34,19 +34,19 @@ type Props = {
   /**
    * Provides a hint to the user of what can be entered in the field.
    */
-  placeholder: string;
+  placeholder?: string;
   /**
    * Defines the number of rows in a text input area.
    */
   rows?: number;
-  /**
-   * Input value for controlled component.
-   */
-  value?: string;
   /**
    * Input value for controlled component after submit.
    */
   value_on_submit: string;
+  /**
+   * Input value for controlled component.
+   */
+  value?: string;
 } & DashComponentProps &
   PersistenceProps;
 
@@ -58,19 +58,19 @@ const ChatInput = (props: Props) => {
     setProps,
     id,
     className,
-    value,
     autofocus,
     debounce,
     disabled,
     maxlength,
-    n_submit,
     n_submit_timestamp,
-    value_on_submit,
-    placeholder,
-    persistence,
+    n_submit,
     persisted_props,
     persistence_type,
+    persistence,
+    placeholder,
     rows,
+    value_on_submit,
+    value,
     ...other
   } = props;
 
@@ -80,7 +80,15 @@ const ChatInput = (props: Props) => {
   const inputClass = classNames("position-relative", className);
   const textareaClass = classNames("form-control");
   const btnClass = classNames(
-    "btn btn-outline-primary border-0 position-absolute bottom-0 end-0 m-1 rounded-4"
+    "btn",
+    "btn-lg",
+    "btn-outline-primary",
+    "border-0",
+    "position-absolute",
+    "bottom-0",
+    "end-0",
+    "m-1",
+    "rounded-4"
   );
 
   useEffect(() => {
@@ -91,7 +99,7 @@ const ChatInput = (props: Props) => {
 
   useEffect(() => {
     if (value !== valueState) {
-      setValueState(value || undefined);
+      setValueState(value || "");
     }
   }, [value]);
 
@@ -117,19 +125,24 @@ const ChatInput = (props: Props) => {
       e.shiftKey === false
     ) {
       e.preventDefault();
-      const payload: Record<string, any> = {
-        n_submit: n_submit + 1,
-        n_submit_timestamp: Date.now(),
-        value_on_submit: inputRef.current.value,
-        value: undefined,
-      };
-      setValueState(undefined);
-      setProps(payload);
+      if (value.trim() !== "") {
+        const payload: Record<string, any> = {
+          n_submit: n_submit + 1,
+          n_submit_timestamp: Date.now(),
+          value_on_submit: inputRef.current.value,
+          value: "",
+        };
+        setValueState(undefined);
+        setProps(payload);
+      }
     }
   };
 
   const onClick = () => {
-    if (setProps) {
+    if (
+      setProps &&
+      value.trim() !== ""
+    ) {
       const payload: Record<string, any> = {
         n_submit: n_submit + 1,
         n_submit_timestamp: Date.now(),
@@ -144,29 +157,29 @@ const ChatInput = (props: Props) => {
   return (
     <div id={id} className={inputClass} {...other}>
       <textarea
-        ref={inputRef}
-        className={textareaClass}
-        onChange={onChange}
-        onBlur={onBlur}
-        onKeyDown={onKeyDown}
         autoFocus={autofocus}
+        className={textareaClass}
         disabled={disabled}
         maxLength={maxlength}
-        rows={rows}
+        onBlur={onBlur}
+        onChange={onChange}
+        onKeyDown={onKeyDown}
         placeholder={placeholder}
+        ref={inputRef}
+        rows={rows}
         style={{ paddingRight: "50px" }}
         value={value}
       />
       <button
         type="button"
-        onClick={onClick}
-        disabled={disabled}
         className={btnClass}
+        disabled={disabled || value.trim() === ""}
+        onClick={onClick}
       >
         <svg
           xmlns="http://www.w3.org/2000/svg"
-          width="16"
-          height="16"
+          width="18"
+          height="18"
           fill="currentColor"
           viewBox="0 0 16 16"
         >
@@ -178,18 +191,16 @@ const ChatInput = (props: Props) => {
 };
 
 ChatInput.defaultProps = {
-  value: "",
-  placeholder: "Type a message...",
   debounce: false,
   maxlength: 4000,
-  n_clicks: 0,
-  n_clicks_timestamp: -1,
-  n_submit: 0,
   n_submit_timestamp: -1,
-  value_on_submit: "",
+  n_submit: 0,
   persisted_props: ["value"],
   persistence_type: "local",
+  placeholder: "Type a message...",
   rows: 2,
+  value_on_submit: "",
+  value: "",
 };
 
 export default ChatInput;
diff --git a/src/ts/components/ChatMessage.css b/src/ts/components/ChatMessage.css
index ee4e2f3..710c186 100644
--- a/src/ts/components/ChatMessage.css
+++ b/src/ts/components/ChatMessage.css
@@ -1,3 +1,19 @@
+.chat-message-received .chat-message-content {
+  border-bottom-left-radius: 0 !important;
+}
+
+.chat-message-received + .chat-message-received .chat-message-content {
+  border-top-left-radius: 0 !important;
+}
+
+.chat-message-outgoing .chat-message-content {
+  border-bottom-right-radius: 0 !important;
+}
+
+.chat-message-outgoing + .chat-message-outgoing .chat-message-content {
+  border-top-right-radius: 0 !important;
+}
+
 .chat-message-received + .chat-message-outgoing,
 .chat-message-outgoing + .chat-message-received {
   margin-top: 10px;
diff --git a/src/ts/components/ChatMessageList.tsx b/src/ts/components/ChatMessageList.tsx
index fd263f1..b846052 100644
--- a/src/ts/components/ChatMessageList.tsx
+++ b/src/ts/components/ChatMessageList.tsx
@@ -43,10 +43,10 @@ const ChatMessageList = (props: Props) => {
     "position-relative",
     "overflow-auto",
     className, {
-      "avatar-received-none": !avatarReceived,
-      "avatar-outgoing-none": !avatarOutgoing,
-      "timestamp-none": !timestamp,
-    }
+    "avatar-received-none": !avatarReceived,
+    "avatar-outgoing-none": !avatarOutgoing,
+    "timestamp-none": !timestamp,
+  }
   );
 
   const scrollToLastMessage = () => {
diff --git a/src/ts/components/ChatMessageTyping.tsx b/src/ts/components/ChatMessageTyping.tsx
index efbce7a..a981169 100644
--- a/src/ts/components/ChatMessageTyping.tsx
+++ b/src/ts/components/ChatMessageTyping.tsx
@@ -30,7 +30,12 @@ const ChatMessageTyping = (props: Props) => {
 
 
     return (
-        <ChatMessage setProps={setProps} avatar={avatar} direction={direction} className={className}>
+        <ChatMessage setProps={setProps}
+            avatar={avatar}
+            className={className}
+            direction={direction}
+            {...other}
+        >
             <div className="typing">
                 <div className="typing__dot"></div>
                 <div className="typing__dot"></div>
diff --git a/src/ts/components/ChatSimple.tsx b/src/ts/components/ChatSimple.tsx
new file mode 100644
index 0000000..1fc5e1f
--- /dev/null
+++ b/src/ts/components/ChatSimple.tsx
@@ -0,0 +1,198 @@
+import React, { useEffect } from "react";
+import { DashComponentProps, PersistenceProps } from "../props";
+import { ChatInput, ChatMessageList, ChatMessage, ChatMessageTyping } from "..";
+
+type Props = {
+  /**
+   * Messages list
+   */
+  messages?: Array<{
+    /**
+     * Avatar
+     */
+    avatar: string;
+    /**
+     * Direction of the mssage: received or outgoing
+     */
+    direction: string;
+    /**
+     * Content of the message
+     */
+    content: string;
+    /**
+     * Time
+     */
+    timestamp: number;
+  }>;
+  /**
+   * Indicates whether the recieved message avatar should be displayed.
+   */
+  avatarReceived?: string;
+  /**
+   * Indicates whether the outgoing message avatar should be displayed.
+   */
+  avatarOutgoing?: string;
+  /**
+   * Indicates whether the message timestamp should be displayed.
+   */
+  timestampDisplay: boolean;
+  /**
+   * The element should be automatically focused after the page loaded.
+   */
+  autofocus?: boolean;
+  /**
+   * If True, changes to input will be sent back to the Dash server only
+   * on enter or when losing focus. If it's False, it will sent the value
+   * back on every change.
+   */
+  debounce: boolean;
+  /**
+   * Indicates whether the user can interact with the element.
+   */
+  disabled?: boolean;
+  /**
+   * Defines the maximum number of characters allowed in the input element.
+   */
+  maxlength?: number;
+  /**
+   * An integer that represents the number of times that the Enter key was
+   * pressed while the input area had focus or submit button has been clicked on.
+   */
+  n_submit: number;
+  /**
+   * An integer that represents the time (in ms since 1970) at which n_submit
+   * changed.
+   */
+  n_submit_timestamp: number;
+  /**
+   * Provides a hint to the user of what can be entered in the field.
+   */
+  placeholder?: string;
+  /**
+   * Defines the number of rows in a text input area.
+   */
+  rows?: number;
+  /**
+   * Input value for controlled component.
+   */
+  value?: string;
+  /**
+   * Input value for controlled component after submit.
+   */
+  value_on_submit: string;
+} & DashComponentProps &
+  PersistenceProps;
+
+/**
+ * Simple chat component
+ */
+const ChatSimple = (props: Props) => {
+  const {
+    setProps,
+    messages,
+    id,
+    className,
+    avatarReceived,
+    avatarOutgoing,
+    timestampDisplay,
+    value,
+    autofocus,
+    debounce,
+    disabled,
+    maxlength,
+    n_submit,
+    n_submit_timestamp,
+    value_on_submit,
+    placeholder,
+    persistence,
+    persisted_props,
+    persistence_type,
+    rows,
+    ...other
+  } = props;
+
+  useEffect(() => {
+    if (value_on_submit !== "") {
+      messages.push({
+        avatar: avatarOutgoing,
+        direction: "outgoing",
+        content: value_on_submit,
+        timestamp: new Date().getTime(),
+      });
+      setProps({ messages: messages });
+    }
+  }, [value_on_submit]);
+
+  useEffect(() => {
+    if (messages[messages.length - 1].direction === "outgoing") {
+      setProps({ disabled: true });
+    } else {
+      setProps({ disabled: false });
+    }
+  }, [messages, value_on_submit]);
+
+  return (
+    <div id={id} className={className} {...other}>
+      <ChatMessageList
+        setProps={setProps}
+        avatarReceived={avatarReceived !== undefined}
+        avatarOutgoing={avatarOutgoing !== undefined}
+        timestamp={timestampDisplay}
+        className="px-2"
+        style={{ height: "calc(100% - 65px)" }}
+      >
+        {messages.map((m) => (
+          <ChatMessage
+            setProps={setProps}
+            avatar={m.avatar}
+            direction={m.direction}
+            timestamp={m.timestamp}
+          >
+            {m.content}
+          </ChatMessage>
+        ))}
+        {messages[messages.length - 1].direction === "outgoing" ? (
+          <ChatMessageTyping
+            setProps={setProps}
+            avatar={avatarReceived}
+            direction="received"
+          />
+        ) : (
+          <></>
+        )}
+      </ChatMessageList>
+      <ChatInput
+        setProps={setProps}
+        autofocus={autofocus}
+        className="mt-2 mx-2"
+        debounce={debounce}
+        disabled={disabled}
+        maxlength={maxlength}
+        n_submit_timestamp={n_submit_timestamp}
+        n_submit={n_submit}
+        persisted_props={persisted_props}
+        persistence_type={persistence_type}
+        persistence={persistence}
+        placeholder={placeholder}
+        rows={rows}
+        style={{ height: "65px" }}
+        value_on_submit={value_on_submit}
+        value={value}
+      />
+    </div>
+  );
+};
+
+ChatSimple.defaultProps = {
+  avatarReceived: "",
+  debounce: false,
+  n_submit_timestamp: -1,
+  n_submit: 0,
+  persisted_props: ["value"],
+  persistence_type: "local",
+  timestampDisplay: true,
+  value_on_submit: "",
+  value: "",
+};
+
+export default ChatSimple;
diff --git a/src/ts/index.ts b/src/ts/index.ts
index 538aead..5cbe10c 100644
--- a/src/ts/index.ts
+++ b/src/ts/index.ts
@@ -3,5 +3,13 @@ import ChatInput from "./components/ChatInput";
 import ChatMessage from "./components/ChatMessage";
 import ChatMessageList from "./components/ChatMessageList";
 import ChatMessageTyping from "./components/ChatMessageTyping";
+import ChatSimple from "./components/ChatSimple";
 
-export { Chat, ChatInput, ChatMessage, ChatMessageList, ChatMessageTyping };
+export {
+  Chat,
+  ChatInput,
+  ChatMessage,
+  ChatMessageList,
+  ChatMessageTyping,
+  ChatSimple,
+};
diff --git a/usage.py b/usage.py
index cad4cc8..cb94638 100644
--- a/usage.py
+++ b/usage.py
@@ -85,7 +85,7 @@
 ], style={
     'height': 'calc(100vh - 40px)',
     'margin': '20px auto',
-    'max-width': '900px'
+    'maxWidth': '900px'
 })
 
 
diff --git a/usage_simple.py b/usage_simple.py
new file mode 100644
index 0000000..1dcc729
--- /dev/null
+++ b/usage_simple.py
@@ -0,0 +1,92 @@
+import math
+import time
+
+import dash
+from dash import Input, Output, State, html
+from dash.exceptions import PreventUpdate
+
+import dash_chat_components as dch
+
+app = dash.Dash(__name__)
+
+app = dash.Dash(
+    external_stylesheets=[
+        "https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css"
+    ]
+)
+
+messages = [
+    {
+        "direction": "outgoing",
+        "avatar": "user.png",
+        "content": "Hi there! I've been thinking about visiting Rome. Have you ever been there?",
+        "timestamp": int(math.floor(time.time() * 1000)),
+    },
+    {
+        "direction": "received",
+        "avatar": "bot.png",
+        "content": "Hello!",
+        "timestamp": int(math.floor(time.time() * 1000)),
+    },
+    {
+        "direction": "received",
+        "avatar": "bot.png",
+        "content": "While I haven't been to Rome myself, I have a lot of information about the city.",
+        "timestamp": int(math.floor(time.time())),
+    },
+    {
+        "direction": "received",
+        "avatar": "bot.png",
+        "content": "Is there anything specific you'd like to know about Rome?",
+        "timestamp": int(math.floor(time.time() * 1000)),
+    },
+    {
+        "direction": "outgoing",
+        "avatar": "user.png",
+        "content": "That's great! I've heard about the Colosseum and the Vatican. Are there any other must-see attractions?",
+        "timestamp": int(math.floor(time.time() * 1000)),
+    },
+    {
+        "direction": "received",
+        "avatar": "bot.png",
+        "content": "Absolutely! In addition to the Colosseum and Vatican City, you should definitely explore the Roman Forum, which was the heart of ancient Rome's political and social life. The Pantheon is another architectural marvel you shouldn't miss. And don't forget to toss a coin into the Trevi Fountain for good luck! Piazza Navona, the Spanish Steps, and the Borghese Gallery are also worth visiting.",
+        "timestamp": int(math.floor(time.time() * 1000)),
+    },
+]
+
+
+app.layout = html.Div(
+    [
+        dch.ChatSimple(
+            messages=messages,
+            id="chat-simple",
+            autofocus=True,
+            className="h-100"
+        ),
+    ],
+    style={"height": "calc(100vh - 40px)", "margin": "20px auto", "maxWidth": "900px"},
+)
+
+
+@app.callback(
+    Output("chat-simple", "messages"),
+    Input("chat-simple", "value_on_submit"),
+    State("chat-simple", "messages"),
+    prevent_initial_call=True,
+)
+def reply_message(value_on_submit, msg_list):
+    time.sleep(2)
+    msg_list.append(
+        {
+            "direction": "received",
+            "avatar": "bot.png",
+            "content": f"You just typed: {value_on_submit}",
+            "timestamp": int(math.floor(time.time() * 1000)),
+        }
+    )
+
+    return msg_list
+
+
+if __name__ == "__main__":
+    app.run_server(debug=True)


Test patch:
diff --git a/.github/workflows/pipy_test_release.yml b/.github/workflows/pipy_test_release.yml
new file mode 100644
index 0000000..8993f41
--- /dev/null
+++ b/.github/workflows/pipy_test_release.yml
@@ -0,0 +1,48 @@
+name: Publish Plotly Dash package 📦
+
+on:
+  push:
+    tags:
+     - '*'
+
+jobs:
+  build-n-publish:
+    name: Build and publish Plotly Dash package
+    runs-on: ubuntu-latest
+    steps:
+    - uses: actions/checkout@v3
+    - name: Setup NodeJS 18
+      uses: actions/setup-node@v3
+      with:
+        node-version: '18.x'
+        # registry-url: 'https://registry.npmjs.org'
+    - name: Set up Python 3.10
+      uses: actions/setup-python@v3
+      with:
+        python-version: "3.10"
+    - name: Install NodeJS dependencies
+      run: npm ci && npm run build
+    - name: Install pypa/setuptools
+      run: >-
+        python -m
+        pip install wheel
+    - name: Extract tag name
+      id: tag
+      run: echo ::set-output name=TAG_NAME::$(echo $GITHUB_REF | cut -d / -f 3)
+    - name: Update version in package.json
+      run: >-
+        sed -i "s/{{VERSION_PLACEHOLDER}}/${{ steps.tag.outputs.TAG_NAME }}/g" package.json
+    - name: Build a webpack bundle
+      run: npm run build
+    - name: Build a binary wheel
+      run: >-
+        python setup.py sdist bdist_wheel
+    #  - name: Publish package 📦 to NPM 
+    #     run: npm publish
+    #     env:
+    #       NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
+    - name: Publish package 📦 to PyPI
+      uses: pypa/gh-action-pypi-publish@master
+      with:
+        password: ${{ secrets.TEST_PYPI_API_TOKEN }}
+        repository-url: https://test.pypi.org/legacy/
\ No newline at end of file