2020-10-03 01:29:27 +08:00
|
|
|
import React, { PureComponent } from 'react';
|
|
|
|
import { defineMessages, injectIntl } from 'react-intl';
|
|
|
|
import PropTypes from 'prop-types';
|
2023-04-28 05:31:11 +08:00
|
|
|
import { isMobile } from '/imports/utils/deviceInfo';
|
2020-10-03 01:29:27 +08:00
|
|
|
import logger from '/imports/startup/client/logger';
|
2023-04-28 05:31:11 +08:00
|
|
|
import ClickOutside from '/imports/ui/components/click-outside/component';
|
2021-10-27 03:50:59 +08:00
|
|
|
import Styled from './styles';
|
2020-10-03 01:29:27 +08:00
|
|
|
|
2023-04-28 05:31:11 +08:00
|
|
|
const EMOJI_BUTTON = Meteor.settings.public.app.enableEmojiButton;
|
|
|
|
|
2020-10-03 01:29:27 +08:00
|
|
|
const propTypes = {
|
|
|
|
placeholder: PropTypes.string,
|
|
|
|
send: PropTypes.func.isRequired,
|
2023-04-28 05:31:11 +08:00
|
|
|
emojiPickerDown: PropTypes.bool,
|
2020-10-03 01:29:27 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
const defaultProps = {
|
|
|
|
placeholder: '',
|
|
|
|
send: () => logger.warn({ logCode: 'text_input_send_function' }, `Missing`),
|
2023-04-28 05:31:11 +08:00
|
|
|
emojiPickerDown: false,
|
|
|
|
enableEmoji: true,
|
2020-10-03 01:29:27 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
const messages = defineMessages({
|
|
|
|
sendLabel: {
|
|
|
|
id: 'app.textInput.sendLabel',
|
|
|
|
description: 'Text input send button label',
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
class TextInput extends PureComponent {
|
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
|
|
|
|
2023-04-28 05:31:11 +08:00
|
|
|
this.state = {
|
|
|
|
message: '',
|
|
|
|
showEmojiPicker: false
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
hasClickOutsideActions() {
|
|
|
|
return this.emojiEnabled();
|
2020-10-03 01:29:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
handleOnChange(e) {
|
|
|
|
const message = e.target.value;
|
|
|
|
this.setState({ message });
|
|
|
|
}
|
|
|
|
|
2023-04-28 05:31:11 +08:00
|
|
|
handleOnClick() {
|
|
|
|
const { send } = this.props;
|
|
|
|
const { message } = this.state;
|
|
|
|
|
|
|
|
send(message);
|
|
|
|
this.setState({
|
|
|
|
message: '',
|
|
|
|
showEmojiPicker: false,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2021-05-05 14:51:43 +08:00
|
|
|
handleOnKeyDown(e) {
|
|
|
|
if (e.keyCode === 13 && e.shiftKey === false) {
|
|
|
|
e.preventDefault();
|
|
|
|
this.handleOnClick();
|
2023-04-28 05:31:11 +08:00
|
|
|
} else if (e.keyCode === 27) { //Escape key
|
|
|
|
const { showEmojiPicker } = this.state;
|
|
|
|
|
|
|
|
//if the emoji picker is opened, close it
|
|
|
|
if (showEmojiPicker) {
|
|
|
|
this.setState({ showEmojiPicker: false });
|
|
|
|
}
|
2021-05-05 14:51:43 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-28 05:31:11 +08:00
|
|
|
handleEmojiButtonClick() {
|
|
|
|
const { showEmojiPicker } = this.state;
|
|
|
|
|
|
|
|
if (this.textarea) this.textarea.focus();
|
|
|
|
this.setState({ showEmojiPicker: !showEmojiPicker });
|
|
|
|
}
|
|
|
|
|
|
|
|
handleEmojiSelect(emojiObject) {
|
2020-10-03 01:29:27 +08:00
|
|
|
const { message } = this.state;
|
2023-04-28 05:31:11 +08:00
|
|
|
if (this.textarea) this.textarea.focus();
|
|
|
|
this.setState({ message: message + emojiObject.native });
|
|
|
|
}
|
2020-10-03 01:29:27 +08:00
|
|
|
|
2023-04-28 05:31:11 +08:00
|
|
|
handleClickOutside() {
|
|
|
|
if (this.emojiEnabled()) {
|
|
|
|
const { showEmojiPicker } = this.state;
|
|
|
|
if (showEmojiPicker) {
|
|
|
|
this.setState({ showEmojiPicker: false });
|
|
|
|
}
|
|
|
|
}
|
2020-10-03 01:29:27 +08:00
|
|
|
}
|
|
|
|
|
2023-04-28 05:31:11 +08:00
|
|
|
emojiEnabled() {
|
|
|
|
if (isMobile) return false;
|
|
|
|
|
|
|
|
const { enableEmoji } = this.props;
|
|
|
|
return enableEmoji && EMOJI_BUTTON;
|
|
|
|
}
|
|
|
|
|
|
|
|
renderEmojiPicker() {
|
|
|
|
const { showEmojiPicker } = this.state;
|
|
|
|
|
|
|
|
if (this.emojiEnabled() && showEmojiPicker) {
|
|
|
|
return (
|
|
|
|
<EmojiPicker
|
|
|
|
onEmojiSelect={emojiObject => this.handleEmojiSelect(emojiObject)}
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
renderEmojiButton = () => {
|
|
|
|
if (!this.emojiEnabled()) return null;
|
|
|
|
|
|
|
|
return (
|
|
|
|
<Styled.EmojiButtonWrapper
|
|
|
|
onClick={() => this.handleEmojiButtonClick()}
|
|
|
|
>
|
|
|
|
<Icon
|
|
|
|
iconName="happy"
|
|
|
|
/>
|
|
|
|
</Styled.EmojiButtonWrapper>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
renderInput() {
|
2020-10-03 01:29:27 +08:00
|
|
|
const {
|
|
|
|
intl,
|
|
|
|
maxLength,
|
|
|
|
placeholder,
|
2023-04-28 05:31:11 +08:00
|
|
|
emojiPickerDown,
|
2020-10-03 01:29:27 +08:00
|
|
|
} = this.props;
|
|
|
|
|
|
|
|
const { message } = this.state;
|
|
|
|
|
|
|
|
return (
|
2021-10-27 03:50:59 +08:00
|
|
|
<Styled.Wrapper>
|
|
|
|
<Styled.TextArea
|
2023-04-28 05:31:11 +08:00
|
|
|
emojiEnabled={this.emojiEnabled()}
|
2020-10-03 01:29:27 +08:00
|
|
|
maxLength={maxLength}
|
|
|
|
onChange={(e) => this.handleOnChange(e)}
|
2021-05-05 14:51:43 +08:00
|
|
|
onKeyDown={(e) => this.handleOnKeyDown(e)}
|
2023-03-10 01:46:45 +08:00
|
|
|
onPaste={(e) => { e.stopPropagation(); }}
|
|
|
|
onCut={(e) => { e.stopPropagation(); }}
|
|
|
|
onCopy={(e) => { e.stopPropagation(); }}
|
2020-10-03 01:29:27 +08:00
|
|
|
placeholder={placeholder}
|
|
|
|
value={message}
|
|
|
|
/>
|
2021-10-27 03:50:59 +08:00
|
|
|
<Styled.TextInputButton
|
2020-10-03 01:29:27 +08:00
|
|
|
circle
|
|
|
|
color="primary"
|
|
|
|
hideLabel
|
|
|
|
icon="send"
|
|
|
|
label={intl.formatMessage(messages.sendLabel)}
|
|
|
|
onClick={() => this.handleOnClick()}
|
|
|
|
/>
|
2021-10-27 03:50:59 +08:00
|
|
|
</Styled.Wrapper>
|
2020-10-03 01:29:27 +08:00
|
|
|
);
|
|
|
|
}
|
2023-04-28 05:31:11 +08:00
|
|
|
|
|
|
|
render() {
|
|
|
|
return this.hasClickOutsideActions() ? (
|
|
|
|
<ClickOutside
|
|
|
|
onClick={() => this.handleClickOutside()}
|
|
|
|
>
|
|
|
|
{this.renderInput()}
|
|
|
|
</ClickOutside>
|
|
|
|
) : this.renderInput();
|
|
|
|
}
|
2020-10-03 01:29:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
TextInput.propTypes = propTypes;
|
|
|
|
TextInput.defaultProps = defaultProps;
|
|
|
|
|
|
|
|
export default injectIntl(TextInput);
|