refactor(gui): Update MUI to v7 (#383)

* task(gui): update to mui v5

* task(gui): use sx prop instead of system props

* task(gui): update to mui v6 and replace makeStyles with sx prop

* task(gui): update to mui v7

* task(gui): update react

* fix(gui): fix import

* task(gui): adjust theme and few components to fix migration introduced styling errors

* fix(gui): animation issues with text field animations

* fix(gui): remove 'darker' theme and make 'dark' theme the default

- with the new update 'dark' theme is already quite dark and therefore a 'darker' theme not necessary
- the default theme is set to 'dark' now in settings initialization

* feat(tooling): Upgrade dprint to 0.50.0, eslint config, prettier, justfile commands

- Upgrade dprint to 0.50.0
- Use sane default eslint config (fairly permissive)
- `dprint fmt` now runs prettier for the `src-gui` folder
- Added `check_gui_eslint`, `check_gui_tsc` and `check_gui` commands

* refactor: fix a few eslint errors

* dprint fmt

* fix tsc complains

* nitpick: small spacing issue

---------

Co-authored-by: Binarybaron <binarybaron@protonmail.com>
Co-authored-by: Mohan <86064887+binarybaron@users.noreply.github.com>
This commit is contained in:
b-enedict 2025-06-06 22:31:33 +02:00 committed by GitHub
parent 2ba69ba340
commit 430a22fbf6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
169 changed files with 12883 additions and 3950 deletions

View file

@ -1,5 +1,4 @@
import { TextField } from "@material-ui/core";
import { TextFieldProps } from "@material-ui/core/TextField/TextField";
import TextField, { TextFieldProps } from "@mui/material/TextField";
import { useEffect } from "react";
import { isTestnet } from "store/config";
import { isBtcAddressValid } from "utils/conversionUtils";

View file

@ -1,39 +1,45 @@
import { createContext, useContext, useState, ReactNode } from 'react'
import { createContext, useContext, useState, ReactNode } from "react";
interface CardSelectionContextType {
selectedValue: string
setSelectedValue: (value: string) => void
selectedValue: string;
setSelectedValue: (value: string) => void;
}
const CardSelectionContext = createContext<CardSelectionContextType | undefined>(undefined)
const CardSelectionContext = createContext<
CardSelectionContextType | undefined
>(undefined);
export function CardSelectionProvider({
children,
initialValue,
onChange
}: {
children: ReactNode
initialValue: string
onChange?: (value: string) => void
export function CardSelectionProvider({
children,
initialValue,
onChange,
}: {
children: ReactNode;
initialValue: string;
onChange?: (value: string) => void;
}) {
const [selectedValue, setSelectedValue] = useState(initialValue)
const [selectedValue, setSelectedValue] = useState(initialValue);
const handleValueChange = (value: string) => {
setSelectedValue(value)
onChange?.(value)
}
const handleValueChange = (value: string) => {
setSelectedValue(value);
onChange?.(value);
};
return (
<CardSelectionContext.Provider value={{ selectedValue, setSelectedValue: handleValueChange }}>
{children}
</CardSelectionContext.Provider>
)
return (
<CardSelectionContext.Provider
value={{ selectedValue, setSelectedValue: handleValueChange }}
>
{children}
</CardSelectionContext.Provider>
);
}
export function useCardSelection() {
const context = useContext(CardSelectionContext)
if (context === undefined) {
throw new Error('useCardSelection must be used within a CardSelectionProvider')
}
return context
}
const context = useContext(CardSelectionContext);
if (context === undefined) {
throw new Error(
"useCardSelection must be used within a CardSelectionProvider",
);
}
return context;
}

View file

@ -1,23 +1,30 @@
import { Box } from '@material-ui/core'
import CheckIcon from '@material-ui/icons/Check'
import { CardSelectionProvider } from './CardSelectionContext'
import { Box } from "@mui/material";
import CheckIcon from "@mui/icons-material/Check";
import { CardSelectionProvider } from "./CardSelectionContext";
interface CardSelectionGroupProps {
children: React.ReactElement<{ value: string }>[]
value: string
onChange: (value: string) => void
children: React.ReactElement<{ value: string }>[];
value: string;
onChange: (value: string) => void;
}
export default function CardSelectionGroup({
children,
value,
onChange,
children,
value,
onChange,
}: CardSelectionGroupProps) {
return (
<CardSelectionProvider initialValue={value} onChange={onChange}>
<Box style={{ display: 'flex', flexDirection: 'column', gap: 12, marginTop: 12 }}>
{children}
</Box>
</CardSelectionProvider>
)
return (
<CardSelectionProvider initialValue={value} onChange={onChange}>
<Box
style={{
display: "flex",
flexDirection: "column",
gap: 12,
marginTop: 12,
}}
>
{children}
</Box>
</CardSelectionProvider>
);
}

View file

@ -1,53 +1,65 @@
import { Box } from "@material-ui/core";
import CheckIcon from '@material-ui/icons/Check'
import { useCardSelection } from './CardSelectionContext'
import { Box } from "@mui/material";
import CheckIcon from "@mui/icons-material/Check";
import { useCardSelection } from "./CardSelectionContext";
// The value prop is used by the parent CardSelectionGroup to determine which option is selected
export default function CardSelectionOption({children, value}: {children: React.ReactNode, value: string}) {
const { selectedValue, setSelectedValue } = useCardSelection()
const selected = value === selectedValue
export default function CardSelectionOption({
children,
value,
}: {
children: React.ReactNode;
value: string;
}) {
const { selectedValue, setSelectedValue } = useCardSelection();
const selected = value === selectedValue;
return (
<Box
onClick={() => setSelectedValue(value)}
return (
<Box
onClick={() => setSelectedValue(value)}
style={{
display: "flex",
alignItems: "flex-start",
gap: 16,
border: selected ? "2px solid #FF5C1B" : "2px solid #555",
borderRadius: 16,
padding: "1em",
cursor: "pointer",
transition: "all 0.2s ease-in-out",
}}
>
<Box
style={{
border: selected ? "2px solid #FF5C1B" : "2px solid #555",
borderRadius: 99999,
width: 28,
height: 28,
background: selected ? "#FF5C1B" : "transparent",
overflow: "hidden",
display: "flex",
alignItems: "center",
justifyContent: "center",
transition: "all 0.2s ease-in-out",
transform: selected ? "scale(1.1)" : "scale(1)",
flexShrink: 0,
}}
>
{selected ? (
<CheckIcon
style={{
display: 'flex',
alignItems: 'flex-start',
gap: 16,
border: selected ? '2px solid #FF5C1B' : '2px solid #555',
borderRadius: 16,
padding: '1em',
cursor: 'pointer',
transition: 'all 0.2s ease-in-out',
transition: "all 0.2s ease-in-out",
transform: "scale(1)",
animation: "checkIn 0.2s ease-in-out",
}}
>
<Box
style={{
border: selected ? '2px solid #FF5C1B' : '2px solid #555',
borderRadius: 99999,
width: 28,
height: 28,
background: selected ? '#FF5C1B' : 'transparent',
overflow: 'hidden',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
transition: 'all 0.2s ease-in-out',
transform: selected ? 'scale(1.1)' : 'scale(1)',
flexShrink: 0,
}}
>
{selected ? (
<CheckIcon
style={{
transition: 'all 0.2s ease-in-out',
transform: 'scale(1)',
animation: 'checkIn 0.2s ease-in-out'
}}
/>
) : null}
</Box>
<Box pt={0.5}>{children}</Box>
</Box>
)
}
/>
) : null}
</Box>
<Box
sx={{
pt: 0.5,
}}
>
{children}
</Box>
</Box>
);
}

View file

@ -1,18 +1,30 @@
import { Box, Button, Dialog, DialogActions, DialogContent, IconButton, List, ListItem, ListItemText, TextField } from "@material-ui/core";
import { TextFieldProps } from "@material-ui/core/TextField/TextField";
import {
Box,
Button,
Dialog,
DialogActions,
DialogContent,
IconButton,
List,
ListItemText,
TextField,
} from "@mui/material";
import { TextFieldProps } from "@mui/material";
import { useEffect, useState } from "react";
import { getMoneroAddresses } from "renderer/rpc";
import { isTestnet } from "store/config";
import { isXmrAddressValid } from "utils/conversionUtils";
import ImportContactsIcon from '@material-ui/icons/ImportContacts';
import ImportContactsIcon from "@mui/icons-material/ImportContacts";
import TruncatedText from "../other/TruncatedText";
import ListItemButton from "@mui/material/ListItemButton";
type MoneroAddressTextFieldProps = TextFieldProps & {
address: string;
onAddressChange: (address: string) => void;
onAddressValidityChange: (valid: boolean) => void;
helperText: string;
}
};
export default function MoneroAddressTextField({
address,
@ -59,12 +71,14 @@ export default function MoneroAddressTextField({
helperText={address.length > 0 ? errorText || helperText : helperText}
placeholder={placeholder}
variant="outlined"
InputProps={{
endAdornment: addresses?.length > 0 && (
<IconButton onClick={() => setShowDialog(true)} size="small">
<ImportContactsIcon />
</IconButton>
)
slotProps={{
input: {
endAdornment: addresses?.length > 0 && (
<IconButton onClick={() => setShowDialog(true)} size="small">
<ImportContactsIcon />
</IconButton>
),
},
}}
{...props}
/>
@ -90,26 +104,21 @@ function RecentlyUsedAddressesDialog({
open,
onClose,
addresses,
onAddressSelect
onAddressSelect,
}: RecentlyUsedAddressesDialogProps) {
return (
<Dialog
open={open}
onClose={onClose}
maxWidth="sm"
fullWidth
>
<Dialog open={open} onClose={onClose} maxWidth="sm" fullWidth>
<DialogContent>
<List>
{addresses.map((addr) => (
<ListItem
button
key={addr}
onClick={() => onAddressSelect(addr)}
>
<ListItemText
<ListItemButton key={addr} onClick={() => onAddressSelect(addr)}>
<ListItemText
primary={
<Box fontFamily="monospace">
<Box
sx={{
fontFamily: "monospace",
}}
>
<TruncatedText limit={40} truncateMiddle>
{addr}
</TruncatedText>
@ -117,16 +126,12 @@ function RecentlyUsedAddressesDialog({
}
secondary="Recently used as a redeem address"
/>
</ListItem>
</ListItemButton>
))}
</List>
</DialogContent>
<DialogActions>
<Button
onClick={onClose}
variant="contained"
color="primary"
>
<Button onClick={onClose} variant="contained" color="primary">
Close
</Button>
</DialogActions>