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 = (
-
);
return (
From a2885dcfe88e865be0cecda5feb99d27d7881f16 Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Tue, 3 Nov 2020 13:18:18 +0000
Subject: [PATCH 3/7] fix alignment of Modal X icon
---
res/css/_common.scss | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/res/css/_common.scss b/res/css/_common.scss
index 666129af34..ec3a1d9c3f 100644
--- a/res/css/_common.scss
+++ b/res/css/_common.scss
@@ -348,8 +348,8 @@ input[type=text]:focus, input[type=password]:focus, textarea:focus {
background-color: $dialog-close-fg-color;
cursor: pointer;
position: absolute;
- top: 4px;
- right: 0px;
+ top: 10px;
+ right: 0;
}
.mx_Dialog_content {
From 2064cf80f58121c3f05483543a0eff9258ec1be0 Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Tue, 3 Nov 2020 13:21:33 +0000
Subject: [PATCH 4/7] Use semi-bold for Modal titles
---
res/css/_common.scss | 2 ++
1 file changed, 2 insertions(+)
diff --git a/res/css/_common.scss b/res/css/_common.scss
index ec3a1d9c3f..0317e89d20 100644
--- a/res/css/_common.scss
+++ b/res/css/_common.scss
@@ -17,6 +17,7 @@ limitations under the License.
*/
@import "./_font-sizes.scss";
+@import "./_font-weights.scss";
$hover-transition: 0.08s cubic-bezier(.46, .03, .52, .96); // quadratic
@@ -323,6 +324,7 @@ input[type=text]:focus, input[type=password]:focus, textarea:focus {
.mx_Dialog_title {
font-size: $font-22px;
+ font-weight: $font-semi-bold;
line-height: $font-36px;
color: $dialog-title-fg-color;
}
From 3b7b66c8562cced08134b4b2de81ebf99fccf622 Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Tue, 3 Nov 2020 14:56:06 +0000
Subject: [PATCH 5/7] Change out caption for email invite suggestions and stack
vertically
---
res/css/views/dialogs/_InviteDialog.scss | 6 +++++-
src/components/views/dialogs/InviteDialog.js | 10 ++++++++--
2 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/res/css/views/dialogs/_InviteDialog.scss b/res/css/views/dialogs/_InviteDialog.scss
index a6871f7547..d8ff56663a 100644
--- a/res/css/views/dialogs/_InviteDialog.scss
+++ b/res/css/views/dialogs/_InviteDialog.scss
@@ -37,7 +37,7 @@ limitations under the License.
}
// Mostly copied from AddressPickerDialog; overrides bunch of our default text input styles
- input, input:focus {
+ > input[type="text"] {
margin: 6px 0 !important;
height: 24px;
line-height: $font-24px;
@@ -140,6 +140,10 @@ limitations under the License.
}
}
+ .mx_InviteDialog_roomTile_nameStack {
+ display: inline-block;
+ }
+
.mx_InviteDialog_roomTile_name {
font-weight: 600;
font-size: $font-14px;
diff --git a/src/components/views/dialogs/InviteDialog.js b/src/components/views/dialogs/InviteDialog.js
index 5e97e94403..99878569d3 100644
--- a/src/components/views/dialogs/InviteDialog.js
+++ b/src/components/views/dialogs/InviteDialog.js
@@ -280,11 +280,17 @@ class DMRoomTile extends React.PureComponent {
);
+ const caption = this.props.member.isEmail
+ ? _t("Invite by email")
+ : this._highlightName(this.props.member.userId);
+
return (
{stackedAvatar}
-
{this._highlightName(this.props.member.name)}
-
{this._highlightName(this.props.member.userId)}
+
+ {this._highlightName(this.props.member.name)}
+ {caption}
+
{timestamp}
);
From 0221c4aebff9afe363fcd80a4a780d1c5ff56d3e Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Tue, 3 Nov 2020 14:56:16 +0000
Subject: [PATCH 6/7] i18n
---
src/i18n/strings/en_EN.json | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index a461937875..074e94fa23 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -1724,6 +1724,7 @@
"To continue, use Single Sign On to prove your identity.": "To continue, use Single Sign On to prove your identity.",
"Confirm to continue": "Confirm to continue",
"Click the button below to confirm your identity.": "Click the button below to confirm your identity.",
+ "Invite by email": "Invite by email",
"Failed to invite the following users to chat: %(csvUsers)s": "Failed to invite the following users to chat: %(csvUsers)s",
"We couldn't create your DM. Please check the users you want to invite and try again.": "We couldn't create your DM. Please check the users you want to invite and try again.",
"Something went wrong trying to invite the users.": "Something went wrong trying to invite the users.",
@@ -1735,11 +1736,11 @@
"May include members not in %(communityName)s": "May include members not in %(communityName)s",
"Recently Direct Messaged": "Recently Direct Messaged",
"Direct Messages": "Direct Messages",
- "Start a conversation with someone using their name, username (like ) or email address.": "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 ).": "Start a conversation with someone using their name, email address or username (like ).",
"Start a conversation with someone using their name or username (like ).": "Start a conversation with someone using their name or username (like ).",
"This won't invite them to %(communityName)s. To invite someone to %(communityName)s, click here": "This won't invite them to %(communityName)s. To invite someone to %(communityName)s, click here",
"Go": "Go",
- "Invite someone using their name, username (like ), email address or share this room.": "Invite someone using their name, username (like ), email address or share this room.",
+ "Invite someone using their name, email address, username (like ) or share this room.": "Invite someone using their name, email address, username (like ) or share this room.",
"Invite someone using their name, username (like ) or share this room.": "Invite someone using their name, username (like ) or share this room.",
"a new master key signature": "a new master key signature",
"a new cross-signing key signature": "a new cross-signing key signature",
From 6029f2a03bbe5a4df0b4967a6a3258b85f4224ab Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Tue, 3 Nov 2020 15:16:52 +0000
Subject: [PATCH 7/7] update e2e tests for invite ux tweaks
---
test/end-to-end-tests/src/usecases/create-room.js | 2 +-
test/end-to-end-tests/src/usecases/invite.js | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/test/end-to-end-tests/src/usecases/create-room.js b/test/end-to-end-tests/src/usecases/create-room.js
index e05edbc051..35b9d5879e 100644
--- a/test/end-to-end-tests/src/usecases/create-room.js
+++ b/test/end-to-end-tests/src/usecases/create-room.js
@@ -64,7 +64,7 @@ async function createDm(session, invitees) {
const startChatButton = await dmsSublist.$(".mx_RoomSublist_auxButton");
await startChatButton.click();
- const inviteesEditor = await session.query('.mx_InviteDialog_editor textarea');
+ const inviteesEditor = await session.query('.mx_InviteDialog_editor input');
for (const target of invitees) {
await session.replaceInputText(inviteesEditor, target);
await session.delay(1000); // give it a moment to figure out a suggestion
diff --git a/test/end-to-end-tests/src/usecases/invite.js b/test/end-to-end-tests/src/usecases/invite.js
index 75ebc61a88..07c9595fe2 100644
--- a/test/end-to-end-tests/src/usecases/invite.js
+++ b/test/end-to-end-tests/src/usecases/invite.js
@@ -31,7 +31,7 @@ module.exports = async function invite(session, userId) {
}
const inviteButton = await session.query(".mx_MemberList_invite");
await inviteButton.click();
- const inviteTextArea = await session.query(".mx_InviteDialog_editor textarea");
+ const inviteTextArea = await session.query(".mx_InviteDialog_editor input");
await inviteTextArea.type(userId);
const selectUserItem = await session.query(".mx_InviteDialog_roomTile");
await selectUserItem.click();