Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit 5a8525d

Browse files
authored
Merge pull request #5387 from matrix-org/t3chguy/fix/13066
Invite / Create DM UX tweaks
2 parents 5c9acc3 + 6029f2a commit 5a8525d

File tree

6 files changed

+60
-37
lines changed

6 files changed

+60
-37
lines changed

res/css/_common.scss

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
*/
1818

1919
@import "./_font-sizes.scss";
20+
@import "./_font-weights.scss";
2021

2122
$hover-transition: 0.08s cubic-bezier(.46, .03, .52, .96); // quadratic
2223

@@ -323,6 +324,7 @@ input[type=text]:focus, input[type=password]:focus, textarea:focus {
323324

324325
.mx_Dialog_title {
325326
font-size: $font-22px;
327+
font-weight: $font-semi-bold;
326328
line-height: $font-36px;
327329
color: $dialog-title-fg-color;
328330
}
@@ -348,8 +350,8 @@ input[type=text]:focus, input[type=password]:focus, textarea:focus {
348350
background-color: $dialog-close-fg-color;
349351
cursor: pointer;
350352
position: absolute;
351-
top: 4px;
352-
right: 0px;
353+
top: 10px;
354+
right: 0;
353355
}
354356

355357
.mx_Dialog_content {

res/css/views/dialogs/_InviteDialog.scss

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -27,37 +27,29 @@ limitations under the License.
2727
padding-left: 8px;
2828
overflow-x: hidden;
2929
overflow-y: auto;
30+
display: flex;
31+
flex-wrap: wrap;
3032

3133
.mx_InviteDialog_userTile {
34+
margin: 6px 6px 0 0;
3235
display: inline-block;
33-
float: left;
34-
position: relative;
35-
top: 7px;
36+
min-width: max-content; // prevent manipulation by flexbox
3637
}
3738

38-
// Using a textarea for this element, to circumvent autofill
39-
// Mostly copied from AddressPickerDialog
40-
textarea,
41-
textarea:focus {
42-
height: 34px;
43-
line-height: $font-34px;
39+
// Mostly copied from AddressPickerDialog; overrides bunch of our default text input styles
40+
> input[type="text"] {
41+
margin: 6px 0 !important;
42+
height: 24px;
43+
line-height: $font-24px;
4444
font-size: $font-14px;
4545
padding-left: 12px;
46-
margin: 0 !important;
4746
border: 0 !important;
4847
outline: 0 !important;
4948
resize: none;
50-
overflow: hidden;
5149
box-sizing: border-box;
52-
word-wrap: nowrap;
53-
54-
// Roughly fill about 2/5ths of the available space. This is to try and 'fill' the
55-
// remaining space after a bunch of pills, but is a bit hacky. Ideally we'd have
56-
// support for "fill remaining width", but traditional tricks don't work with what
57-
// we're pushing into this "field". Flexbox just makes things worse. The theory is
58-
// that users won't need more than about 2/5ths of the input to find the person
59-
// they're looking for.
60-
width: 40%;
50+
min-width: 40%;
51+
flex: 1 !important;
52+
color: $primary-fg-color !important;
6153
}
6254
}
6355

@@ -148,6 +140,10 @@ limitations under the License.
148140
}
149141
}
150142

143+
.mx_InviteDialog_roomTile_nameStack {
144+
display: inline-block;
145+
}
146+
151147
.mx_InviteDialog_roomTile_name {
152148
font-weight: 600;
153149
font-size: $font-14px;

src/components/views/dialogs/InviteDialog.js

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -280,11 +280,17 @@ class DMRoomTile extends React.PureComponent {
280280
</span>
281281
);
282282

283+
const caption = this.props.member.isEmail
284+
? _t("Invite by email")
285+
: this._highlightName(this.props.member.userId);
286+
283287
return (
284288
<div className='mx_InviteDialog_roomTile' onClick={this._onClick}>
285289
{stackedAvatar}
286-
<span className='mx_InviteDialog_roomTile_name'>{this._highlightName(this.props.member.name)}</span>
287-
<span className='mx_InviteDialog_roomTile_userId'>{this._highlightName(this.props.member.userId)}</span>
290+
<span className="mx_InviteDialog_roomTile_nameStack">
291+
<div className='mx_InviteDialog_roomTile_name'>{this._highlightName(this.props.member.name)}</div>
292+
<div className='mx_InviteDialog_roomTile_userId'>{caption}</div>
293+
</span>
288294
{timestamp}
289295
</div>
290296
);
@@ -663,12 +669,21 @@ export default class InviteDialog extends React.PureComponent {
663669
};
664670

665671
_onKeyDown = (e) => {
666-
// when the field is empty and the user hits backspace remove the right-most target
667-
if (!e.target.value && !this.state.busy && this.state.targets.length > 0 && e.key === Key.BACKSPACE &&
668-
!e.ctrlKey && !e.shiftKey && !e.metaKey
669-
) {
672+
if (this.state.busy) return;
673+
const value = e.target.value.trim();
674+
const hasModifiers = e.ctrlKey || e.shiftKey || e.metaKey;
675+
if (!value && this.state.targets.length > 0 && e.key === Key.BACKSPACE && !hasModifiers) {
676+
// when the field is empty and the user hits backspace remove the right-most target
670677
e.preventDefault();
671678
this._removeMember(this.state.targets[this.state.targets.length - 1]);
679+
} else if (value && e.key === Key.ENTER && !hasModifiers) {
680+
// when the user hits enter with something in their field try to convert it
681+
e.preventDefault();
682+
this._convertFilter();
683+
} else if (value && e.key === Key.SPACE && !hasModifiers && value.includes("@") && !value.includes(" ")) {
684+
// when the user hits space and their input looks like an e-mail/MXID then try to convert it
685+
e.preventDefault();
686+
this._convertFilter();
672687
}
673688
};
674689

@@ -811,6 +826,10 @@ export default class InviteDialog extends React.PureComponent {
811826
filterText = ""; // clear the filter when the user accepts a suggestion
812827
}
813828
this.setState({targets, filterText});
829+
830+
if (this._editorRef && this._editorRef.current) {
831+
this._editorRef.current.focus();
832+
}
814833
};
815834

816835
_removeMember = (member: Member) => {
@@ -820,6 +839,10 @@ export default class InviteDialog extends React.PureComponent {
820839
targets.splice(idx, 1);
821840
this.setState({targets});
822841
}
842+
843+
if (this._editorRef && this._editorRef.current) {
844+
this._editorRef.current.focus();
845+
}
823846
};
824847

825848
_onPaste = async (e) => {
@@ -829,7 +852,7 @@ export default class InviteDialog extends React.PureComponent {
829852
return;
830853
}
831854

832-
// Prevent the text being pasted into the textarea
855+
// Prevent the text being pasted into the input
833856
e.preventDefault();
834857

835858
// Process it as a list of addresses to add instead
@@ -1024,15 +1047,16 @@ export default class InviteDialog extends React.PureComponent {
10241047
<DMUserTile member={t} onRemove={!this.state.busy && this._removeMember} key={t.userId} />
10251048
));
10261049
const input = (
1027-
<textarea
1028-
rows={1}
1050+
<input
1051+
type="text"
10291052
onKeyDown={this._onKeyDown}
10301053
onChange={this._updateFilter}
10311054
value={this.state.filterText}
10321055
ref={this._editorRef}
10331056
onPaste={this._onPaste}
10341057
autoFocus={true}
10351058
disabled={this.state.busy}
1059+
autoComplete="off"
10361060
/>
10371061
);
10381062
return (
@@ -1103,7 +1127,7 @@ export default class InviteDialog extends React.PureComponent {
11031127

11041128
if (identityServersEnabled) {
11051129
helpText = _t(
1106-
"Start a conversation with someone using their name, username (like <userId/>) or email address.",
1130+
"Start a conversation with someone using their name, email address or username (like <userId/>).",
11071131
{},
11081132
{userId: () => {
11091133
return (
@@ -1158,7 +1182,7 @@ export default class InviteDialog extends React.PureComponent {
11581182

11591183
if (identityServersEnabled) {
11601184
helpText = _t(
1161-
"Invite someone using their name, username (like <userId/>), email address or " +
1185+
"Invite someone using their name, email address, username (like <userId/>) or " +
11621186
"<a>share this room</a>.",
11631187
{},
11641188
{

src/i18n/strings/en_EN.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1724,6 +1724,7 @@
17241724
"To continue, use Single Sign On to prove your identity.": "To continue, use Single Sign On to prove your identity.",
17251725
"Confirm to continue": "Confirm to continue",
17261726
"Click the button below to confirm your identity.": "Click the button below to confirm your identity.",
1727+
"Invite by email": "Invite by email",
17271728
"Failed to invite the following users to chat: %(csvUsers)s": "Failed to invite the following users to chat: %(csvUsers)s",
17281729
"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.",
17291730
"Something went wrong trying to invite the users.": "Something went wrong trying to invite the users.",
@@ -1735,11 +1736,11 @@
17351736
"May include members not in %(communityName)s": "May include members not in %(communityName)s",
17361737
"Recently Direct Messaged": "Recently Direct Messaged",
17371738
"Direct Messages": "Direct Messages",
1738-
"Start a conversation with someone using their name, username (like <userId/>) or email address.": "Start a conversation with someone using their name, username (like <userId/>) or email address.",
1739+
"Start a conversation with someone using their name, email address or username (like <userId/>).": "Start a conversation with someone using their name, email address or username (like <userId/>).",
17391740
"Start a conversation with someone using their name or username (like <userId/>).": "Start a conversation with someone using their name or username (like <userId/>).",
17401741
"This won't invite them to %(communityName)s. To invite someone to %(communityName)s, click <a>here</a>": "This won't invite them to %(communityName)s. To invite someone to %(communityName)s, click <a>here</a>",
17411742
"Go": "Go",
1742-
"Invite someone using their name, username (like <userId/>), email address or <a>share this room</a>.": "Invite someone using their name, username (like <userId/>), email address or <a>share this room</a>.",
1743+
"Invite someone using their name, email address, username (like <userId/>) or <a>share this room</a>.": "Invite someone using their name, email address, username (like <userId/>) or <a>share this room</a>.",
17431744
"Invite someone using their name, username (like <userId/>) or <a>share this room</a>.": "Invite someone using their name, username (like <userId/>) or <a>share this room</a>.",
17441745
"a new master key signature": "a new master key signature",
17451746
"a new cross-signing key signature": "a new cross-signing key signature",

test/end-to-end-tests/src/usecases/create-room.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ async function createDm(session, invitees) {
6464
const startChatButton = await dmsSublist.$(".mx_RoomSublist_auxButton");
6565
await startChatButton.click();
6666

67-
const inviteesEditor = await session.query('.mx_InviteDialog_editor textarea');
67+
const inviteesEditor = await session.query('.mx_InviteDialog_editor input');
6868
for (const target of invitees) {
6969
await session.replaceInputText(inviteesEditor, target);
7070
await session.delay(1000); // give it a moment to figure out a suggestion

test/end-to-end-tests/src/usecases/invite.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ module.exports = async function invite(session, userId) {
3131
}
3232
const inviteButton = await session.query(".mx_MemberList_invite");
3333
await inviteButton.click();
34-
const inviteTextArea = await session.query(".mx_InviteDialog_editor textarea");
34+
const inviteTextArea = await session.query(".mx_InviteDialog_editor input");
3535
await inviteTextArea.type(userId);
3636
const selectUserItem = await session.query(".mx_InviteDialog_roomTile");
3737
await selectUserItem.click();

0 commit comments

Comments
 (0)