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:
parent
85ec3060d9
commit
91a227913a
|
@ -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) {
|
return function (dispatch, getState) {
|
||||||
const reduxReplyToId = getState().getIn(['compose', 'in_reply_to'])
|
const reduxReplyToId = getState().getIn(['compose', 'in_reply_to'])
|
||||||
const existingText = getState().getIn(['compose', 'text']).trim()
|
const existingText = getState().getIn(['compose', 'text']).trim()
|
||||||
|
@ -105,6 +105,7 @@ export function changeCompose(text, markdown, replyId, isStandalone) {
|
||||||
type: COMPOSE_CHANGE,
|
type: COMPOSE_CHANGE,
|
||||||
text: text,
|
text: text,
|
||||||
markdown: markdown,
|
markdown: markdown,
|
||||||
|
caretPosition: caretPosition,
|
||||||
})
|
})
|
||||||
} else if (existingText.length > 0 && text.trim().length > 0) {
|
} else if (existingText.length > 0 && text.trim().length > 0) {
|
||||||
dispatch(openModal('CONFIRM', {
|
dispatch(openModal('CONFIRM', {
|
||||||
|
@ -119,6 +120,7 @@ export function changeCompose(text, markdown, replyId, isStandalone) {
|
||||||
type: COMPOSE_CHANGE,
|
type: COMPOSE_CHANGE,
|
||||||
text: text,
|
text: text,
|
||||||
markdown: markdown,
|
markdown: markdown,
|
||||||
|
caretPosition: caretPosition,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
@ -136,6 +138,7 @@ export function changeCompose(text, markdown, replyId, isStandalone) {
|
||||||
type: COMPOSE_CHANGE,
|
type: COMPOSE_CHANGE,
|
||||||
text: text,
|
text: text,
|
||||||
markdown: markdown,
|
markdown: markdown,
|
||||||
|
caretPosition: caretPosition,
|
||||||
})
|
})
|
||||||
} else if (existingText.length > 0 && text.trim().length > 0) {
|
} else if (existingText.length > 0 && text.trim().length > 0) {
|
||||||
dispatch(openModal('CONFIRM', {
|
dispatch(openModal('CONFIRM', {
|
||||||
|
@ -149,6 +152,7 @@ export function changeCompose(text, markdown, replyId, isStandalone) {
|
||||||
type: COMPOSE_CHANGE,
|
type: COMPOSE_CHANGE,
|
||||||
text: text,
|
text: text,
|
||||||
markdown: markdown,
|
markdown: markdown,
|
||||||
|
caretPosition: caretPosition,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
}))
|
}))
|
||||||
|
@ -160,6 +164,7 @@ export function changeCompose(text, markdown, replyId, isStandalone) {
|
||||||
type: COMPOSE_CHANGE,
|
type: COMPOSE_CHANGE,
|
||||||
text: text,
|
text: text,
|
||||||
markdown: markdown,
|
markdown: markdown,
|
||||||
|
caretPosition: caretPosition,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -642,10 +647,9 @@ export function changeComposeVisibility(value) {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export function insertEmojiCompose(position, emoji, needsSpace) {
|
export function insertEmojiCompose(emoji, needsSpace) {
|
||||||
return {
|
return {
|
||||||
type: COMPOSE_EMOJI_INSERT,
|
type: COMPOSE_EMOJI_INSERT,
|
||||||
position,
|
|
||||||
emoji,
|
emoji,
|
||||||
needsSpace,
|
needsSpace,
|
||||||
};
|
};
|
||||||
|
|
|
@ -255,61 +255,27 @@ export default class AutosuggestTextbox extends ImmutablePureComponent {
|
||||||
justifyContentCenter: small,
|
justifyContentCenter: small,
|
||||||
})
|
})
|
||||||
|
|
||||||
if (textarea) {
|
|
||||||
return (
|
|
||||||
<Fragment>
|
|
||||||
<div className={textareaContainerClasses}>
|
|
||||||
<Textarea
|
|
||||||
inputRef={this.setTextbox}
|
|
||||||
className={textareaClasses}
|
|
||||||
disabled={disabled}
|
|
||||||
placeholder={placeholder}
|
|
||||||
autoFocus={false}
|
|
||||||
value={value}
|
|
||||||
onChange={this.onChange}
|
|
||||||
onKeyDown={this.onKeyDown}
|
|
||||||
onKeyUp={onKeyUp}
|
|
||||||
onFocus={this.onFocus}
|
|
||||||
onBlur={this.onBlur}
|
|
||||||
onPaste={this.onPaste}
|
|
||||||
aria-autocomplete='list'
|
|
||||||
/>
|
|
||||||
|
|
||||||
{/*<Composer
|
|
||||||
inputRef={this.setTextbox}
|
|
||||||
disabled={disabled}
|
|
||||||
placeholder={placeholder}
|
|
||||||
autoFocus={autoFocus}
|
|
||||||
value={value}
|
|
||||||
onChange={this.onChange}
|
|
||||||
onKeyDown={this.onKeyDown}
|
|
||||||
onKeyUp={onKeyUp}
|
|
||||||
onFocus={this.onFocus}
|
|
||||||
onBlur={this.onBlur}
|
|
||||||
onPaste={this.onPaste}
|
|
||||||
small={small}
|
|
||||||
/>*/}
|
|
||||||
|
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
{ /* : todo : put in popover */ }
|
|
||||||
<div className='autosuggest-textarea__suggestions-wrapper'>
|
|
||||||
<div className={`autosuggest-textarea__suggestions ${suggestionsHidden || suggestions.isEmpty() ? '' : 'autosuggest-textarea__suggestions--visible'}`}>
|
|
||||||
{suggestions.map(this.renderSuggestion)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Fragment>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={[_s.default, _s.flexGrow1].join(' ')}>
|
<Fragment>
|
||||||
<label className={[_s.default].join(' ')}>
|
<div className={textareaContainerClasses}>
|
||||||
<span style={{ display: 'none' }}>{placeholder}</span>
|
<Textarea
|
||||||
|
inputRef={this.setTextbox}
|
||||||
|
className={textareaClasses}
|
||||||
|
disabled={disabled}
|
||||||
|
placeholder={placeholder}
|
||||||
|
autoFocus={false}
|
||||||
|
value={value}
|
||||||
|
onChange={this.onChange}
|
||||||
|
onKeyDown={this.onKeyDown}
|
||||||
|
onKeyUp={onKeyUp}
|
||||||
|
onFocus={this.onFocus}
|
||||||
|
onBlur={this.onBlur}
|
||||||
|
onPaste={this.onPaste}
|
||||||
|
aria-autocomplete='list'
|
||||||
|
/>
|
||||||
|
|
||||||
<Input
|
{/*<Composer
|
||||||
type='text'
|
inputRef={this.setTextbox}
|
||||||
ref={this.setTextbox}
|
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
autoFocus={autoFocus}
|
autoFocus={autoFocus}
|
||||||
|
@ -319,20 +285,21 @@ export default class AutosuggestTextbox extends ImmutablePureComponent {
|
||||||
onKeyUp={onKeyUp}
|
onKeyUp={onKeyUp}
|
||||||
onFocus={this.onFocus}
|
onFocus={this.onFocus}
|
||||||
onBlur={this.onBlur}
|
onBlur={this.onBlur}
|
||||||
style={style}
|
onPaste={this.onPaste}
|
||||||
aria-autocomplete='list'
|
small={small}
|
||||||
id={id}
|
/>*/}
|
||||||
className={className}
|
|
||||||
maxLength={maxLength}
|
|
||||||
prependIcon={prependIcon}
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<div className={`autosuggest-textarea__suggestions ${suggestionsHidden || suggestions.isEmpty() ? '' : 'autosuggest-textarea__suggestions--visible'}`}>
|
{children}
|
||||||
{suggestions.map(this.renderSuggestion)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
);
|
{ /* : todo : put in popover */ }
|
||||||
|
<div className='autosuggest-textarea__suggestions-wrapper'>
|
||||||
|
<div className={`autosuggest-textarea__suggestions ${suggestionsHidden || suggestions.isEmpty() ? '' : 'autosuggest-textarea__suggestions--visible'}`}>
|
||||||
|
{suggestions.map(this.renderSuggestion)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Fragment>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ const messages = defineMessages({
|
||||||
const assetHost = process.env.CDN_HOST || ''
|
const assetHost = process.env.CDN_HOST || ''
|
||||||
let EmojiPicker, Emoji // load asynchronously
|
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 listenerOptions = detectPassiveEvents.hasSupport ? { passive: true } : false
|
||||||
|
|
||||||
const perLine = 8
|
const perLine = 8
|
||||||
|
@ -223,7 +223,7 @@ const mapDispatchToProps = (dispatch) => ({
|
||||||
|
|
||||||
onPickEmoji: (emoji) => {
|
onPickEmoji: (emoji) => {
|
||||||
dispatch(useEmoji(emoji))
|
dispatch(useEmoji(emoji))
|
||||||
dispatch(insertEmojiCompose(0, emoji, false))
|
dispatch(insertEmojiCompose(emoji, false))
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -93,7 +93,13 @@ class ComposeForm extends ImmutablePureComponent {
|
||||||
};
|
};
|
||||||
|
|
||||||
handleChange = (e, markdown) => {
|
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 = () => {
|
handleComposeFocus = () => {
|
||||||
|
@ -131,11 +137,11 @@ class ComposeForm extends ImmutablePureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSubmit = () => {
|
handleSubmit = () => {
|
||||||
// if (this.props.text !== 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)
|
// Something changed the text inside the textarea (e.g. browser extensions like Grammarly)
|
||||||
// // Update the state to match the current text
|
// Update the state to match the current text
|
||||||
// this.props.onChange(this.autosuggestTextarea.textbox.value);
|
this.props.onChange(this.autosuggestTextarea.textbox.value);
|
||||||
// }
|
}
|
||||||
|
|
||||||
// Submit disabled:
|
// Submit disabled:
|
||||||
const { isSubmitting, isChangingUpload, isUploading, anyMedia } = this.props;
|
const { isSubmitting, isChangingUpload, isUploading, anyMedia } = this.props;
|
||||||
|
@ -198,8 +204,8 @@ class ComposeForm extends ImmutablePureComponent {
|
||||||
selectionStart = selectionEnd;
|
selectionStart = selectionEnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
// this.autosuggestTextarea.textbox.setSelectionRange(selectionStart, selectionEnd);
|
this.autosuggestTextarea.textbox.setSelectionRange(selectionStart, selectionEnd);
|
||||||
// this.autosuggestTextarea.textbox.focus();
|
this.autosuggestTextarea.textbox.focus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -318,7 +324,6 @@ class ComposeForm extends ImmutablePureComponent {
|
||||||
onPaste={onPaste}
|
onPaste={onPaste}
|
||||||
autoFocus={shouldAutoFocus}
|
autoFocus={shouldAutoFocus}
|
||||||
small={shouldCondense}
|
small={shouldCondense}
|
||||||
textarea
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className={actionsContainerClasses}>
|
<div className={actionsContainerClasses}>
|
||||||
|
@ -409,7 +414,6 @@ class ComposeForm extends ImmutablePureComponent {
|
||||||
onPaste={onPaste}
|
onPaste={onPaste}
|
||||||
autoFocus={shouldAutoFocus}
|
autoFocus={shouldAutoFocus}
|
||||||
small={shouldCondense}
|
small={shouldCondense}
|
||||||
textarea
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -456,7 +460,7 @@ class ComposeForm extends ImmutablePureComponent {
|
||||||
<div className={actionsContainerClasses}>
|
<div className={actionsContainerClasses}>
|
||||||
<div className={[_s.default, _s.flexRow, _s.mrAuto].join(' ')}>
|
<div className={[_s.default, _s.flexRow, _s.mrAuto].join(' ')}>
|
||||||
|
|
||||||
{ /* <EmojiPickerButton small={shouldCondense} isMatch={isMatch} /> */ }
|
<EmojiPickerButton small={shouldCondense} isMatch={isMatch} />
|
||||||
|
|
||||||
<UploadButton small={shouldCondense} />
|
<UploadButton small={shouldCondense} />
|
||||||
{ /* <GifSelectorButton small={shouldCondense} /> */}
|
{ /* <GifSelectorButton small={shouldCondense} /> */}
|
||||||
|
|
|
@ -86,8 +86,8 @@ const mapStateToProps = (state, { replyToId, isStandalone }) => {
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch, { reduxReplyToId, replyToId, isStandalone }) => ({
|
const mapDispatchToProps = (dispatch, { reduxReplyToId, replyToId, isStandalone }) => ({
|
||||||
|
|
||||||
onChange(text, markdown, newReplyToId) {
|
onChange(text, markdown, newReplyToId, position) {
|
||||||
dispatch(changeCompose(text, markdown, newReplyToId, isStandalone))
|
dispatch(changeCompose(text, markdown, newReplyToId, isStandalone, position))
|
||||||
},
|
},
|
||||||
|
|
||||||
onSubmit(group, replyToId, router) {
|
onSubmit(group, replyToId, router) {
|
||||||
|
|
|
@ -169,14 +169,13 @@ const updateSuggestionTags = (state, token) => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const insertEmoji = (state, position, emojiData, needsSpace) => {
|
const insertEmoji = (state, emojiData, needsSpace) => {
|
||||||
const oldText = state.get('text')
|
const position = state.get('caretPosition')
|
||||||
const emoji = needsSpace ? ' ' + emojiData.native : emojiData.native
|
const oldText = state.get('text');
|
||||||
const text = `${oldText.slice(0, position)}${emoji} ${oldText.slice(position)}`
|
const emoji = needsSpace ? ' ' + emojiData.native : emojiData.native;
|
||||||
// console.log("insertEmoji reducer:", emoji, position, emojiData, needsSpace, text)
|
|
||||||
|
|
||||||
return state.merge({
|
return state.merge({
|
||||||
text,
|
text: `${oldText.slice(0, position)}${emoji} ${oldText.slice(position)}`,
|
||||||
focusDate: new Date(),
|
focusDate: new Date(),
|
||||||
caretPosition: position + emoji.length + 1,
|
caretPosition: position + emoji.length + 1,
|
||||||
idempotencyKey: uuid(),
|
idempotencyKey: uuid(),
|
||||||
|
@ -254,6 +253,7 @@ export default function compose(state = initialState, action) {
|
||||||
map.set('text', action.text)
|
map.set('text', action.text)
|
||||||
map.set('markdown', action.markdown)
|
map.set('markdown', action.markdown)
|
||||||
map.set('idempotencyKey', uuid())
|
map.set('idempotencyKey', uuid())
|
||||||
|
map.set('caretPosition', action.caretPosition)
|
||||||
if (action.replyId) {
|
if (action.replyId) {
|
||||||
map.set('in_reply_to', action.replyId)
|
map.set('in_reply_to', action.replyId)
|
||||||
}
|
}
|
||||||
|
@ -345,7 +345,7 @@ export default function compose(state = initialState, action) {
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
case COMPOSE_EMOJI_INSERT:
|
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:
|
case COMPOSE_UPLOAD_CHANGE_SUCCESS:
|
||||||
return state
|
return state
|
||||||
.set('is_changing_upload', false)
|
.set('is_changing_upload', false)
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 2.4 MiB |
Binary file not shown.
After Width: | Height: | Size: 839 KiB |
Loading…
Reference in New Issue