diff --git a/package.json b/package.json
index 2e5fce6..a7c1e9f 100644
--- a/package.json
+++ b/package.json
@@ -4,6 +4,8 @@
"homepage": "https://pusher.github.io/react-slack-clone",
"dependencies": {
"@pusher/chatkit": "^0.7.9",
+ "emoji-js": "^3.4.0",
+ "emoji-picker-react": "^2.0.4",
"object-path-immutable": "^1.0.1",
"react": "^16.2.0",
"react-dom": "^16.2.0",
diff --git a/src/components/CreateMessageForm/index.js b/src/components/CreateMessageForm/index.js
index 0f1685c..e7d90ed 100644
--- a/src/components/CreateMessageForm/index.js
+++ b/src/components/CreateMessageForm/index.js
@@ -1,36 +1,109 @@
-import React from 'react'
+import React, { Component } from 'react'
import style from './index.module.css'
import { FileInput } from '../FileInput'
+import EmojiPicker from '../EmojiPicker'
-export const CreateMessageForm = ({
- state: { user = {}, room = {}, message = '' },
- actions: { runCommand },
-}) =>
- room.id ? (
-
- ) : null
+export class CreateMessageForm extends Component {
+ constructor(props) {
+ super(props)
+
+ this.state = {
+ message: '',
+ cursorPostion: 0
+ }
+ }
+
+ render() {
+ const { runCommand, toggleEmojiPicker } = this.props.actions
+ const { user, room, message, isPickerShowing } = this.props.state
+
+ return room.id ? (
+
+ ) : null
+ }
+
+ handleInput(e) {
+ const { user, room } = this.props.state
+ user.isTypingIn({ roomId: room.id })
+
+ this.setState({
+ message: e.target.value,
+ cursorPostion: e.target.selectionStart
+ })
+ }
+
+ updateCursorPostion(e) {
+ this.setState({
+ cursorPostion: e.target.selectionStart
+ })
+ }
+
+ addEmojiToMessage(emoji) {
+ let message = this.state.message
+ let newMessage = ''
+ let cursor = this.state.cursorPostion
+ let beforeCursorStr = ''
+ let afterCursorStr = ''
+
+ beforeCursorStr = message.substring(0, cursor)
+ afterCursorStr = message.substr(cursor)
+ newMessage = `${beforeCursorStr}${emoji}${afterCursorStr}`
+
+ // reset the cursor to be after the emoji
+ this.messageInput.setSelectionRange(
+ this.state.cursorPostion + 2,
+ this.state.cursorPostion + 2,
+ 0
+ )
+
+ this.setState({
+ cursorPostion: this.state.cursorPostion + 2,
+ message: newMessage
+ })
+ }
+}
diff --git a/src/components/EmojiPicker/index.js b/src/components/EmojiPicker/index.js
new file mode 100644
index 0000000..cdac12a
--- /dev/null
+++ b/src/components/EmojiPicker/index.js
@@ -0,0 +1,42 @@
+import EmojiPicker from 'emoji-picker-react'
+import style from './index.module.css'
+
+import React from 'react'
+import JSEMOJI from 'emoji-js'
+
+let jsemoji = new JSEMOJI()
+
+const Picker = ({
+ state: { isPickerShowing },
+ actions: { toggleEmojiPicker, handleEmojiSelection },
+}) => (
+ {
+ e.nativeEvent.stopImmediatePropagation()
+ }}
+ className={style.component}
+ >
+
+ {
+ e.nativeEvent.stopImmediatePropagation()
+ const emoji = jsemoji.replace_colons(`:${emojiObj.name}:`)
+ handleEmojiSelection(emoji)
+ toggleEmojiPicker(!isPickerShowing)
+ }}
+ />
+
+
{
+ e.preventDefault()
+ toggleEmojiPicker(!isPickerShowing)
+ }}
+ />
+
+)
+
+export default Picker
diff --git a/src/components/EmojiPicker/index.module.css b/src/components/EmojiPicker/index.module.css
new file mode 100644
index 0000000..8f3c5f9
--- /dev/null
+++ b/src/components/EmojiPicker/index.module.css
@@ -0,0 +1,34 @@
+.component {
+ width: 2rem;
+ height: 2rem;
+ position: relative;
+}
+
+.overlayWrapper {
+ height: 0;
+ overflow: hidden;
+ position: absolute;
+ bottom: 32px;
+ right: 0;
+ -webkit-transition: height .25s ease-in-out; /* Safari */
+ transition: height .25s ease-in-out;
+}
+
+.button {
+ width: 32px;
+ height: 32px;
+ position: absolute;
+ bottom: 0;
+ right: 0;
+ background-image: url("https://cdn.jsdelivr.net/emojione/assets/3.0/png/32/1f600.png");
+ background-position: center center;
+ background-repeat: no-repeat;
+ background-size: contain;
+ border: none;
+ cursor: pointer;
+}
+
+.show {
+ /* find a better way to set this height */
+ height: 333px;
+}
diff --git a/src/index.js b/src/index.js
index 4688580..0953144 100644
--- a/src/index.js
+++ b/src/index.js
@@ -28,6 +28,7 @@ class View extends React.Component {
messages: {},
typing: {},
sidebarOpen: false,
+ isPickerShowing: false,
userListOpen: window.innerWidth > 1000,
}
@@ -38,6 +39,7 @@ class View extends React.Component {
setSidebar: sidebarOpen => this.setState({ sidebarOpen }),
setUserList: userListOpen => this.setState({ userListOpen }),
+ toggleEmojiPicker: isPickerShowing => this.setState({ isPickerShowing }),
// --------------------------------------
// User
@@ -66,12 +68,13 @@ class View extends React.Component {
)
},
- subscribeToRoom: room =>
+ subscribeToRoom: room => {
!this.state.user.roomSubscriptions[room.id] &&
- this.state.user.subscribeToRoom({
- roomId: room.id,
- hooks: { onNewMessage: this.actions.addMessage },
- }),
+ this.state.user.subscribeToRoom({
+ roomId: room.id,
+ hooks: { onNewMessage: this.actions.addMessage },
+ })
+ },
createRoom: options =>
this.state.user.createRoom(options).then(this.actions.joinRoom),
@@ -172,7 +175,6 @@ class View extends React.Component {
// --------------------------------------
// Notifications
// --------------------------------------
-
showNotification: message => {
if (
'Notification' in window &&
@@ -210,6 +212,14 @@ class View extends React.Component {
window.history.replaceState(null, null, window.location.pathname)
ChatManager(this, user)
})
+
+ document.addEventListener(
+ 'click',
+ e => {
+ this.actions.toggleEmojiPicker(false)
+ },
+ false
+ )
}
render() {
diff --git a/yarn.lock b/yarn.lock
index c24f55b..4dc0526 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1063,7 +1063,7 @@
lodash "^4.2.0"
to-fast-properties "^2.0.0"
-"@pusher/chatkit@^0.7.3":
+"@pusher/chatkit@^0.7.9":
version "0.7.9"
resolved "https://registry.yarnpkg.com/@pusher/chatkit/-/chatkit-0.7.9.tgz#34587299107baf55b36b3fe1c9870ea99e90a62a"
dependencies:
@@ -1611,7 +1611,7 @@ babel-register@^6.26.0:
mkdirp "^0.5.1"
source-map-support "^0.4.15"
-babel-runtime@^6.22.0, babel-runtime@^6.26.0:
+babel-runtime@^6.22.0, babel-runtime@^6.25.0, babel-runtime@^6.26.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
dependencies:
@@ -2964,6 +2964,23 @@ elliptic@^6.0.0:
minimalistic-assert "^1.0.0"
minimalistic-crypto-utils "^1.0.0"
+emoji-datasource@4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/emoji-datasource/-/emoji-datasource-4.0.0.tgz#3fc9c0c2f4fb321d9291138819f6d100603d3e2f"
+
+emoji-js@^3.4.0:
+ version "3.4.0"
+ resolved "https://registry.yarnpkg.com/emoji-js/-/emoji-js-3.4.0.tgz#dabdeda60c92d1948a5177e51ba9421d2029b052"
+ dependencies:
+ emoji-datasource "4.0.0"
+
+emoji-picker-react@^2.0.4:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/emoji-picker-react/-/emoji-picker-react-2.0.4.tgz#a58edc3412d39726dbcd64a7811806ccc90d9b46"
+ dependencies:
+ babel-runtime "^6.25.0"
+ throttle-debounce "^1.0.1"
+
emoji-regex@^6.1.0:
version "6.5.1"
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-6.5.1.tgz#9baea929b155565c11ea41c6626eaa65cef992c2"
@@ -7955,6 +7972,10 @@ throat@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/throat/-/throat-4.1.0.tgz#89037cbc92c56ab18926e6ba4cbb200e15672a6a"
+throttle-debounce@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/throttle-debounce/-/throttle-debounce-1.0.1.tgz#dad0fe130f9daf3719fdea33dc36a8e6ba7f30b5"
+
through2@^2.0.0:
version "2.0.3"
resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be"