From db8cd68d8b0cf9d8ea0cdb5b7ebba18b42e7af80 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 3 Nov 2020 12:47:13 +0000 Subject: [PATCH 1/7] Rearrange copy --- src/components/views/dialogs/InviteDialog.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/views/dialogs/InviteDialog.js b/src/components/views/dialogs/InviteDialog.js index fc3245aa18..108fa4d8c7 100644 --- a/src/components/views/dialogs/InviteDialog.js +++ b/src/components/views/dialogs/InviteDialog.js @@ -1103,7 +1103,7 @@ export default class InviteDialog extends React.PureComponent { if (identityServersEnabled) { helpText = _t( - "Start a conversation with someone using their name, username (like ) or email address.", + "Start a conversation with someone using their name, email address or username (like ).", {}, {userId: () => { return ( @@ -1158,7 +1158,7 @@ export default class InviteDialog extends React.PureComponent { if (identityServersEnabled) { helpText = _t( - "Invite someone using their name, username (like ), email address or " + + "Invite someone using their name, email address, username (like ) or " + "share this room.", {}, { From 66377eb731d347cd94341c2475fa5a12704f8c5b Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 3 Nov 2020 13:14:35 +0000 Subject: [PATCH 2/7] Invite UX tweaks: + re-focus input field after all interactions + change textarea to text input + fix margins between things + improve keyboard usage with enter/space autofilling --- res/css/views/dialogs/_InviteDialog.scss | 32 ++++++++------------ src/components/views/dialogs/InviteDialog.js | 32 +++++++++++++++----- 2 files changed, 37 insertions(+), 27 deletions(-) diff --git a/res/css/views/dialogs/_InviteDialog.scss b/res/css/views/dialogs/_InviteDialog.scss index b9063f46b9..a6871f7547 100644 --- a/res/css/views/dialogs/_InviteDialog.scss +++ b/res/css/views/dialogs/_InviteDialog.scss @@ -27,37 +27,29 @@ limitations under the License. padding-left: 8px; overflow-x: hidden; overflow-y: auto; + display: flex; + flex-wrap: wrap; .mx_InviteDialog_userTile { + margin: 6px 6px 0 0; display: inline-block; - float: left; - position: relative; - top: 7px; + min-width: max-content; // prevent manipulation by flexbox } - // Using a textarea for this element, to circumvent autofill - // Mostly copied from AddressPickerDialog - textarea, - textarea:focus { - height: 34px; - line-height: $font-34px; + // Mostly copied from AddressPickerDialog; overrides bunch of our default text input styles + input, input:focus { + margin: 6px 0 !important; + height: 24px; + line-height: $font-24px; font-size: $font-14px; padding-left: 12px; - margin: 0 !important; border: 0 !important; outline: 0 !important; resize: none; - overflow: hidden; box-sizing: border-box; - word-wrap: nowrap; - - // Roughly fill about 2/5ths of the available space. This is to try and 'fill' the - // remaining space after a bunch of pills, but is a bit hacky. Ideally we'd have - // support for "fill remaining width", but traditional tricks don't work with what - // we're pushing into this "field". Flexbox just makes things worse. The theory is - // that users won't need more than about 2/5ths of the input to find the person - // they're looking for. - width: 40%; + min-width: 40%; + flex: 1 !important; + color: $primary-fg-color !important; } } diff --git a/src/components/views/dialogs/InviteDialog.js b/src/components/views/dialogs/InviteDialog.js index 108fa4d8c7..5e97e94403 100644 --- a/src/components/views/dialogs/InviteDialog.js +++ b/src/components/views/dialogs/InviteDialog.js @@ -663,12 +663,21 @@ export default class InviteDialog extends React.PureComponent { }; _onKeyDown = (e) => { - // when the field is empty and the user hits backspace remove the right-most target - if (!e.target.value && !this.state.busy && this.state.targets.length > 0 && e.key === Key.BACKSPACE && - !e.ctrlKey && !e.shiftKey && !e.metaKey - ) { + if (this.state.busy) return; + const value = e.target.value.trim(); + const hasModifiers = e.ctrlKey || e.shiftKey || e.metaKey; + if (!value && this.state.targets.length > 0 && e.key === Key.BACKSPACE && !hasModifiers) { + // when the field is empty and the user hits backspace remove the right-most target e.preventDefault(); this._removeMember(this.state.targets[this.state.targets.length - 1]); + } else if (value && e.key === Key.ENTER && !hasModifiers) { + // when the user hits enter with something in their field try to convert it + e.preventDefault(); + this._convertFilter(); + } else if (value && e.key === Key.SPACE && !hasModifiers && value.includes("@") && !value.includes(" ")) { + // when the user hits space and their input looks like an e-mail/MXID then try to convert it + e.preventDefault(); + this._convertFilter(); } }; @@ -811,6 +820,10 @@ export default class InviteDialog extends React.PureComponent { filterText = ""; // clear the filter when the user accepts a suggestion } this.setState({targets, filterText}); + + if (this._editorRef && this._editorRef.current) { + this._editorRef.current.focus(); + } }; _removeMember = (member: Member) => { @@ -820,6 +833,10 @@ export default class InviteDialog extends React.PureComponent { targets.splice(idx, 1); this.setState({targets}); } + + if (this._editorRef && this._editorRef.current) { + this._editorRef.current.focus(); + } }; _onPaste = async (e) => { @@ -829,7 +846,7 @@ export default class InviteDialog extends React.PureComponent { return; } - // Prevent the text being pasted into the textarea + // Prevent the text being pasted into the input e.preventDefault(); // Process it as a list of addresses to add instead @@ -1024,8 +1041,8 @@ export default class InviteDialog extends React.PureComponent { )); const input = ( -