add emoji selector

This commit is contained in:
Sharon Kennedy
2020-03-25 19:01:29 -04:00
parent f0b9578d66
commit b4e4356cb7
6 changed files with 233 additions and 49 deletions

View File

@@ -195,7 +195,7 @@
}
&:focus {
background: $theme-light-color;
background-color: $theme-light-color;
outline: none;
}
}
@@ -366,36 +366,6 @@
margin-bottom: 0;
}
input[placeholder] {
text-overflow: ellipsis;
overflow: hidden;
}
input[type="text"] {
font-size: 1rem;
padding: 0.5rem;
border: none;
display: flex;
flex: 1 1 auto;
border: 1px solid $dark-color;
background: $white;
color: $dark-color;
font-family: $theme-font;
margin-right: 0.2rem;
transition: all 0.2s ease-in-out;
border-radius: 10px;
&:hover {
box-shadow: inset 0px 0px 0px 1px $dark-color;
}
&:focus {
outline: none;
box-shadow: inset 0px 0px 0px 1px $dark-color;
background: $theme-light-color;
}
}
input[type="submit"] {
background-color: $theme-color;
height: 100%;
@@ -423,12 +393,122 @@
background-color: $theme-highlight-color;
}
}
.message-input-container {
display: flex;
flex: 1 1 auto;
position: relative;
input[type="text"] {
font-size: 1rem;
padding: 0.5rem;
padding-right: 32px;
border: none;
display: flex;
flex: 1 1 auto;
background: $white;
color: $dark-color;
font-family: $theme-font;
margin-right: 0.2rem;
transition: all 0.2s ease-in-out;
border-radius: 10px;
border: 1px solid $dark-color;
&:hover {
box-shadow: inset 0px 0px 0px 1px $dark-color;
}
&:focus {
outline: none;
box-shadow: inset 0px 0px 0px 1px $dark-color;
background: $theme-light-color;
}
}
.emoji-button-container {
position: absolute;
right: 6px;
top: 0;
bottom: 0;
height: 100%;
display: flex;
align-items: center;
justify-content: flex-start;
button {
transition: all 0.2s ease-in-out;
&:hover {
box-shadow: none;
}
&:focus {
outline: none;
}
&#emoji-button {
background: transparent;
border: none;
padding: 0;
margin-right: 3px;
transition: all 0.2s ease-in-out;
&:hover {
svg path#icon {
fill: $theme-color;
}
}
&:focus {
svg path#icon {
fill: $theme-highlight-color;
}
}
}
}
}
.emoji-picker {
animation-duration: 0.2s;
animation-fill-mode: forwards;
position: absolute;
bottom: 32px;
right: -4px;
&-entering {
animation-name: slideInUp;
opacity: 0.5;
}
&-entered {
display: inherit;
visibility: visible;
opacity: 1;
}
&-exiting {
animation-name: slideOutDown;
opacity: 0.5;
}
&-exited {
display: none;
visibility: hidden;
opacity: 0;
}
}
}
}
.highlight-text {
color: $theme-color;
}
.pos-relative {
position: relative;
}
}
.hidden {
display: none;
}
@media screen and (max-width: 420px){
@@ -448,6 +528,11 @@
}
}
.hidden {
display: none;
@media screen and (max-width: 360px){
#ocrcc-chatbox .input-window .message-input-container .emoji-picker {
position: fixed;
left: 5px;
right: 5px;
bottom: 42px;
}
}

View File

@@ -15,6 +15,7 @@ import {uuid} from "uuidv4"
import Message from "./message";
import Dock from "./dock";
import Header from "./header";
import EmojiSelector from './emoji-selector';
import './styles.scss';
@@ -54,6 +55,7 @@ class ChatBox extends React.Component {
roomId: null,
typingStatus: null,
awaitingAgreement: true,
emojiSelectorOpen: false,
}
this.state = this.initialState
this.chatboxInput = React.createRef();
@@ -74,6 +76,14 @@ class ChatBox extends React.Component {
});
}
toggleEmojiSelector = () => {
this.setState({ emojiSelectorOpen: !this.state.emojiSelectorOpen })
}
closeEmojiSelector = () => {
this.setState({ emojiSelectorOpen: false }, () => this.chatboxInput.current.focus())
}
handleWidgetExit = () => {
this.setState({
showDock: true,
@@ -357,9 +367,13 @@ class ChatBox extends React.Component {
}
handleEscape = (e) => {
if (e.keyCode === 27 && this.state.opened) {
this.handleToggleOpen()
handleKeyDown = (e) => {
if (e.keyCode === 27) {
if (this.state.emojiSelectorOpen) {
this.closeEmojiSelector()
} else if (this.state.opened) {
this.handleToggleOpen()
}
}
}
@@ -413,12 +427,12 @@ class ChatBox extends React.Component {
}
componentDidMount() {
document.addEventListener("keydown", this.handleEscape, false);
document.addEventListener("keydown", this.handleKeyDown, false);
window.addEventListener('beforeunload', this.exitChat)
}
componentWillUnmount() {
document.removeEventListener("keydown", this.handleEscape, false);
document.removeEventListener("keydown", this.handleKeyDown, false);
window.removeEventListener('beforeunload', this.exitChat)
this.exitChat();
}
@@ -449,8 +463,16 @@ class ChatBox extends React.Component {
}
}
onEmojiClick = (event, emojiObject) => {
const { emoji } = emojiObject;
this.setState({
inputValue: this.state.inputValue.concat(emoji),
emojiSelectorOpen: false,
}, () => this.chatboxInput.current.focus())
}
render() {
const { ready, messages, inputValue, userId, roomId, typingStatus, opened, showDock } = this.state;
const { ready, messages, inputValue, userId, roomId, typingStatus, opened, showDock, emojiSelectorOpen } = this.state;
const inputLabel = 'Send a message...'
return (
@@ -501,16 +523,25 @@ class ChatBox extends React.Component {
</div>
<div className="input-window">
<form onSubmit={this.handleSubmit}>
<input
id="message-input"
type="text"
onChange={this.handleInputChange}
value={inputValue}
aria-label={inputLabel}
placeholder={inputLabel}
autoFocus={true}
ref={this.chatboxInput}
/>
<div className="message-input-container">
<input
id="message-input"
type="text"
onChange={this.handleInputChange}
value={inputValue}
aria-label={inputLabel}
placeholder={inputLabel}
autoFocus={true}
onFocus={(e) => this.setState({ inputValue: this.state.inputValue })}
ref={this.chatboxInput}
/>
<EmojiSelector
onEmojiClick={this.onEmojiClick}
emojiSelectorOpen={emojiSelectorOpen}
toggleEmojiSelector={this.toggleEmojiSelector}
closeEmojiSelector={this.closeEmojiSelector}
/>
</div>
<input type="submit" value="Send" id="submit" />
</form>
</div>

View File

@@ -0,0 +1,47 @@
import React from "react"
import PropTypes from "prop-types"
import { Transition } from 'react-transition-group';
import EmojiPicker from 'emoji-picker-react';
import onClickOutside from "react-onclickoutside";
const SVG = () => <svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path id="icon" fill="#828282" d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zm3.5-9c.83 0 1.5-.67 1.5-1.5S16.33 8 15.5 8 14 8.67 14 9.5s.67 1.5 1.5 1.5zm-7 0c.83 0 1.5-.67 1.5-1.5S9.33 8 8.5 8 7 8.67 7 9.5 7.67 11 8.5 11zm3.5 6.5c2.33 0 4.31-1.46 5.11-3.5H6.89c.8 2.04 2.78 3.5 5.11 3.5z"/></svg>
class EmojiSelector extends React.Component {
constructor(props){
super(props)
}
handleClickOutside = e => {
this.props.closeEmojiSelector()
};
render() {
const { onEmojiClick, emojiSelectorOpen, toggleEmojiSelector } = this.props;
return(
<div className="emoji-button-container">
<div className="pos-relative">
<Transition in={emojiSelectorOpen} timeout={250}>
{
status => {
return(
<div className={`emoji-picker emoji-picker-${status}`} aria-hidden={!emojiSelectorOpen}>
<EmojiPicker onEmojiClick={onEmojiClick}/>
</div>
)
}
}
</Transition>
<button id="emoji-button" onClick={toggleEmojiSelector} aria-label="Emoji picker">
<SVG />
</button>
</div>
</div>
)
}
}
export default onClickOutside(EmojiSelector)

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.4, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
<path style="fill:none;" d="M0,0h24v24H0V0z"/>
<path style="fill:#828282;" d="M12,2C6.5,2,2,6.5,2,12s4.5,10,10,10c5.5,0,10-4.5,10-10S17.5,2,12,2z M12,20c-4.4,0-8-3.6-8-8
s3.6-8,8-8s8,3.6,8,8S16.4,20,12,20z M15.5,11c0.8,0,1.5-0.7,1.5-1.5S16.3,8,15.5,8S14,8.7,14,9.5S14.7,11,15.5,11z M8.5,11
c0.8,0,1.5-0.7,1.5-1.5S9.3,8,8.5,8S7,8.7,7,9.5S7.7,11,8.5,11z M12,17.5c2.3,0,4.3-1.5,5.1-3.5H6.9C7.7,16,9.7,17.5,12,17.5z"/>
</svg>

After

Width:  |  Height:  |  Size: 769 B