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 autofillingpull/21833/head
parent
db8cd68d8b
commit
66377eb731
|
@ -27,37 +27,29 @@ limitations under the License.
|
||||||
padding-left: 8px;
|
padding-left: 8px;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
.mx_InviteDialog_userTile {
|
.mx_InviteDialog_userTile {
|
||||||
|
margin: 6px 6px 0 0;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
float: left;
|
min-width: max-content; // prevent manipulation by flexbox
|
||||||
position: relative;
|
|
||||||
top: 7px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Using a textarea for this element, to circumvent autofill
|
// Mostly copied from AddressPickerDialog; overrides bunch of our default text input styles
|
||||||
// Mostly copied from AddressPickerDialog
|
input, input:focus {
|
||||||
textarea,
|
margin: 6px 0 !important;
|
||||||
textarea:focus {
|
height: 24px;
|
||||||
height: 34px;
|
line-height: $font-24px;
|
||||||
line-height: $font-34px;
|
|
||||||
font-size: $font-14px;
|
font-size: $font-14px;
|
||||||
padding-left: 12px;
|
padding-left: 12px;
|
||||||
margin: 0 !important;
|
|
||||||
border: 0 !important;
|
border: 0 !important;
|
||||||
outline: 0 !important;
|
outline: 0 !important;
|
||||||
resize: none;
|
resize: none;
|
||||||
overflow: hidden;
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
word-wrap: nowrap;
|
min-width: 40%;
|
||||||
|
flex: 1 !important;
|
||||||
// Roughly fill about 2/5ths of the available space. This is to try and 'fill' the
|
color: $primary-fg-color !important;
|
||||||
// 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%;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -663,12 +663,21 @@ export default class InviteDialog extends React.PureComponent {
|
||||||
};
|
};
|
||||||
|
|
||||||
_onKeyDown = (e) => {
|
_onKeyDown = (e) => {
|
||||||
|
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
|
// 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
|
|
||||||
) {
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this._removeMember(this.state.targets[this.state.targets.length - 1]);
|
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
|
filterText = ""; // clear the filter when the user accepts a suggestion
|
||||||
}
|
}
|
||||||
this.setState({targets, filterText});
|
this.setState({targets, filterText});
|
||||||
|
|
||||||
|
if (this._editorRef && this._editorRef.current) {
|
||||||
|
this._editorRef.current.focus();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
_removeMember = (member: Member) => {
|
_removeMember = (member: Member) => {
|
||||||
|
@ -820,6 +833,10 @@ export default class InviteDialog extends React.PureComponent {
|
||||||
targets.splice(idx, 1);
|
targets.splice(idx, 1);
|
||||||
this.setState({targets});
|
this.setState({targets});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this._editorRef && this._editorRef.current) {
|
||||||
|
this._editorRef.current.focus();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
_onPaste = async (e) => {
|
_onPaste = async (e) => {
|
||||||
|
@ -829,7 +846,7 @@ export default class InviteDialog extends React.PureComponent {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prevent the text being pasted into the textarea
|
// Prevent the text being pasted into the input
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
// Process it as a list of addresses to add instead
|
// Process it as a list of addresses to add instead
|
||||||
|
@ -1024,8 +1041,8 @@ export default class InviteDialog extends React.PureComponent {
|
||||||
<DMUserTile member={t} onRemove={!this.state.busy && this._removeMember} key={t.userId} />
|
<DMUserTile member={t} onRemove={!this.state.busy && this._removeMember} key={t.userId} />
|
||||||
));
|
));
|
||||||
const input = (
|
const input = (
|
||||||
<textarea
|
<input
|
||||||
rows={1}
|
type="text"
|
||||||
onKeyDown={this._onKeyDown}
|
onKeyDown={this._onKeyDown}
|
||||||
onChange={this._updateFilter}
|
onChange={this._updateFilter}
|
||||||
value={this.state.filterText}
|
value={this.state.filterText}
|
||||||
|
@ -1033,6 +1050,7 @@ export default class InviteDialog extends React.PureComponent {
|
||||||
onPaste={this._onPaste}
|
onPaste={this._onPaste}
|
||||||
autoFocus={true}
|
autoFocus={true}
|
||||||
disabled={this.state.busy}
|
disabled={this.state.busy}
|
||||||
|
autoComplete="off"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
|
|
Loading…
Reference in New Issue