Fix handling of enter/return in space creation menu
This commit is contained in:
parent
45acf70b00
commit
3a75eb1226
3 changed files with 83 additions and 29 deletions
|
@ -32,17 +32,11 @@ interface IProps {
|
||||||
setTopic(topic: string): void;
|
setTopic(topic: string): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SpaceBasicSettings = ({
|
export const SpaceAvatar = ({
|
||||||
avatarUrl,
|
avatarUrl,
|
||||||
avatarDisabled = false,
|
avatarDisabled = false,
|
||||||
setAvatar,
|
setAvatar,
|
||||||
name = "",
|
}: Pick<IProps, "avatarUrl" | "avatarDisabled" | "setAvatar">) => {
|
||||||
nameDisabled = false,
|
|
||||||
setName,
|
|
||||||
topic = "",
|
|
||||||
topicDisabled = false,
|
|
||||||
setTopic,
|
|
||||||
}: IProps) => {
|
|
||||||
const avatarUploadRef = useRef<HTMLInputElement>();
|
const avatarUploadRef = useRef<HTMLInputElement>();
|
||||||
const [avatar, setAvatarDataUrl] = useState(avatarUrl); // avatar data url cache
|
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">
|
return <div className="mx_SpaceBasicSettings">
|
||||||
<div className="mx_SpaceBasicSettings_avatarContainer">
|
<SpaceAvatar avatarUrl={avatarUrl} avatarDisabled={avatarDisabled} setAvatar={setAvatar} />
|
||||||
{ 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>
|
|
||||||
|
|
||||||
<Field
|
<Field
|
||||||
name="spaceName"
|
name="spaceName"
|
||||||
|
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, {useContext, useState} from "react";
|
import React, {useContext, useRef, useState} from "react";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import {EventType, RoomType, RoomCreateTypeField} from "matrix-js-sdk/src/@types/event";
|
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 {ChevronFace, ContextMenu} from "../../structures/ContextMenu";
|
||||||
import createRoom, {IStateEvent, Preset} from "../../../createRoom";
|
import createRoom, {IStateEvent, Preset} from "../../../createRoom";
|
||||||
import MatrixClientContext from "../../../contexts/MatrixClientContext";
|
import MatrixClientContext from "../../../contexts/MatrixClientContext";
|
||||||
import SpaceBasicSettings from "./SpaceBasicSettings";
|
import {SpaceAvatar} from "./SpaceBasicSettings";
|
||||||
import AccessibleButton from "../elements/AccessibleButton";
|
import AccessibleButton from "../elements/AccessibleButton";
|
||||||
import FocusLock from "react-focus-lock";
|
import FocusLock from "react-focus-lock";
|
||||||
|
import Field from "../elements/Field";
|
||||||
|
import withValidation from "../elements/Validation";
|
||||||
|
|
||||||
const SpaceCreateMenuType = ({ title, description, className, onClick }) => {
|
const SpaceCreateMenuType = ({ title, description, className, onClick }) => {
|
||||||
return (
|
return (
|
||||||
|
@ -41,17 +43,39 @@ enum Visibility {
|
||||||
Private,
|
Private,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const spaceNameValidator = withValidation({
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
key: "required",
|
||||||
|
test: async ({ value }) => !!value,
|
||||||
|
invalid: () => _t("Please enter a name for the space"),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
const SpaceCreateMenu = ({ onFinished }) => {
|
const SpaceCreateMenu = ({ onFinished }) => {
|
||||||
const cli = useContext(MatrixClientContext);
|
const cli = useContext(MatrixClientContext);
|
||||||
const [visibility, setVisibility] = useState<Visibility>(null);
|
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 [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;
|
if (busy) return;
|
||||||
|
|
||||||
setBusy(true);
|
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[] = [
|
const initialState: IStateEvent[] = [
|
||||||
{
|
{
|
||||||
type: EventType.RoomHistoryVisibility,
|
type: EventType.RoomHistoryVisibility,
|
||||||
|
@ -146,9 +170,30 @@ const SpaceCreateMenu = ({ onFinished }) => {
|
||||||
}
|
}
|
||||||
</p>
|
</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") }
|
{ busy ? _t("Creating...") : _t("Create") }
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
</React.Fragment>;
|
</React.Fragment>;
|
||||||
|
|
|
@ -996,6 +996,7 @@
|
||||||
"Upload": "Upload",
|
"Upload": "Upload",
|
||||||
"Name": "Name",
|
"Name": "Name",
|
||||||
"Description": "Description",
|
"Description": "Description",
|
||||||
|
"Please enter a name for the space": "Please enter a name for the space",
|
||||||
"Create a space": "Create a 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.",
|
"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",
|
"Public": "Public",
|
||||||
|
|
Loading…
Reference in a new issue