Add a dedicated TextField component

This commit is contained in:
2025-09-05 21:04:45 +03:00
Unverified
parent 0cd76af33e
commit 420bad2405
10 changed files with 38 additions and 31 deletions
+1
View File
@@ -11,3 +11,4 @@ When working with this project, follow these rules:
- To typecheck, run "npm run frontend:typecheck".
- To build, run "npm run frontend:build".
- Do NOT "cd" to the project directory.
@@ -1,6 +1,6 @@
import { useState, useEffect } from "react";
import type { Message } from "../../../core/types";
import { MaterialDialog } from "../Dialog";
import { MaterialDialog } from "../core/Dialog";
interface EditMessageDialogProps {
isOpen: boolean;
@@ -1,6 +1,7 @@
import { useState, useEffect } from "react";
import type { Message } from "../../../core/types";
import { MaterialDialog } from "../Dialog";
import { MaterialDialog } from "../core/Dialog";
import { MaterialTextField } from "../core/TextField";
interface ReplyMessageDialogProps {
isOpen: boolean;
@@ -42,14 +43,13 @@ export function ReplyMessageDialog({ isOpen, onOpenChange, replyToMessage, onSen
<span className="reply-text">{replyToMessage.content}</span>
</div>
</div>
<mdui-text-field
<MaterialTextField
value={replyContent}
onInput={(e) => setReplyContent((e.target as HTMLInputElement).value)}
label="Reply"
variant="outlined"
placeholder="Type your reply..."
maxlength={1000}>
</mdui-text-field>
maxlength={1000} />
<div className="dialog-actions">
<mdui-button onClick={handleCancel} variant="outlined">Cancel</mdui-button>
<mdui-button onClick={handleSendReply}>Send Reply</mdui-button>
@@ -1,6 +1,6 @@
import type { DialogProps } from "../../../core/types";
import type { UserProfile } from "../../../core/types";
import { MaterialDialog } from "../Dialog";
import { MaterialDialog } from "../core/Dialog";
import { formatTime } from "../../../utils/utils";
import defaultAvatar from "../../../resources/images/default-avatar.png";
@@ -1,7 +1,7 @@
import type { Dialog as MduiDialog } from "mdui/components/dialog";
import React, { useEffect, useRef } from "react"
import { createPortal } from "react-dom";
import { id } from "../../utils/utils";
import { id } from "../../../utils/utils";
export interface BaseDialogProps {
onOpenChange: (value: boolean) => void;
@@ -0,0 +1,9 @@
import type { TextField } from "mdui/components/text-field";
type TextFieldProps = React.ComponentPropsWithoutRef<"mdui-text-field">
export function MaterialTextField(props: TextFieldProps & { ref?: React.Ref<TextField> }) {
return <mdui-text-field
autocomplete="off"
{...(props as TextFieldProps & { ref?: React.Ref<HTMLElement> })} />
}
@@ -2,9 +2,10 @@ import { useState, useEffect, useRef, type FormEvent } from "react";
import defaultAvatar from "../../../resources/images/default-avatar.png";
import type { TextField } from "mdui/components/text-field";
import type { DialogProps } from "../../../core/types";
import { MaterialDialog } from "../Dialog";
import { MaterialDialog } from "../core/Dialog";
import { useProfile } from "../../hooks/useProfile";
import { ImageCropper } from "./ImageCropper";
import { MaterialTextField } from "../core/TextField";
export function ProfileDialog({ isOpen, onOpenChange }: DialogProps) {
const { profileData, isLoading, isUpdating, updateProfileData, uploadProfilePictureData } = useProfile();
@@ -109,19 +110,18 @@ export function ProfileDialog({ isOpen, onOpenChange }: DialogProps) {
onChange={handleImageSelect}
/>
</div>
<mdui-text-field
<MaterialTextField
id="username-field"
label="Имя пользователя"
variant="outlined"
value={username}
onChange={(e: FormEvent<HTMLElement & TextField>) => setUsername((e.target as TextField).value)}
autocomplete="username"
disabled={isLoading || isUpdating}
/>
disabled={isLoading || isUpdating} />
</div>
<form id="profile-form" onSubmit={handleSubmit}>
<mdui-text-field
<MaterialTextField
id="description-field"
label="О себе"
variant="outlined"
@@ -129,8 +129,7 @@ export function ProfileDialog({ isOpen, onOpenChange }: DialogProps) {
onChange={(e: FormEvent<HTMLElement & TextField>) => setDescription((e.target as TextField).value)}
placeholder="Расскажите о себе..."
autocomplete="none"
disabled={isLoading || isUpdating}
/>
disabled={isLoading || isUpdating} />
<div className="dialog-actions">
<mdui-button
type="submit"
@@ -1,7 +1,7 @@
import { useState } from "react";
import { PRODUCT_NAME } from "../../../core/config";
import type { DialogProps } from "../../../core/types";
import { MaterialDialog } from "../Dialog";
import { MaterialDialog } from "../core/Dialog";
export function SettingsDialog({ isOpen, onOpenChange }: DialogProps) {
const [activePanel, setActivePanel] = useState("notifications-settings");
+6 -6
View File
@@ -8,6 +8,7 @@ import { API_BASE_URL } from "../../core/config";
import { useRef } from "react";
import type { TextField } from "mdui/components/text-field";
import { useAppState } from "../state";
import { MaterialTextField } from "../components/core/TextField";
export default function LoginScreen() {
const [alerts, updateAlerts] = useImmer<Alert[]>([]);
@@ -75,7 +76,7 @@ export default function LoginScreen() {
showAlert("danger", "Ошибка соединения с сервером");
}
}}>
<mdui-text-field
<MaterialTextField
label="Имя пользователя"
id="login-username"
name="username"
@@ -83,9 +84,9 @@ export default function LoginScreen() {
icon="person--filled"
autocomplete="username"
required
ref={usernameElement as React.RefObject<HTMLElement & TextField>}>
</mdui-text-field>
<mdui-text-field
ref={usernameElement} />
<MaterialTextField
label="Пароль"
id="login-password"
name="password"
@@ -95,8 +96,7 @@ export default function LoginScreen() {
icon="password--filled"
autocomplete="current-password"
required
ref={passwordElement as React.RefObject<HTMLElement & TextField>}>
</mdui-text-field>
ref={passwordElement} />
<mdui-button type="submit">Войти</mdui-button>
</form>
+7 -9
View File
@@ -8,6 +8,7 @@ import type { ErrorResponse, RegisterRequest } from "../../core/types";
import { API_BASE_URL } from "../../core/config";
import { delay } from "../../utils/utils";
import { useAppState } from "../state";
import { MaterialTextField } from "../components/core/TextField";
export default function RegisterScreen() {
const [alerts, updateAlerts] = useImmer<Alert[]>([]);
@@ -82,7 +83,7 @@ export default function RegisterScreen() {
showAlert("danger", "Ошибка соединения с сервером");
}
}}>
<mdui-text-field
<MaterialTextField
label="Имя пользователя"
id="register-username"
name="username"
@@ -92,9 +93,8 @@ export default function RegisterScreen() {
maxlength={20}
counter
required
ref={usernameElement as React.RefObject<HTMLElement & TextField>}>
</mdui-text-field>
<mdui-text-field
ref={usernameElement} />
<MaterialTextField
label="Пароль"
id="register-password"
name="password"
@@ -104,9 +104,8 @@ export default function RegisterScreen() {
icon="password--filled"
autocomplete="new-password"
required
ref={passwordElement as React.RefObject<HTMLElement & TextField>}>
</mdui-text-field>
<mdui-text-field
ref={passwordElement} />
<MaterialTextField
label="Подтвердите пароль"
id="register-confirm-password"
name="confirm_password"
@@ -116,8 +115,7 @@ export default function RegisterScreen() {
icon="password--filled"
autocomplete="new-password"
required
ref={confirmPasswordElement as React.RefObject<HTMLElement & TextField>}>
</mdui-text-field>
ref={confirmPasswordElement} />
<mdui-button type="submit">Зарегистрироваться</mdui-button>
</form>