Fix handling of enter/return in space creation menu

This commit is contained in:
Michael Telatynski 2021-05-10 14:39:10 +01:00
parent 45acf70b00
commit 3a75eb1226
3 changed files with 83 additions and 29 deletions

View file

@ -32,17 +32,11 @@ interface IProps {
setTopic(topic: string): void;
}
const SpaceBasicSettings = ({
export const SpaceAvatar = ({
avatarUrl,
avatarDisabled = false,
setAvatar,
name = "",
nameDisabled = false,
setName,
topic = "",
topicDisabled = false,
setTopic,
}: IProps) => {
}: Pick<IProps, "avatarUrl" | "avatarDisabled" | "setAvatar">) => {
const avatarUploadRef = useRef<HTMLInputElement>();
const [avatar, setAvatarDataUrl] = useState(avatarUrl); // avatar data url cache
@ -81,20 +75,34 @@ const SpaceBasicSettings = ({
}
}
return <div className="mx_SpaceBasicSettings_avatarContainer">
{ avatarSection }
<input type="file" ref={avatarUploadRef} onChange={(e) => {
if (!e.target.files?.length) return;
const file = e.target.files[0];
setAvatar(file);
const reader = new FileReader();
reader.onload = (ev) => {
setAvatarDataUrl(ev.target.result as string);
};
reader.readAsDataURL(file);
}} accept="image/*" />
</div>;
};
const SpaceBasicSettings = ({
avatarUrl,
avatarDisabled = false,
setAvatar,
name = "",
nameDisabled = false,
setName,
topic = "",
topicDisabled = false,
setTopic,
}: IProps) => {
return <div className="mx_SpaceBasicSettings">
<div className="mx_SpaceBasicSettings_avatarContainer">
{ avatarSection }
<input type="file" ref={avatarUploadRef} onChange={(e) => {
if (!e.target.files?.length) return;
const file = e.target.files[0];
setAvatar(file);
const reader = new FileReader();
reader.onload = (ev) => {
setAvatarDataUrl(ev.target.result as string);
};
reader.readAsDataURL(file);
}} accept="image/*" />
</div>
<SpaceAvatar avatarUrl={avatarUrl} avatarDisabled={avatarDisabled} setAvatar={setAvatar} />
<Field
name="spaceName"

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React, {useContext, useState} from "react";
import React, {useContext, useRef, useState} from "react";
import classNames from "classnames";
import {EventType, RoomType, RoomCreateTypeField} from "matrix-js-sdk/src/@types/event";
@ -23,9 +23,11 @@ import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
import {ChevronFace, ContextMenu} from "../../structures/ContextMenu";
import createRoom, {IStateEvent, Preset} from "../../../createRoom";
import MatrixClientContext from "../../../contexts/MatrixClientContext";
import SpaceBasicSettings from "./SpaceBasicSettings";
import {SpaceAvatar} from "./SpaceBasicSettings";
import AccessibleButton from "../elements/AccessibleButton";
import FocusLock from "react-focus-lock";
import Field from "../elements/Field";
import withValidation from "../elements/Validation";
const SpaceCreateMenuType = ({ title, description, className, onClick }) => {
return (
@ -41,17 +43,39 @@ enum Visibility {
Private,
}
const spaceNameValidator = withValidation({
rules: [
{
key: "required",
test: async ({ value }) => !!value,
invalid: () => _t("Please enter a name for the space"),
},
],
});
const SpaceCreateMenu = ({ onFinished }) => {
const cli = useContext(MatrixClientContext);
const [visibility, setVisibility] = useState<Visibility>(null);
const [name, setName] = useState("");
const [avatar, setAvatar] = useState<File>(null);
const [topic, setTopic] = useState<string>("");
const [busy, setBusy] = useState<boolean>(false);
const onSpaceCreateClick = async () => {
const [name, setName] = useState("");
const spaceNameField = useRef<Field>();
const [avatar, setAvatar] = useState<File>(null);
const [topic, setTopic] = useState<string>("");
const onSpaceCreateClick = async (e) => {
e.preventDefault();
if (busy) return;
setBusy(true);
// require & validate the space name field
if (!await spaceNameField.current.validate({ allowEmpty: false })) {
spaceNameField.current.focus();
spaceNameField.current.validate({ allowEmpty: false, focused: true });
setBusy(false);
return;
}
const initialState: IStateEvent[] = [
{
type: EventType.RoomHistoryVisibility,
@ -146,9 +170,30 @@ const SpaceCreateMenu = ({ onFinished }) => {
}
</p>
<SpaceBasicSettings setAvatar={setAvatar} name={name} setName={setName} topic={topic} setTopic={setTopic} />
<form className="mx_SpaceBasicSettings" onSubmit={onSpaceCreateClick}>
<SpaceAvatar setAvatar={setAvatar} />
<AccessibleButton kind="primary" onClick={onSpaceCreateClick} disabled={!name || busy}>
<Field
name="spaceName"
label={_t("Name")}
autoFocus={true}
value={name}
onChange={ev => setName(ev.target.value)}
ref={spaceNameField}
onValidate={spaceNameValidator}
/>
<Field
name="spaceTopic"
element="textarea"
label={_t("Description")}
value={topic}
onChange={ev => setTopic(ev.target.value)}
rows={3}
/>
</form>
<AccessibleButton kind="primary" onClick={onSpaceCreateClick} disabled={busy}>
{ busy ? _t("Creating...") : _t("Create") }
</AccessibleButton>
</React.Fragment>;

View file

@ -996,6 +996,7 @@
"Upload": "Upload",
"Name": "Name",
"Description": "Description",
"Please enter a name for the space": "Please enter a name for the space",
"Create a space": "Create a space",
"Spaces are new ways to group rooms and people. To join an existing space you'll need an invite.": "Spaces are new ways to group rooms and people. To join an existing space you'll need an invite.",
"Public": "Public",