mirror of
https://github.com/fromchat-messenger/web.git
synced 2026-09-22 19:15:08 +03:00
Add a dedicated TextField component
This commit is contained in:
@@ -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");
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user