diff --git a/.eslintrc.js b/.eslintrc.js index ba4c9c40b5..ae13b0711c 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -165,7 +165,7 @@ module.exports = defineConfig({ // }, // ], 'jsx-a11y/no-noninteractive-tabindex': 'off', - 'jsx-a11y/no-onchange': 'warn', + 'jsx-a11y/no-onchange': 'off', // recommended is full 'error' 'jsx-a11y/no-static-element-interactions': [ 'warn', diff --git a/app/javascript/flavours/glitch/actions/compose.js b/app/javascript/flavours/glitch/actions/compose.js index 07f60b9270..06f0d79874 100644 --- a/app/javascript/flavours/glitch/actions/compose.js +++ b/app/javascript/flavours/glitch/actions/compose.js @@ -21,7 +21,6 @@ let fetchComposeSuggestionsAccountsController; let fetchComposeSuggestionsTagsController; export const COMPOSE_CHANGE = 'COMPOSE_CHANGE'; -export const COMPOSE_CYCLE_ELEFRIEND = 'COMPOSE_CYCLE_ELEFRIEND'; export const COMPOSE_SUBMIT_REQUEST = 'COMPOSE_SUBMIT_REQUEST'; export const COMPOSE_SUBMIT_SUCCESS = 'COMPOSE_SUBMIT_SUCCESS'; export const COMPOSE_SUBMIT_FAIL = 'COMPOSE_SUBMIT_FAIL'; @@ -59,7 +58,7 @@ export const COMPOSE_SENSITIVITY_CHANGE = 'COMPOSE_SENSITIVITY_CHANGE'; export const COMPOSE_SPOILERNESS_CHANGE = 'COMPOSE_SPOILERNESS_CHANGE'; export const COMPOSE_SPOILER_TEXT_CHANGE = 'COMPOSE_SPOILER_TEXT_CHANGE'; export const COMPOSE_VISIBILITY_CHANGE = 'COMPOSE_VISIBILITY_CHANGE'; -export const COMPOSE_LISTABILITY_CHANGE = 'COMPOSE_LISTABILITY_CHANGE'; +export const COMPOSE_COMPOSING_CHANGE = 'COMPOSE_COMPOSING_CHANGE'; export const COMPOSE_CONTENT_TYPE_CHANGE = 'COMPOSE_CONTENT_TYPE_CHANGE'; export const COMPOSE_LANGUAGE_CHANGE = 'COMPOSE_LANGUAGE_CHANGE'; @@ -117,12 +116,6 @@ export function changeCompose(text) { }; } -export function cycleElefriendCompose() { - return { - type: COMPOSE_CYCLE_ELEFRIEND, - }; -} - export function replyCompose(status, routerHistory) { return (dispatch, getState) => { const prependCWRe = getState().getIn(['local_settings', 'prepend_cw_re']); @@ -148,13 +141,13 @@ export function resetCompose() { }; } -export const focusCompose = (routerHistory, defaultText) => dispatch => { +export const focusCompose = (routerHistory, defaultText) => (dispatch, getState) => { dispatch({ type: COMPOSE_FOCUS, defaultText, }); - ensureComposeIsVisible(routerHistory); + ensureComposeIsVisible(getState, routerHistory); }; export function mentionCompose(account, routerHistory) { @@ -179,7 +172,7 @@ export function directCompose(account, routerHistory) { }; } -export function submitCompose(routerHistory) { +export function submitCompose(routerHistory, overridePrivacy = null) { return function (dispatch, getState) { let status = getState().getIn(['compose', 'text'], ''); const media = getState().getIn(['compose', 'media_attachments']); @@ -228,7 +221,7 @@ export function submitCompose(routerHistory) { media_attributes, sensitive: getState().getIn(['compose', 'sensitive']) || (spoilerText.length > 0 && media.size !== 0), spoiler_text: spoilerText, - visibility: getState().getIn(['compose', 'privacy']), + visibility: overridePrivacy || getState().getIn(['compose', 'privacy']), poll: getState().getIn(['compose', 'poll'], null), language: getState().getIn(['compose', 'language']), }, @@ -246,11 +239,6 @@ export function submitCompose(routerHistory) { dispatch(insertIntoTagHistory(response.data.tags, status)); dispatch(submitComposeSuccess({ ...response.data })); - // If the response has no data then we can't do anything else. - if (!response.data) { - return; - } - // To make the app more responsive, immediately push the status // into the columns const insertIfOnline = timelineId => { @@ -660,15 +648,19 @@ export const readyComposeSuggestionsTags = (token, tags) => ({ export function selectComposeSuggestion(position, token, suggestion, path) { return (dispatch, getState) => { - let completion; + let completion, startPosition; + if (suggestion.type === 'emoji') { - completion = suggestion.native || suggestion.colons; + completion = suggestion.native || suggestion.colons; + startPosition = position - 1; dispatch(useEmoji(suggestion)); } else if (suggestion.type === 'hashtag') { - completion = `#${suggestion.name}`; + completion = `#${suggestion.name}`; + startPosition = position - 1; } else if (suggestion.type === 'account') { - completion = '@' + getState().getIn(['accounts', suggestion.id, 'acct']); + completion = getState().getIn(['accounts', suggestion.id, 'acct']); + startPosition = position; } // We don't want to replace hashtags that vary only in case due to accessibility, but we need to fire off an event so that @@ -676,7 +668,7 @@ export function selectComposeSuggestion(position, token, suggestion, path) { if (suggestion.type !== 'hashtag' || token.slice(1).localeCompare(suggestion.name, undefined, { sensitivity: 'accent' }) !== 0) { dispatch({ type: COMPOSE_SUGGESTION_SELECT, - position, + position: startPosition, token, completion, path, @@ -684,7 +676,7 @@ export function selectComposeSuggestion(position, token, suggestion, path) { } else { dispatch({ type: COMPOSE_SUGGESTION_IGNORE, - position, + position: startPosition, token, completion, path, @@ -786,18 +778,26 @@ export function changeComposeVisibility(value) { }; } -export function changeComposeContentType(value) { - return { - type: COMPOSE_CONTENT_TYPE_CHANGE, - value, - }; -} - -export function insertEmojiCompose(position, emoji) { +export function insertEmojiCompose(position, emoji, needsSpace) { return { type: COMPOSE_EMOJI_INSERT, position, emoji, + needsSpace, + }; +} + +export function changeComposing(value) { + return { + type: COMPOSE_COMPOSING_CHANGE, + value, + }; +} + +export function changeComposeContentType(value) { + return { + type: COMPOSE_CONTENT_TYPE_CHANGE, + value, }; } diff --git a/app/javascript/flavours/glitch/components/account.jsx b/app/javascript/flavours/glitch/components/account.jsx index fd7caea6df..7e5209653e 100644 --- a/app/javascript/flavours/glitch/components/account.jsx +++ b/app/javascript/flavours/glitch/components/account.jsx @@ -37,10 +37,10 @@ class Account extends ImmutablePureComponent { static propTypes = { size: PropTypes.number, account: ImmutablePropTypes.record, - onFollow: PropTypes.func.isRequired, - onBlock: PropTypes.func.isRequired, - onMute: PropTypes.func.isRequired, - onMuteNotifications: PropTypes.func.isRequired, + onFollow: PropTypes.func, + onBlock: PropTypes.func, + onMute: PropTypes.func, + onMuteNotifications: PropTypes.func, intl: PropTypes.object.isRequired, hidden: PropTypes.bool, minimal: PropTypes.bool, diff --git a/app/javascript/flavours/glitch/components/autosuggest_emoji.jsx b/app/javascript/flavours/glitch/components/autosuggest_emoji.jsx index eb25f5a643..892d068b31 100644 --- a/app/javascript/flavours/glitch/components/autosuggest_emoji.jsx +++ b/app/javascript/flavours/glitch/components/autosuggest_emoji.jsx @@ -35,7 +35,7 @@ export default class AutosuggestEmoji extends PureComponent { alt={emoji.native || emoji.colons} /> - {emoji.colons} +
{emoji.colons}
); } diff --git a/app/javascript/flavours/glitch/components/autosuggest_hashtag.tsx b/app/javascript/flavours/glitch/components/autosuggest_hashtag.tsx index 6da6200142..808f303754 100644 --- a/app/javascript/flavours/glitch/components/autosuggest_hashtag.tsx +++ b/app/javascript/flavours/glitch/components/autosuggest_hashtag.tsx @@ -1,5 +1,3 @@ -import { FormattedMessage } from 'react-intl'; - import { ShortNumber } from 'flavours/glitch/components/short_number'; interface Props { @@ -16,27 +14,18 @@ interface Props { }; } -export const AutosuggestHashtag: React.FC = ({ tag }) => { - const weeklyUses = tag.history && ( - total + day.uses * 1, 0)} - /> - ); - - return ( -
-
- #{tag.name} -
- {tag.history !== undefined && ( -
- -
- )} +export const AutosuggestHashtag: React.FC = ({ tag }) => ( +
+
+ #{tag.name}
- ); -}; + + {tag.history !== undefined && ( +
+ total + day.uses * 1, 0)} + /> +
+ )} +
+); diff --git a/app/javascript/flavours/glitch/components/autosuggest_input.jsx b/app/javascript/flavours/glitch/components/autosuggest_input.jsx index 6d2474b442..f707a18e1d 100644 --- a/app/javascript/flavours/glitch/components/autosuggest_input.jsx +++ b/app/javascript/flavours/glitch/components/autosuggest_input.jsx @@ -5,6 +5,8 @@ import classNames from 'classnames'; import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePureComponent from 'react-immutable-pure-component'; +import Overlay from 'react-overlays/Overlay'; + import AutosuggestAccountContainer from '../features/compose/containers/autosuggest_account_container'; import AutosuggestEmoji from './autosuggest_emoji'; @@ -13,8 +15,8 @@ import { AutosuggestHashtag } from './autosuggest_hashtag'; const textAtCursorMatchesToken = (str, caretPosition, searchTokens) => { let word; - let left = str.slice(0, caretPosition).search(/[^\s\u200B]+$/); - let right = str.slice(caretPosition).search(/[\s\u200B]/); + let left = str.slice(0, caretPosition).search(/\S+$/); + let right = str.slice(caretPosition).search(/\s/); if (right < 0) { word = str.slice(left); @@ -29,7 +31,7 @@ const textAtCursorMatchesToken = (str, caretPosition, searchTokens) => { word = word.trim().toLowerCase(); if (word.length > 0) { - return [left, word]; + return [left + 1, word]; } else { return [null, null]; } @@ -195,34 +197,37 @@ export default class AutosuggestInput extends ImmutablePureComponent { return (
- - -
- {suggestions.map(this.renderSuggestion)} -
+ + {({ props }) => ( +
+
+ {suggestions.map(this.renderSuggestion)} +
+
+ )} +
); } diff --git a/app/javascript/flavours/glitch/components/autosuggest_textarea.jsx b/app/javascript/flavours/glitch/components/autosuggest_textarea.jsx index 28384075c3..07fbccacc9 100644 --- a/app/javascript/flavours/glitch/components/autosuggest_textarea.jsx +++ b/app/javascript/flavours/glitch/components/autosuggest_textarea.jsx @@ -5,6 +5,7 @@ import classNames from 'classnames'; import ImmutablePropTypes from 'react-immutable-proptypes'; +import Overlay from 'react-overlays/Overlay'; import Textarea from 'react-textarea-autosize'; import AutosuggestAccountContainer from '../features/compose/containers/autosuggest_account_container'; @@ -15,8 +16,8 @@ import { AutosuggestHashtag } from './autosuggest_hashtag'; const textAtCursorMatchesToken = (str, caretPosition) => { let word; - let left = str.slice(0, caretPosition).search(/[^\s\u200B]+$/); - let right = str.slice(caretPosition).search(/[\s\u200B]/); + let left = str.slice(0, caretPosition).search(/\S+$/); + let right = str.slice(caretPosition).search(/\s/); if (right < 0) { word = str.slice(left); @@ -31,7 +32,7 @@ const textAtCursorMatchesToken = (str, caretPosition) => { word = word.trim().toLowerCase(); if (word.length > 0) { - return [left, word]; + return [left + 1, word]; } else { return [null, null]; } @@ -52,7 +53,6 @@ const AutosuggestTextarea = forwardRef(({ onFocus, autoFocus = true, lang, - children, }, textareaRef) => { const [suggestionsHidden, setSuggestionsHidden] = useState(true); @@ -183,40 +183,38 @@ const AutosuggestTextarea = forwardRef(({ ); }; - return [ -
-
-