Migrate to Mantine v8 and Design Changes (#961)

* mantine v8 migration

* various design changes and improvements
This commit is contained in:
Jeff
2025-06-24 00:04:36 -07:00
committed by GitHub
parent bea55d48a8
commit c1330d92b2
473 changed files with 12469 additions and 11607 deletions
@@ -0,0 +1,156 @@
.root {
font-weight: 500;
border: 1px solid transparent;
transition:
background-color 0.2s ease-in-out,
border-color 0.2s ease-in-out;
&[data-disabled='true'] {
opacity: 0.6;
}
&[data-variant='default'] {
color: var(--theme-colors-foreground);
background-color: var(--theme-colors-surface);
&:hover {
background: lighten(var(--theme-colors-surface), 5%);
}
&:focus-visible {
background: lighten(var(--theme-colors-surface), 10%);
}
}
&[data-variant='outline'] {
--button-border: var(--theme-colors-border);
color: var(--theme-colors-foreground);
border: 1px solid var(--theme-colors-border);
&:hover {
border: 1px solid lighten(var(--theme-colors-border), 10%);
}
&:focus-visible {
border: 1px solid lighten(var(--theme-colors-border), 10%);
}
}
&[data-variant='filled'] {
color: var(--theme-colors-primary-contrast);
background: var(--theme-colors-primary-filled);
border: 1px solid transparent;
transition: background-color 0.2s ease-in-out;
&:hover,
&:focus-visible {
background: darken(var(--theme-colors-primary-filled), 10%);
}
}
&[data-variant='state-error'] {
background: var(--theme-colors-state-error);
&:hover,
&:focus-visible {
background: darken(var(--theme-colors-state-error), 10%);
}
}
&[data-variant='state-info'] {
background: var(--theme-colors-state-info);
&:hover,
&:focus-visible {
background: darken(var(--theme-colors-state-info), 10%);
}
}
&[data-variant='state-success'] {
background: var(--theme-colors-state-success);
&:hover,
&:focus-visible {
background: darken(var(--theme-colors-state-success), 10%);
}
}
&[data-variant='state-warning'] {
background: var(--theme-colors-state-warning);
&:hover,
&:focus-visible {
background: darken(var(--theme-colors-state-warning), 10%);
}
}
&[data-variant='subtle'] {
color: var(--theme-colors-foreground);
background: transparent;
&:hover,
&:active,
&:focus-visible {
background-color: lighten(var(--button-bg), 10%);
}
}
&[data-variant='secondary'] {
border: 1px solid transparent;
&:hover {
background-color: darken(var(--button-bg), 5%);
}
&:focus-visible {
background-color: darken(var(--button-bg), 10%);
}
}
&[data-variant='transparent'] {
color: var(--theme-colors-foreground);
border: 1px solid transparent;
transition: color 0.2s ease-in-out;
&:hover {
background-color: transparent;
@mixin dark {
color: lighten(var(--theme-colors-foreground), 10%);
}
@mixin light {
color: darken(var(--theme-colors-foreground), 10%);
}
}
&:focus-visible {
border: 1px solid lighten(var(--theme-colors-border), 10%);
}
}
}
.loader {
display: none;
}
.section {
display: flex;
margin-inline-end: var(--theme-spacing-sm);
}
.button-inner.loading {
color: transparent;
}
.spinner {
position: absolute;
top: 50%;
left: 50%;
transform: translate3d(-50%, -50%, 0);
}
.uppercase {
text-transform: uppercase;
}
+155
View File
@@ -0,0 +1,155 @@
import type { ButtonVariant, ButtonProps as MantineButtonProps } from '@mantine/core';
import { ElementProps, Button as MantineButton } from '@mantine/core';
import { useTimeout } from '@mantine/hooks';
import clsx from 'clsx';
import { forwardRef, useCallback, useRef, useState } from 'react';
import styles from './button.module.css';
import { Spinner } from '/@/shared/components/spinner/spinner';
import { Tooltip, TooltipProps } from '/@/shared/components/tooltip/tooltip';
import { createPolymorphicComponent } from '/@/shared/utils/create-polymorphic-component';
export interface ButtonProps
extends ElementProps<'button', keyof MantineButtonProps>,
MantineButtonProps,
MantineButtonProps {
tooltip?: Omit<TooltipProps, 'children'>;
uppercase?: boolean;
variant?: ExtendedButtonVariant;
}
type ExtendedButtonVariant =
| 'state-error'
| 'state-info'
| 'state-success'
| 'state-warning'
| ButtonVariant;
export const _Button = forwardRef<HTMLButtonElement, ButtonProps>(
(
{
children,
classNames,
loading,
size = 'sm',
style,
tooltip,
uppercase,
variant = 'default',
...props
}: ButtonProps,
ref,
) => {
if (tooltip) {
return (
<Tooltip
withinPortal
{...tooltip}
>
<MantineButton
autoContrast
classNames={{
label: clsx(styles.label, {
[styles.uppercase]: uppercase,
}),
loader: styles.loader,
root: styles.root,
section: styles.section,
...classNames,
}}
ref={ref}
size={size}
style={style}
variant={variant}
{...props}
>
{children}
{loading && (
<div className={styles.spinner}>
<Spinner />
</div>
)}
</MantineButton>
</Tooltip>
);
}
return (
<MantineButton
classNames={{
label: clsx(styles.label, {
[styles.uppercase]: uppercase,
}),
loader: styles.loader,
root: styles.root,
section: styles.section,
...classNames,
}}
ref={ref}
size={size}
style={style}
variant={variant}
{...props}
>
{children}
{loading && (
<div className={styles.spinner}>
<Spinner />
</div>
)}
</MantineButton>
);
},
);
export const Button = createPolymorphicComponent<'button', ButtonProps>(_Button);
interface TimeoutButtonProps extends ButtonProps {
timeoutProps: {
callback: () => void;
duration: number;
};
}
export const TimeoutButton = ({ timeoutProps, ...props }: TimeoutButtonProps) => {
const [, setTimeoutRemaining] = useState(timeoutProps.duration);
const [isRunning, setIsRunning] = useState(false);
const intervalRef = useRef(0);
const callback = () => {
timeoutProps.callback();
setTimeoutRemaining(timeoutProps.duration);
clearInterval(intervalRef.current);
setIsRunning(false);
};
const { clear, start } = useTimeout(callback, timeoutProps.duration);
const startTimeout = useCallback(() => {
if (isRunning) {
clearInterval(intervalRef.current);
setIsRunning(false);
clear();
} else {
setIsRunning(true);
start();
const intervalId = window.setInterval(() => {
setTimeoutRemaining((prev) => prev - 100);
}, 100);
intervalRef.current = intervalId;
}
}, [clear, isRunning, start]);
return (
<Button
onClick={startTimeout}
{...props}
>
{isRunning ? 'Cancel' : props.children}
</Button>
);
};