Compare commits

..

3 Commits

Author SHA1 Message Date
967c2f94f2 add toast login 2025-04-06 01:45:11 +08:00
b8b649e694 feat: add react render 2025-04-05 20:34:01 +08:00
c7763cddc3 fix: fixbug theme 2025-04-03 22:50:43 +08:00
7 changed files with 161 additions and 13 deletions

View File

@@ -15,10 +15,12 @@
"dependencies": { "dependencies": {
"@emotion/react": "^11.14.0", "@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.0", "@emotion/styled": "^11.14.0",
"@mui/material": "^6.4.7", "@mui/material": "^7.0.1",
"react": "19.0.0", "re-resizable": "^6.11.2",
"react-dom": "19.0.0", "react": "19.1.0",
"react-hook-form": "^7.54.2" "react-dom": "19.1.0",
"react-draggable": "^4.4.6",
"react-hook-form": "^7.55.0"
}, },
"exports": { "exports": {
".": "./src/index.tsx", ".": "./src/index.tsx",
@@ -26,7 +28,7 @@
}, },
"devDependencies": { "devDependencies": {
"clsx": "^2.1.1", "clsx": "^2.1.1",
"tailwind-merge": "^3.0.2" "tailwind-merge": "^3.1.0"
}, },
"publishConfig": { "publishConfig": {
"access": "public" "access": "public"

View File

@@ -1,4 +1,4 @@
import MuiButton, { ButtonProps } from '@mui/material/Button'; import { Button as MuiButton, ButtonProps } from '@mui/material';
export const Button = (props: ButtonProps) => { export const Button = (props: ButtonProps) => {
return <MuiButton {...props} />; return <MuiButton {...props} />;
@@ -7,7 +7,7 @@ export const Button = (props: ButtonProps) => {
export const IconButton = (props: ButtonProps) => { export const IconButton = (props: ButtonProps) => {
const { variant = 'contained', color = 'primary', sx, children, ...rest } = props; const { variant = 'contained', color = 'primary', sx, children, ...rest } = props;
return ( return (
<MuiButton variant={variant} color={color} {...rest} sx={{ color: 'white', minWidth: '32px', padding: '8px', ...sx }}> <MuiButton variant={variant} color={color} {...rest} sx={{ color: 'white', minWidth: '24px', padding: '8px', ...sx }}>
{children} {children}
</MuiButton> </MuiButton>
); );
@@ -16,8 +16,8 @@ export const IconButton = (props: ButtonProps) => {
export const IconButtonItem = (props: ButtonProps) => { export const IconButtonItem = (props: ButtonProps) => {
const { variant = 'contained', size = 'small', color = 'primary', sx, children, ...rest } = props; const { variant = 'contained', size = 'small', color = 'primary', sx, children, ...rest } = props;
return ( return (
<MuiButton {...props} > <MuiButton {...props}>
{/* <MuiButton variant={'contained'} size={size} color={color} {...rest} sx={{ color: 'white', ...sx }}> */} {/* <MuiButton variant={'contained'} size={size} color={color} {...rest} sx={{ color: 'white', ...sx }}> */}
{children} {children}
</MuiButton> </MuiButton>

65
src/drag-modal/index.tsx Normal file
View File

@@ -0,0 +1,65 @@
import { useRef } from 'react';
import Draggable from 'react-draggable';
import { clsxMerge } from '../clsx';
import { Resizable } from 're-resizable';
type DragModalProps = {
title?: React.ReactNode;
content?: React.ReactNode;
onClose?: () => void;
containerClassName?: string;
handleClassName?: string;
contentClassName?: string;
/**
* 默认大小, 单位为px
* width: defaultSize.width || 320
* height: defaultSize.height || 400
*/
defaultSize?: {
width: number;
height: number;
};
style?: React.CSSProperties;
};
export const DragModal = (props: DragModalProps) => {
const dragRef = useRef<HTMLDivElement>(null);
return (
<Draggable
nodeRef={dragRef as any}
onStop={(e, data) => {
console.log(e, data);
}}
handle='.handle'
grid={[1, 1]}
scale={1}
bounds='parent'
defaultPosition={{
x: 0,
y: 0,
}}>
<div
className={clsxMerge('absolute top-0 left-0 bg-white rounded-md border border-gray-200 shadow-sm', props.containerClassName)}
ref={dragRef}
style={props.style}>
<div className={clsxMerge('handle cursor-move border-b border-gray-200 py-2 px-4', props.handleClassName)}>{props.title || 'Move'}</div>
<Resizable
className={clsxMerge('', props.contentClassName)}
defaultSize={{
width: props.defaultSize?.width || 600,
height: props.defaultSize?.height || 400,
}}
onResizeStop={(e, direction, ref, d) => {
// console.log(e, direction, ref, d);
}}
enable={{
bottom: true,
right: true,
bottomRight: true,
}}>
{props.content}
</Resizable>
</div>
</Draggable>
);
};

View File

@@ -0,0 +1,40 @@
import React from 'react';
import { createRoot } from 'react-dom/client';
export class ReactRenderer {
component: any;
element: HTMLElement;
ref: React.RefObject<any>;
props: any;
root: any;
constructor(component: any, { props }: any) {
this.component = component;
this.element = document.createElement('div');
this.ref = React.createRef();
this.props = {
...props,
ref: this.ref,
};
this.root = createRoot(this.element);
this.render();
}
updateProps(props: any) {
this.props = {
...this.props,
...props,
};
this.render();
}
render() {
this.root.render(React.createElement(this.component, this.props));
}
destroy() {
this.root.unmount();
}
}
export default ReactRenderer;

View File

@@ -7,7 +7,6 @@ type SelectProps = {
export const Select = React.forwardRef((props: SelectProps, ref) => { export const Select = React.forwardRef((props: SelectProps, ref) => {
const { options, ...rest } = props; const { options, ...rest } = props;
console.log(props, 'props');
return ( return (
<MuiSelect {...rest} ref={ref}> <MuiSelect {...rest} ref={ref}>
{options?.map((option) => ( {options?.map((option) => (

View File

@@ -1,7 +1,7 @@
import { createTheme, Shadows, ThemeOptions } from '@mui/material/styles'; import { createTheme, Shadows, ThemeOptions } from '@mui/material';
import { useTheme as useMuiTheme, Theme } from '@mui/material/styles'; import { useTheme as useMuiTheme, Theme } from '@mui/material';
import { amber, red } from '@mui/material/colors'; import { amber, red } from '@mui/material/colors';
import { ThemeProvider } from '@mui/material/styles'; import { ThemeProvider } from '@mui/material';
const generateShadows = (color: string): Shadows => { const generateShadows = (color: string): Shadows => {
return [ return [
'none', 'none',

42
src/toast/ToastLogin.tsx Normal file
View File

@@ -0,0 +1,42 @@
import { toast } from 'react-toastify';
import { useTranslation } from 'react-i18next';
// Custom message component
const LoginMessage = (props: ToastLoginProps) => {
const { t } = useTranslation();
const handleClick = () => {
const currentUrl = window.location.href;
const redirect = encodeURIComponent(props?.redirectUrl || currentUrl);
const loginUrl = props?.loginUrl || '/user/login/';
const newUrl = location.origin + loginUrl + '?redirect=' + redirect;
window.open(newUrl, '_self');
};
return (
<div className='msg-container' onClick={handleClick} style={{ cursor: 'pointer' }}>
<p className='msg-title'>{t('Please login')}</p>
<p className='msg-description'>{t('Click here to go to the login page.')}</p>
</div>
);
};
type ToastLoginProps = {
/**
* 登录页面地址, /user/login
*/
loginUrl?: string;
/**
* 登录成功后跳转的地址, 默认是当前页面
*/
redirectUrl?: string;
};
/**
* 登录提示
* @param props
* @example
* toastLogin({
* loginUrl: '/user/login/',
* redirectUrl: window.location.href,
* });
*/
export const toastLogin = (props: ToastLoginProps = {}) => {
toast.info(<LoginMessage {...props} />);
};