Added emoji support for composer

• Added:
- emoji support for composer
- new emoji sheet

• Updated:
- Textarea to accomodate
- Reducers and actions to retrieve caretPosition on text change when typing

• Removed:
- Unused input type on AutosuggestTextbox
- Old emoji sheet.png
This commit is contained in:
mgabdev 2020-06-05 21:43:08 -04:00
parent 85ec3060d9
commit 91a227913a
8 changed files with 65 additions and 90 deletions

View File

@ -81,7 +81,7 @@ export const ensureComposeIsVisible = (getState, routerHistory) => {
}
};
export function changeCompose(text, markdown, replyId, isStandalone) {
export function changeCompose(text, markdown, replyId, isStandalone, caretPosition) {
return function (dispatch, getState) {
const reduxReplyToId = getState().getIn(['compose', 'in_reply_to'])
const existingText = getState().getIn(['compose', 'text']).trim()
@ -105,6 +105,7 @@ export function changeCompose(text, markdown, replyId, isStandalone) {
type: COMPOSE_CHANGE,
text: text,
markdown: markdown,
caretPosition: caretPosition,
})
} else if (existingText.length > 0 && text.trim().length > 0) {
dispatch(openModal('CONFIRM', {
@ -119,6 +120,7 @@ export function changeCompose(text, markdown, replyId, isStandalone) {
type: COMPOSE_CHANGE,
text: text,
markdown: markdown,
caretPosition: caretPosition,
})
}
}))
@ -136,6 +138,7 @@ export function changeCompose(text, markdown, replyId, isStandalone) {
type: COMPOSE_CHANGE,
text: text,
markdown: markdown,
caretPosition: caretPosition,
})
} else if (existingText.length > 0 && text.trim().length > 0) {
dispatch(openModal('CONFIRM', {
@ -149,6 +152,7 @@ export function changeCompose(text, markdown, replyId, isStandalone) {
type: COMPOSE_CHANGE,
text: text,
markdown: markdown,
caretPosition: caretPosition,
})
},
}))
@ -160,6 +164,7 @@ export function changeCompose(text, markdown, replyId, isStandalone) {
type: COMPOSE_CHANGE,
text: text,
markdown: markdown,
caretPosition: caretPosition,
})
}
}
@ -642,10 +647,9 @@ export function changeComposeVisibility(value) {
};
};
export function insertEmojiCompose(position, emoji, needsSpace) {
export function insertEmojiCompose(emoji, needsSpace) {
return {
type: COMPOSE_EMOJI_INSERT,
position,
emoji,
needsSpace,
};

View File

@ -255,7 +255,6 @@ export default class AutosuggestTextbox extends ImmutablePureComponent {
justifyContentCenter: small,
})
if (textarea) {
return (
<Fragment>
<div className={textareaContainerClasses}>
@ -292,6 +291,7 @@ export default class AutosuggestTextbox extends ImmutablePureComponent {
{children}
</div>
{ /* : todo : put in popover */ }
<div className='autosuggest-textarea__suggestions-wrapper'>
<div className={`autosuggest-textarea__suggestions ${suggestionsHidden || suggestions.isEmpty() ? '' : 'autosuggest-textarea__suggestions--visible'}`}>
@ -302,37 +302,4 @@ export default class AutosuggestTextbox extends ImmutablePureComponent {
)
}
return (
<div className={[_s.default, _s.flexGrow1].join(' ')}>
<label className={[_s.default].join(' ')}>
<span style={{ display: 'none' }}>{placeholder}</span>
<Input
type='text'
ref={this.setTextbox}
disabled={disabled}
placeholder={placeholder}
autoFocus={autoFocus}
value={value}
onChange={this.onChange}
onKeyDown={this.onKeyDown}
onKeyUp={onKeyUp}
onFocus={this.onFocus}
onBlur={this.onBlur}
style={style}
aria-autocomplete='list'
id={id}
className={className}
maxLength={maxLength}
prependIcon={prependIcon}
/>
</label>
<div className={`autosuggest-textarea__suggestions ${suggestionsHidden || suggestions.isEmpty() ? '' : 'autosuggest-textarea__suggestions--visible'}`}>
{suggestions.map(this.renderSuggestion)}
</div>
</div>
);
}
}

View File

@ -35,7 +35,7 @@ const messages = defineMessages({
const assetHost = process.env.CDN_HOST || ''
let EmojiPicker, Emoji // load asynchronously
const backgroundImageFn = () => `${assetHost}/emoji/sheet.png`
const backgroundImageFn = () => `${assetHost}/emoji/sheet_1.png`
const listenerOptions = detectPassiveEvents.hasSupport ? { passive: true } : false
const perLine = 8
@ -223,7 +223,7 @@ const mapDispatchToProps = (dispatch) => ({
onPickEmoji: (emoji) => {
dispatch(useEmoji(emoji))
dispatch(insertEmojiCompose(0, emoji, false))
dispatch(insertEmojiCompose(emoji, false))
},
})

View File

@ -93,7 +93,13 @@ class ComposeForm extends ImmutablePureComponent {
};
handleChange = (e, markdown) => {
this.props.onChange(e.target.value, markdown, this.props.replyToId)
let position = null
try {
position = this.autosuggestTextarea.textbox.selectionStart
} catch (error) {
//
}
this.props.onChange(e.target.value, markdown, this.props.replyToId, position)
}
handleComposeFocus = () => {
@ -131,11 +137,11 @@ class ComposeForm extends ImmutablePureComponent {
}
handleSubmit = () => {
// if (this.props.text !== this.autosuggestTextarea.textbox.value) {
// // Something changed the text inside the textarea (e.g. browser extensions like Grammarly)
// // Update the state to match the current text
// this.props.onChange(this.autosuggestTextarea.textbox.value);
// }
if (this.props.text !== this.autosuggestTextarea.textbox.value) {
// Something changed the text inside the textarea (e.g. browser extensions like Grammarly)
// Update the state to match the current text
this.props.onChange(this.autosuggestTextarea.textbox.value);
}
// Submit disabled:
const { isSubmitting, isChangingUpload, isUploading, anyMedia } = this.props;
@ -198,8 +204,8 @@ class ComposeForm extends ImmutablePureComponent {
selectionStart = selectionEnd;
}
// this.autosuggestTextarea.textbox.setSelectionRange(selectionStart, selectionEnd);
// this.autosuggestTextarea.textbox.focus();
this.autosuggestTextarea.textbox.setSelectionRange(selectionStart, selectionEnd);
this.autosuggestTextarea.textbox.focus();
}
}
@ -318,7 +324,6 @@ class ComposeForm extends ImmutablePureComponent {
onPaste={onPaste}
autoFocus={shouldAutoFocus}
small={shouldCondense}
textarea
/>
<div className={actionsContainerClasses}>
@ -409,7 +414,6 @@ class ComposeForm extends ImmutablePureComponent {
onPaste={onPaste}
autoFocus={shouldAutoFocus}
small={shouldCondense}
textarea
/>
{
@ -456,7 +460,7 @@ class ComposeForm extends ImmutablePureComponent {
<div className={actionsContainerClasses}>
<div className={[_s.default, _s.flexRow, _s.mrAuto].join(' ')}>
{ /* <EmojiPickerButton small={shouldCondense} isMatch={isMatch} /> */ }
<EmojiPickerButton small={shouldCondense} isMatch={isMatch} />
<UploadButton small={shouldCondense} />
{ /* <GifSelectorButton small={shouldCondense} /> */}

View File

@ -86,8 +86,8 @@ const mapStateToProps = (state, { replyToId, isStandalone }) => {
const mapDispatchToProps = (dispatch, { reduxReplyToId, replyToId, isStandalone }) => ({
onChange(text, markdown, newReplyToId) {
dispatch(changeCompose(text, markdown, newReplyToId, isStandalone))
onChange(text, markdown, newReplyToId, position) {
dispatch(changeCompose(text, markdown, newReplyToId, isStandalone, position))
},
onSubmit(group, replyToId, router) {

View File

@ -169,14 +169,13 @@ const updateSuggestionTags = (state, token) => {
});
};
const insertEmoji = (state, position, emojiData, needsSpace) => {
const oldText = state.get('text')
const emoji = needsSpace ? ' ' + emojiData.native : emojiData.native
const text = `${oldText.slice(0, position)}${emoji} ${oldText.slice(position)}`
// console.log("insertEmoji reducer:", emoji, position, emojiData, needsSpace, text)
const insertEmoji = (state, emojiData, needsSpace) => {
const position = state.get('caretPosition')
const oldText = state.get('text');
const emoji = needsSpace ? ' ' + emojiData.native : emojiData.native;
return state.merge({
text,
text: `${oldText.slice(0, position)}${emoji} ${oldText.slice(position)}`,
focusDate: new Date(),
caretPosition: position + emoji.length + 1,
idempotencyKey: uuid(),
@ -254,6 +253,7 @@ export default function compose(state = initialState, action) {
map.set('text', action.text)
map.set('markdown', action.markdown)
map.set('idempotencyKey', uuid())
map.set('caretPosition', action.caretPosition)
if (action.replyId) {
map.set('in_reply_to', action.replyId)
}
@ -345,7 +345,7 @@ export default function compose(state = initialState, action) {
return state;
}
case COMPOSE_EMOJI_INSERT:
return insertEmoji(state, action.position, action.emoji, action.needsSpace);
return insertEmoji(state, action.emoji, action.needsSpace);
case COMPOSE_UPLOAD_CHANGE_SUCCESS:
return state
.set('is_changing_upload', false)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 MiB

BIN
public/emoji/sheet_32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 839 KiB