feat: support context menu and draggable button (#844)
Co-authored-by: sealday <sealday@gmail.com> Reviewed-on: daoyoucloud/tachybase#844
This commit is contained in:
parent
9f215c76e8
commit
1816660c14
@ -26,6 +26,7 @@
|
||||
"@vitejs/plugin-react": "^4.0.0",
|
||||
"chalk": "2.4.2",
|
||||
"esbuild-register": "^3.4.2",
|
||||
"sass": "^1.75.0",
|
||||
"execa": "^5.1.1",
|
||||
"fast-glob": "^3.3.1",
|
||||
"fs-extra": "^11.1.1",
|
||||
|
@ -27,6 +27,7 @@
|
||||
"fs-extra": "^11.1.1",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"lodash": "4.17.21",
|
||||
"react-transition-group": "^4.4.5",
|
||||
"path-to-regexp": "^6.1.0",
|
||||
"qrcode": "^1.5.1",
|
||||
"qrcode.react": "^3.1.0",
|
||||
|
@ -0,0 +1,14 @@
|
||||
import React from 'react';
|
||||
import CSSTransition from 'react-transition-group/CSSTransition';
|
||||
|
||||
const AnimateComponent = ({ children, isVisible, timeout, className }) => {
|
||||
const nodeRef = React.useRef(null);
|
||||
|
||||
return (
|
||||
<CSSTransition nodeRef={nodeRef} in={isVisible} timeout={timeout} classNames={className} unmountOnExit>
|
||||
{children}
|
||||
</CSSTransition>
|
||||
);
|
||||
};
|
||||
|
||||
export default AnimateComponent;
|
@ -0,0 +1,166 @@
|
||||
import React, { useRef, useEffect, useState, useCallback } from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import classnames from 'classnames';
|
||||
import { registerEvent, callHideEvent } from './registerEvent';
|
||||
import AnimateComponent from './animateComponent';
|
||||
import { throttle } from './helper';
|
||||
|
||||
function ContextMenu({
|
||||
children,
|
||||
id,
|
||||
appendTo,
|
||||
hideOnLeave,
|
||||
onMouseLeave,
|
||||
onHide,
|
||||
onShow,
|
||||
preventHideOnScroll,
|
||||
preventHideOnResize,
|
||||
attributes,
|
||||
className,
|
||||
animation,
|
||||
}) {
|
||||
const contextMenuEl = useRef(null);
|
||||
const [isVisible, setVisible] = useState(false);
|
||||
const [clientPosition, setClientPosition] = useState(null);
|
||||
|
||||
const showMenu = (e) => {
|
||||
const { position } = e;
|
||||
|
||||
setVisible(true);
|
||||
setClientPosition(position);
|
||||
};
|
||||
|
||||
const hideMenu = () => {
|
||||
setVisible(false);
|
||||
if (onHide) onHide();
|
||||
};
|
||||
|
||||
const handleMouseLeave = useCallback((e) => {
|
||||
e.preventDefault();
|
||||
|
||||
onMouseLeave(e);
|
||||
|
||||
if (hideOnLeave) callHideEvent(id);
|
||||
});
|
||||
|
||||
const clickOutsideCallback = (event) => {
|
||||
if (contextMenuEl.current && !contextMenuEl.current.contains(event.target)) {
|
||||
callHideEvent(id);
|
||||
}
|
||||
};
|
||||
|
||||
const contextMenuCallback = (event) => {
|
||||
let targetElement = event.target;
|
||||
|
||||
do {
|
||||
if (targetElement.classList && targetElement.classList.contains('menu-trigger')) {
|
||||
return;
|
||||
}
|
||||
targetElement = targetElement.parentNode;
|
||||
} while (targetElement);
|
||||
|
||||
callHideEvent(id);
|
||||
};
|
||||
|
||||
const onScrollHideCallback = throttle(() => {
|
||||
callHideEvent(id);
|
||||
}, 200);
|
||||
|
||||
const onResizeHideCallback = throttle(() => {
|
||||
callHideEvent(id);
|
||||
}, 200);
|
||||
|
||||
useEffect(() => {
|
||||
registerEvent(id, showMenu, hideMenu);
|
||||
|
||||
// detect click outside
|
||||
document.addEventListener('mousedown', clickOutsideCallback);
|
||||
|
||||
// detect right click outside
|
||||
document.addEventListener('contextmenu', contextMenuCallback);
|
||||
|
||||
// on scroll hide handled
|
||||
if (!preventHideOnScroll) {
|
||||
window.addEventListener('scroll', onScrollHideCallback);
|
||||
}
|
||||
|
||||
// on resize hide handled
|
||||
if (!preventHideOnResize) {
|
||||
window.addEventListener('resize', onResizeHideCallback);
|
||||
}
|
||||
|
||||
return () => {
|
||||
document.removeEventListener('mousedown', clickOutsideCallback);
|
||||
document.removeEventListener('contextmenu', contextMenuCallback);
|
||||
window.removeEventListener('scroll', onScrollHideCallback);
|
||||
window.removeEventListener('resize', onResizeHideCallback);
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (isVisible) {
|
||||
const { clientY, clientX } = clientPosition;
|
||||
const { innerHeight: windowInnerHeight, innerWidth: windowInnerWidth } = window;
|
||||
const { offsetHeight: elemHeight, offsetWidth: elemWidth } = contextMenuEl.current;
|
||||
|
||||
let newClientY = clientY;
|
||||
let newClientX = clientX;
|
||||
|
||||
if (windowInnerHeight < clientY + elemHeight) newClientY = clientY - elemHeight;
|
||||
if (windowInnerWidth < clientX + elemWidth) newClientX = clientX - elemWidth;
|
||||
|
||||
contextMenuEl.current.style.top = `${newClientY + 2}px`;
|
||||
contextMenuEl.current.style.left = `${newClientX + 2}px`;
|
||||
|
||||
if (onShow) onShow();
|
||||
}
|
||||
}, [isVisible, clientPosition]);
|
||||
|
||||
const childrenWithProps = React.Children.map(children, (child) => React.cloneElement(child, { id }));
|
||||
|
||||
const ContextComponent = () => (
|
||||
<div
|
||||
className={classnames('contextmenu', ...className.split(' '))}
|
||||
ref={contextMenuEl}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
{...attributes}
|
||||
>
|
||||
{childrenWithProps}
|
||||
</div>
|
||||
);
|
||||
|
||||
const PortalContextComponent = () => ReactDOM.createPortal(<ContextComponent />, document.querySelector(appendTo));
|
||||
|
||||
if (document.readyState === 'complete' && appendTo) {
|
||||
return animation ? (
|
||||
<AnimateComponent isVisible={isVisible} timeout={200} className={animation}>
|
||||
<PortalContextComponent />
|
||||
</AnimateComponent>
|
||||
) : (
|
||||
<PortalContextComponent />
|
||||
);
|
||||
}
|
||||
|
||||
return animation ? (
|
||||
<AnimateComponent isVisible={isVisible} timeout={200} className={animation}>
|
||||
<ContextComponent />
|
||||
</AnimateComponent>
|
||||
) : (
|
||||
<ContextComponent />
|
||||
);
|
||||
}
|
||||
|
||||
export default ContextMenu;
|
||||
|
||||
ContextMenu.defaultProps = {
|
||||
appendTo: null,
|
||||
hideOnLeave: false,
|
||||
preventHideOnResize: false,
|
||||
preventHideOnScroll: false,
|
||||
attributes: {},
|
||||
className: '',
|
||||
animation: 'fade',
|
||||
onMouseLeave: () => null,
|
||||
onHide: () => null,
|
||||
onShow: () => null,
|
||||
};
|
@ -0,0 +1,42 @@
|
||||
import React, { useCallback, useRef } from 'react';
|
||||
import classnames from 'classnames';
|
||||
import { callHideEvent } from './registerEvent';
|
||||
|
||||
function ContextMenuItem({ children, onClick, disabled, preventClose, attributes, className }) {
|
||||
const contextMenuItem = useRef(null);
|
||||
|
||||
const handleClickEvent = useCallback((e) => {
|
||||
if (disabled) return;
|
||||
onClick(e);
|
||||
|
||||
if (!preventClose) callHideEvent('ID_NOT_REQUIRED');
|
||||
});
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classnames(
|
||||
'contextmenu__item',
|
||||
{
|
||||
'contextmenu__item--disabled': disabled,
|
||||
},
|
||||
...className.split(' '),
|
||||
)}
|
||||
onClick={handleClickEvent}
|
||||
{...attributes}
|
||||
ref={contextMenuItem}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default ContextMenuItem;
|
||||
|
||||
ContextMenuItem.defaultProps = {
|
||||
disabled: false,
|
||||
preventClose: false,
|
||||
attributes: {},
|
||||
className: '',
|
||||
onClick: () => null,
|
||||
onItemHover: () => null,
|
||||
};
|
@ -0,0 +1,49 @@
|
||||
import React, { useRef, useCallback } from 'react';
|
||||
import classnames from 'classnames';
|
||||
import { callShowEvent, callHideEvent } from './registerEvent';
|
||||
|
||||
function ContextMenuTrigger({ children, id, disableWhileShiftPressed, attributes, disable, className }) {
|
||||
const menuTrigger = useRef(null);
|
||||
|
||||
const handleContextMenu = useCallback((e) => {
|
||||
if (disable) return;
|
||||
if (disableWhileShiftPressed && e.nativeEvent.shiftKey) {
|
||||
callHideEvent(id);
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
const { clientX, clientY } = e.nativeEvent;
|
||||
const opts = {
|
||||
position: {
|
||||
clientY,
|
||||
clientX,
|
||||
},
|
||||
id,
|
||||
};
|
||||
|
||||
callShowEvent(opts);
|
||||
});
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classnames('menu-trigger', ...className.split(' '))}
|
||||
ref={menuTrigger}
|
||||
{...attributes}
|
||||
onContextMenu={(e) => handleContextMenu(e)}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default ContextMenuTrigger;
|
||||
|
||||
ContextMenuTrigger.defaultProps = {
|
||||
attributes: {},
|
||||
disable: false,
|
||||
renderTag: 'div',
|
||||
disableWhileShiftPressed: false,
|
||||
className: '',
|
||||
};
|
@ -0,0 +1,27 @@
|
||||
/* global arguments */
|
||||
|
||||
export const uniqueId = () => `_${Math.random().toString(36).substr(2, 9)}`;
|
||||
|
||||
export const throttle = (func, limit) => {
|
||||
let lastFunc;
|
||||
let lastRan;
|
||||
return () => {
|
||||
const context = window;
|
||||
const args = arguments;
|
||||
if (!lastRan) {
|
||||
func.apply(context, args);
|
||||
lastRan = Date.now();
|
||||
} else {
|
||||
clearTimeout(lastFunc);
|
||||
lastFunc = setTimeout(
|
||||
() => {
|
||||
if (Date.now() - lastRan >= limit) {
|
||||
func.apply(context, args);
|
||||
lastRan = Date.now();
|
||||
}
|
||||
},
|
||||
limit - (Date.now() - lastRan),
|
||||
);
|
||||
}
|
||||
};
|
||||
};
|
46
packages/plugins/@hera/plugin-core/src/client/components/context-menu/index.d.ts
vendored
Normal file
46
packages/plugins/@hera/plugin-core/src/client/components/context-menu/index.d.ts
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
import * as React from 'react';
|
||||
|
||||
export interface ContextMenu {
|
||||
id: string;
|
||||
appendTo?: string;
|
||||
animation?: string;
|
||||
hideOnLeave?: boolean;
|
||||
attributes?: object;
|
||||
className?: string;
|
||||
children?: ReactNode;
|
||||
preventHideOnResize?: boolean;
|
||||
preventHideOnScroll?: boolean;
|
||||
onShow?: { (event: any): void };
|
||||
onHide?: { (event: any): void };
|
||||
onMouseLeave?: { (event: any): void };
|
||||
}
|
||||
|
||||
export interface ContextMenuItem {
|
||||
disabled?: boolean;
|
||||
preventClose?: boolean;
|
||||
disableWhileShiftPressed?: boolean;
|
||||
attributes?: object;
|
||||
className?: string;
|
||||
children?: ReactNode;
|
||||
onClick?: { (event: any): void };
|
||||
}
|
||||
|
||||
export interface ContextMenuTrigger {
|
||||
id: string;
|
||||
attributes?: object;
|
||||
disable?: boolean;
|
||||
className?: string;
|
||||
children?: ReactNode;
|
||||
}
|
||||
|
||||
export interface Submenu {
|
||||
title: string;
|
||||
attributes?: object;
|
||||
className?: boolean;
|
||||
children?: ReactNode;
|
||||
}
|
||||
|
||||
export const ContextMenu: React.FunctionComponent<ContextMenu>;
|
||||
export const ContextMenuItem: React.FunctionComponent<ContextMenuItem>;
|
||||
export const ContextMenuTrigger: React.FunctionComponent<ContextMenuTrigger>;
|
||||
export const Submenu: React.FunctionComponent<Submenu>;
|
@ -0,0 +1,6 @@
|
||||
import './style.scss';
|
||||
|
||||
export { default as ContextMenu } from './contextMenu';
|
||||
export { default as ContextMenuItem } from './contextMenuItem';
|
||||
export { default as ContextMenuTrigger } from './contextMenuTrigger';
|
||||
export { default as Submenu } from './submenu';
|
@ -0,0 +1,36 @@
|
||||
import { uniqueId } from './helper';
|
||||
|
||||
const events = {};
|
||||
|
||||
let activeEvent = {};
|
||||
|
||||
const registerEvent = (id, showMenu, hideMenu) => {
|
||||
const _ = uniqueId();
|
||||
|
||||
events[_] = {
|
||||
id,
|
||||
showMenu,
|
||||
hideMenu,
|
||||
};
|
||||
|
||||
return id;
|
||||
};
|
||||
|
||||
const callShowEvent = (opts) => {
|
||||
if (activeEvent.hideMenu) activeEvent.hideMenu();
|
||||
Object.keys(events).forEach((key) => {
|
||||
if (events[key].id && events[key].id === opts.id) {
|
||||
events[key].showMenu(opts);
|
||||
activeEvent = events[key];
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const callHideEvent = (menuId) => {
|
||||
if (activeEvent.id === menuId || menuId === 'ID_NOT_REQUIRED') {
|
||||
if (activeEvent.hideMenu) activeEvent.hideMenu();
|
||||
activeEvent = {};
|
||||
}
|
||||
};
|
||||
|
||||
export { registerEvent, callShowEvent, callHideEvent };
|
@ -0,0 +1,175 @@
|
||||
.contextmenu {
|
||||
$contextmenu: '.contextmenu';
|
||||
|
||||
position: fixed;
|
||||
width: 200px;
|
||||
left: 0;
|
||||
top: calc(100% + 10px);
|
||||
border-radius: 4px;
|
||||
background-color: #fff;
|
||||
padding: 10px 0;
|
||||
z-index: 1001;
|
||||
box-shadow: 0 0 20px rgba(0, 0, 0, 0.2);
|
||||
&__item {
|
||||
$item: &;
|
||||
|
||||
font-size: 14px;
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
padding: 10px 15px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
transition: 0.2s;
|
||||
position: relative;
|
||||
margin-bottom: 2px;
|
||||
&:hover:not(#{$item}--disabled) {
|
||||
background-color: #f1f1f1;
|
||||
}
|
||||
&--disabled {
|
||||
opacity: 0.5;
|
||||
cursor: no-drop;
|
||||
}
|
||||
}
|
||||
.submenu {
|
||||
$submenu: '.submenu';
|
||||
|
||||
position: relative;
|
||||
&:hover {
|
||||
& > #{$contextmenu}__item {
|
||||
background-color: #f1f1f1;
|
||||
}
|
||||
}
|
||||
&__item {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 100%;
|
||||
width: 100%;
|
||||
border: solid 1px #ccc;
|
||||
background-color: #fff;
|
||||
border-radius: 4px;
|
||||
padding: 5px 0;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
}
|
||||
& > #{$contextmenu}__item {
|
||||
&:after {
|
||||
content: '';
|
||||
border-style: solid;
|
||||
border-width: 5px 8px;
|
||||
border-color: transparent transparent transparent #000;
|
||||
width: 0;
|
||||
height: 0;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
right: 0px;
|
||||
transition: 0.2s;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fade in animation start
|
||||
.fade-enter {
|
||||
opacity: 0;
|
||||
}
|
||||
.fade-enter-active {
|
||||
opacity: 1;
|
||||
transition: opacity 200ms;
|
||||
}
|
||||
.fade-exit {
|
||||
opacity: 1;
|
||||
}
|
||||
.fade-exit-active {
|
||||
opacity: 0;
|
||||
transition: opacity 200ms;
|
||||
}
|
||||
// fade in animation start
|
||||
|
||||
// zoom in animation start
|
||||
.zoom-enter {
|
||||
opacity: 0;
|
||||
transform: scale(0.8);
|
||||
transform-origin: top left;
|
||||
}
|
||||
.zoom-enter-active {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
transition: opacity 200ms, transform 200ms;
|
||||
transform-origin: top left;
|
||||
}
|
||||
.zoom-exit {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
transform-origin: top left;
|
||||
}
|
||||
.zoom-exit-active {
|
||||
opacity: 0;
|
||||
transform: scale(0.8);
|
||||
transition: opacity 200ms, transform 200ms;
|
||||
transform-origin: top left;
|
||||
}
|
||||
// zoom in animation start
|
||||
|
||||
// to top left animation start
|
||||
.toTopLeft-enter {
|
||||
opacity: 0;
|
||||
transform: translate(10px, 10px);
|
||||
}
|
||||
.toTopLeft-enter-active {
|
||||
opacity: 1;
|
||||
transform: translate(0px, 0px);
|
||||
transition: opacity 200ms, transform 200ms;
|
||||
}
|
||||
.toTopLeft-exit {
|
||||
opacity: 1;
|
||||
transform: translate(0px, 0px);
|
||||
}
|
||||
.toTopLeft-exit-active {
|
||||
opacity: 0;
|
||||
transform: translate(10px, 10px);
|
||||
transition: opacity 200ms, transform 200ms;
|
||||
}
|
||||
// to top left animation start
|
||||
|
||||
// right to left animation start
|
||||
.rightToLeft-enter {
|
||||
opacity: 0;
|
||||
transform: translateX(10px);
|
||||
}
|
||||
.rightToLeft-enter-active {
|
||||
opacity: 1;
|
||||
transform: translateX(0px);
|
||||
transition: opacity 200ms, transform 200ms;
|
||||
}
|
||||
.rightToLeft-exit {
|
||||
opacity: 1;
|
||||
transform: translateX(0px);
|
||||
}
|
||||
.rightToLeft-exit-active {
|
||||
opacity: 0;
|
||||
transform: translateX(10px);
|
||||
transition: opacity 200ms, transform 200ms;
|
||||
}
|
||||
// right to left animation start
|
||||
|
||||
// right to left animation start
|
||||
.pop-enter {
|
||||
opacity: 0;
|
||||
transform: scale(0.8);
|
||||
}
|
||||
.pop-enter-active {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
transition: opacity 200ms, transform 200ms;
|
||||
}
|
||||
.pop-exit {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
.pop-exit-active {
|
||||
opacity: 0;
|
||||
transform: scale(0.8);
|
||||
transition: opacity 200ms, transform 200ms;
|
||||
}
|
||||
// right to left animation start
|
@ -0,0 +1,74 @@
|
||||
import React, { useCallback, useState, useRef } from 'react';
|
||||
import classnames from 'classnames';
|
||||
import ContextMenuItem from './contextMenuItem';
|
||||
|
||||
function Submenu({ children, title, attributes, className }) {
|
||||
const [submenuStyle, setSubmenuStyle] = useState(null);
|
||||
const submenuEl = useRef(null);
|
||||
const submenuItem = useRef(null);
|
||||
|
||||
const calculateSubmenuPos = useCallback(() => {
|
||||
const { innerHeight: windowInnerHeight, innerWidth: windowInnerWidth } = window;
|
||||
const {
|
||||
left: itemLeft,
|
||||
top: itemTop,
|
||||
width: itemWidth,
|
||||
height: itemHeight,
|
||||
} = submenuItem.current.getBoundingClientRect();
|
||||
const { width: submenuWidth, height: submenuHeight } = submenuEl.current.getBoundingClientRect();
|
||||
let style = {
|
||||
opacity: 1,
|
||||
visibility: 'visible',
|
||||
};
|
||||
|
||||
if (itemTop + submenuHeight + itemHeight > windowInnerHeight) {
|
||||
style = {
|
||||
...style,
|
||||
top: 'inherit',
|
||||
bottom: '0',
|
||||
};
|
||||
}
|
||||
if (itemLeft + submenuWidth + itemWidth > windowInnerWidth) {
|
||||
style = {
|
||||
...style,
|
||||
left: 'inherit',
|
||||
right: '100%',
|
||||
};
|
||||
}
|
||||
|
||||
setSubmenuStyle(style);
|
||||
});
|
||||
|
||||
const hideSubmenu = useCallback(() => {
|
||||
const style = {
|
||||
opacity: 0,
|
||||
visibility: 'hidden',
|
||||
};
|
||||
|
||||
setSubmenuStyle(style);
|
||||
});
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classnames('submenu', ...className.split(' '))}
|
||||
onMouseOver={() => calculateSubmenuPos()}
|
||||
onMouseOut={() => hideSubmenu()}
|
||||
onFocus={() => null}
|
||||
onBlur={() => null}
|
||||
ref={submenuItem}
|
||||
{...attributes}
|
||||
>
|
||||
<ContextMenuItem>{title}</ContextMenuItem>
|
||||
<div className="submenu__item" ref={submenuEl} style={submenuStyle}>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Submenu;
|
||||
|
||||
Submenu.defaultProps = {
|
||||
title: 'Sub Menu',
|
||||
className: '',
|
||||
};
|
@ -1,9 +1,12 @@
|
||||
import { CalculatorOutlined, CommentOutlined, HighlightOutlined, ToolOutlined } from '@ant-design/icons';
|
||||
import { CalculatorOutlined, CommentOutlined, HighlightOutlined, ToolOutlined, ToolFilled } from '@ant-design/icons';
|
||||
import { useDesignable } from '@nocobase/client';
|
||||
import { FloatButton } from 'antd';
|
||||
import React from 'react';
|
||||
import { useContextMenu } from '../context-menu/useContextMenu';
|
||||
export const AssistantProvider = ({ children }) => {
|
||||
const { designable, setDesignable } = useDesignable();
|
||||
const { contextMenuEnabled, setContextMenuEnable } = useContextMenu();
|
||||
const ContextMenuIcon = contextMenuEnabled ? ToolFilled : ToolOutlined;
|
||||
return (
|
||||
<>
|
||||
{children}
|
||||
@ -11,6 +14,7 @@ export const AssistantProvider = ({ children }) => {
|
||||
<FloatButton icon={<HighlightOutlined />} onClick={() => setDesignable(!designable)} />
|
||||
<FloatButton icon={<CalculatorOutlined />} />
|
||||
<FloatButton icon={<CommentOutlined />} />
|
||||
<FloatButton icon={<ContextMenuIcon onClick={() => setContextMenuEnable(!contextMenuEnabled)} />} />
|
||||
</FloatButton.Group>
|
||||
</>
|
||||
);
|
||||
|
@ -0,0 +1,281 @@
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { css } from '@nocobase/client';
|
||||
import { ContextMenuTrigger } from '../../components/context-menu';
|
||||
import { ContextMenu } from '../../components/context-menu';
|
||||
import { ContextMenuItem } from '../../components/context-menu';
|
||||
import { ContextMenuContext } from './useContextMenu';
|
||||
|
||||
export const ContextMenuProvider = ({ children }) => {
|
||||
const [enable, setEnable] = useState(true);
|
||||
const [enableDragable, setEnableDragable] = useState(false);
|
||||
const ref = useRef<HTMLDivElement>();
|
||||
useEffect(() => {
|
||||
if (!ref.current) {
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* 摇杆配置
|
||||
*/
|
||||
const config = {
|
||||
/** 摇杆半径 */
|
||||
radius: 100,
|
||||
};
|
||||
|
||||
/**
|
||||
* 摇杆区域元素,摇杆只会渲染在该区域
|
||||
*/
|
||||
const ele = ref.current;
|
||||
|
||||
/** 是否正在按压 */
|
||||
let pressing = false;
|
||||
|
||||
/** 初始X坐标 */
|
||||
let prevX = 0;
|
||||
/** 初始Y坐标 */
|
||||
let prevY = 0;
|
||||
|
||||
/** 当前X坐标 */
|
||||
let newX = 0;
|
||||
/** 当前Y坐标 */
|
||||
let newY = 0;
|
||||
|
||||
/** 相对X坐标 */
|
||||
let relX = 0;
|
||||
/** 相对Y坐标 */
|
||||
let relY = 0;
|
||||
|
||||
/** 摇杆canvas移动后应在的X坐标 */
|
||||
let moveX = 0;
|
||||
/** 摇杆canvas移动后应在的Y坐标 */
|
||||
let moveY = 0;
|
||||
|
||||
/** 根据半径限制相对坐标后的X坐标 */
|
||||
let displayX = 0;
|
||||
/** 根据半径限制相对坐标后的Y坐标 */
|
||||
let displayY = 0;
|
||||
|
||||
ele.addEventListener('mousedown', down);
|
||||
ele.addEventListener('mousemove', move);
|
||||
ele.addEventListener('mouseup', up);
|
||||
|
||||
ele.addEventListener('touchstart', down);
|
||||
ele.addEventListener('touchmove', move);
|
||||
ele.addEventListener('touchend', up);
|
||||
|
||||
const stickEle = createStickCanvas();
|
||||
const baseEle = createBaseCanvas();
|
||||
|
||||
// ele.style.position = 'fixed';
|
||||
ele.appendChild(baseEle);
|
||||
baseEle.style.position = 'absolute';
|
||||
baseEle.style.visibility = 'hidden';
|
||||
ele.appendChild(stickEle);
|
||||
stickEle.style.position = 'absolute';
|
||||
stickEle.style.visibility = 'hidden';
|
||||
|
||||
/**
|
||||
* 按压或鼠标点击后渲染摇杆
|
||||
* @param {} event TouchEvent | MouseEvent
|
||||
*/
|
||||
function down(event: MouseEvent) {
|
||||
if (event.buttons === 1) {
|
||||
console.log('🚀 ~ file: ContextMenu.provider.tsx:81 ~ down ~ event:', event);
|
||||
pressing = true;
|
||||
prevX = getClientPosition(event).x;
|
||||
prevY = getClientPosition(event).y;
|
||||
baseEle.style.visibility = 'visible';
|
||||
stickEle.style.visibility = 'visible';
|
||||
stickMove(stickEle.style, prevX - stickEle.width / 2, prevY - stickEle.height / 2);
|
||||
stickMove(baseEle.style, prevX - baseEle.width / 2, prevY - baseEle.height / 2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消按压或松开鼠标后隐藏摇杆,并重置display坐标
|
||||
* @param {} event TouchEvent | MouseEvent
|
||||
*/
|
||||
function up(event) {
|
||||
pressing = false;
|
||||
baseEle.style.visibility = 'hidden';
|
||||
stickEle.style.visibility = 'hidden';
|
||||
displayX = 0;
|
||||
displayY = 0;
|
||||
}
|
||||
|
||||
function moveTable(relX: number, relY: number) {
|
||||
const tables = document.querySelectorAll('.ant-table-content');
|
||||
const main = document.querySelector('main');
|
||||
tables.forEach((table) => {
|
||||
table.scrollBy(relX * 10, 0);
|
||||
});
|
||||
main.scrollBy(0, relY * 10 * -1);
|
||||
}
|
||||
|
||||
let moveRelX = 0;
|
||||
let moveRelY = 0;
|
||||
|
||||
const timerId = setInterval(() => {
|
||||
if (pressing) {
|
||||
moveTable(moveRelX, moveRelY);
|
||||
}
|
||||
}, 16);
|
||||
|
||||
/**
|
||||
* 移动鼠标响应事件,根据移动坐标计算相对坐标以及需要渲染的坐标,
|
||||
* 并根据半径限制距离,对计算后的值进行四舍五入
|
||||
* @param {} event TouchEvent | MouseEvent
|
||||
*/
|
||||
function move(event) {
|
||||
if (pressing) {
|
||||
newX = getClientPosition(event).x;
|
||||
newY = getClientPosition(event).y;
|
||||
relX = newX - prevX;
|
||||
relY = prevY - newY;
|
||||
const distance = Math.sqrt(Math.pow(relX, 2) + Math.pow(relY, 2));
|
||||
const stickNormalizedX = relX / distance;
|
||||
const stickNormalizedY = relY / distance;
|
||||
moveRelX = stickNormalizedX;
|
||||
moveRelY = stickNormalizedY;
|
||||
// moveTable(stickNormalizedX, stickNormalizedY);
|
||||
if (distance <= config.radius) {
|
||||
moveX = newX - stickEle.width / 2;
|
||||
moveY = newY - stickEle.height / 2;
|
||||
stickMove(stickEle.style, moveX, moveY);
|
||||
} else {
|
||||
moveX = stickNormalizedX * config.radius + prevX - stickEle.width / 2;
|
||||
moveY = -stickNormalizedY * config.radius + prevY - stickEle.height / 2;
|
||||
stickMove(stickEle.style, moveX, moveY);
|
||||
}
|
||||
displayX = Math.round(stickNormalizedX * config.radius);
|
||||
displayY = Math.round(stickNormalizedY * config.radius);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建摇杆canvas
|
||||
*/
|
||||
function createStickCanvas() {
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = 86;
|
||||
canvas.height = 86;
|
||||
const ctx = canvas.getContext('2d');
|
||||
ctx.beginPath();
|
||||
ctx.lineWidth = 6;
|
||||
ctx.arc(canvas.width / 2, canvas.width / 2, 40, 0, Math.PI * 2, true);
|
||||
ctx.stroke();
|
||||
return canvas;
|
||||
}
|
||||
/**
|
||||
* 创建摇杆底座canvas
|
||||
*/
|
||||
function createBaseCanvas() {
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = 126;
|
||||
canvas.height = 126;
|
||||
|
||||
const ctx = canvas.getContext('2d');
|
||||
ctx.beginPath();
|
||||
ctx.lineWidth = 6;
|
||||
ctx.arc(canvas.width / 2, canvas.width / 2, 40, 0, Math.PI * 2, true);
|
||||
ctx.stroke();
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.lineWidth = 2;
|
||||
ctx.arc(canvas.width / 2, canvas.width / 2, 60, 0, Math.PI * 2, true);
|
||||
ctx.stroke();
|
||||
|
||||
return canvas;
|
||||
}
|
||||
/**
|
||||
* 移动摇杆
|
||||
* @param {} style 传入摇杆底座/摇杆的style属性
|
||||
* @param {} x x轴移动距离
|
||||
* @param {} y y轴移动距离
|
||||
* @example stickMove(stickEle.style, (prevX - stickEle.width/2), (prevY - stickEle.height/2));
|
||||
*/
|
||||
function stickMove(style, x, y) {
|
||||
const transform = supportTransform();
|
||||
if (transform) {
|
||||
style[transform] = 'translate(' + x + 'px,' + y + 'px)';
|
||||
} else {
|
||||
style.left = x + 'px';
|
||||
style.top = y + 'px';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查看是否支持translate
|
||||
*/
|
||||
function supportTransform() {
|
||||
const styles = ['webkitTransform', 'MozTransform', 'msTransform', 'OTransform', 'transform'];
|
||||
|
||||
const el = document.createElement('p');
|
||||
let style;
|
||||
|
||||
for (let i = 0; i < styles.length; i++) {
|
||||
style = styles[i];
|
||||
if (null != el.style[style]) {
|
||||
return style;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取client坐标,不同的响应对象取值方法不同
|
||||
* @param {} event TouchEvent | MouseEvent
|
||||
*/
|
||||
function getClientPosition(event) {
|
||||
if (event instanceof TouchEvent) {
|
||||
return {
|
||||
x: event.touches[0].clientX,
|
||||
y: event.touches[0].clientY,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
x: event.clientX,
|
||||
y: event.clientY,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return () => {
|
||||
clearInterval(timerId);
|
||||
};
|
||||
});
|
||||
return (
|
||||
<ContextMenuContext.Provider value={{ contextMenuEnabled: enable, setContextMenuEnable: setEnable }}>
|
||||
{enable ? (
|
||||
<>
|
||||
<ContextMenu id="my-context-menu-1">
|
||||
<ContextMenuItem
|
||||
onClick={() => {
|
||||
setEnableDragable((enable) => !enable);
|
||||
}}
|
||||
>
|
||||
拖动助手
|
||||
</ContextMenuItem>
|
||||
</ContextMenu>
|
||||
<ContextMenuTrigger id="my-context-menu-1">
|
||||
{enableDragable && (
|
||||
<div
|
||||
ref={ref}
|
||||
className={css`
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
z-index: 1000;
|
||||
background-color: rgba(141, 141, 113, 0.274);
|
||||
`}
|
||||
></div>
|
||||
)}
|
||||
{children}
|
||||
</ContextMenuTrigger>
|
||||
</>
|
||||
) : (
|
||||
<>{children}</>
|
||||
)}
|
||||
</ContextMenuContext.Provider>
|
||||
);
|
||||
};
|
@ -0,0 +1,8 @@
|
||||
import { Plugin } from '@nocobase/client';
|
||||
import { ContextMenuProvider } from './ContextMenu.provider';
|
||||
|
||||
export class PluginContextMenu extends Plugin {
|
||||
async load() {
|
||||
this.app.use(ContextMenuProvider);
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
import React, { createContext, useContext } from 'react';
|
||||
|
||||
interface ContextMenuContext {
|
||||
contextMenuEnabled: boolean;
|
||||
setContextMenuEnable: (enabled: boolean) => void;
|
||||
}
|
||||
|
||||
export const ContextMenuContext = createContext<Partial<ContextMenuContext>>({});
|
||||
|
||||
export const useContextMenu = () => {
|
||||
return useContext(ContextMenuContext);
|
||||
};
|
@ -80,6 +80,7 @@ import { PluginPageStyle } from './features/page-style';
|
||||
import { PluginHeraVersion } from './features/hera-version';
|
||||
import { PluginAssistant } from './features/assistant';
|
||||
import { TstzrangeFieldInterface } from './interfaces/TstzrangeFieldInterface';
|
||||
import { PluginContextMenu } from './features/context-menu';
|
||||
export { usePDFViewerRef } from './schema-initializer';
|
||||
export * from './components/custom-components/custom-components';
|
||||
|
||||
@ -92,6 +93,7 @@ export class PluginCoreClient extends Plugin {
|
||||
await this.app.pm.add(DepartmentsPlugin);
|
||||
await this.app.pm.add(PluginPageStyle);
|
||||
await this.app.pm.add(PluginHeraVersion);
|
||||
await this.app.pm.add(PluginContextMenu);
|
||||
await this.app.pm.add(PluginAssistant);
|
||||
}
|
||||
|
||||
|
106
pnpm-lock.yaml
106
pnpm-lock.yaml
@ -257,6 +257,9 @@ importers:
|
||||
gulp-typescript:
|
||||
specifier: 6.0.0-alpha.1
|
||||
version: 6.0.0-alpha.1(typescript@5.4.4)
|
||||
sass:
|
||||
specifier: ^1.75.0
|
||||
version: 1.75.0
|
||||
tar:
|
||||
specifier: ^6.2.0
|
||||
version: 6.2.0
|
||||
@ -271,7 +274,7 @@ importers:
|
||||
version: 3.0.0
|
||||
vite:
|
||||
specifier: ^5.0.0
|
||||
version: 5.1.5(@types/node@20.12.7)
|
||||
version: 5.1.5(@types/node@20.12.7)(sass@1.75.0)
|
||||
vite-plugin-css-injected-by-js:
|
||||
specifier: ^3.2.1
|
||||
version: 3.3.0(vite@5.1.5)
|
||||
@ -1234,7 +1237,7 @@ importers:
|
||||
version: 6.3.3
|
||||
vite:
|
||||
specifier: ^5.0.0
|
||||
version: 5.1.5(@types/node@20.12.7)
|
||||
version: 5.1.5(@types/node@20.12.7)(sass@1.75.0)
|
||||
vitest:
|
||||
specifier: ^1.4.0
|
||||
version: 1.4.0(@types/node@20.12.7)(jsdom@16.7.0)
|
||||
@ -1531,6 +1534,9 @@ importers:
|
||||
react-router-dom:
|
||||
specifier: ^6.11.2
|
||||
version: 6.21.0(react-dom@18.2.0)(react@18.2.0)
|
||||
react-transition-group:
|
||||
specifier: ^4.4.5
|
||||
version: 4.4.5(react-dom@18.2.0)(react@18.2.0)
|
||||
redis:
|
||||
specifier: ^4.6.11
|
||||
version: 4.6.13
|
||||
@ -9652,7 +9658,7 @@ packages:
|
||||
peerDependencies:
|
||||
react: '>=16.3.0'
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.6
|
||||
'@babel/runtime': 7.24.4
|
||||
hoist-non-react-statics: 3.3.2
|
||||
react: 18.1.0
|
||||
react-is: 16.13.1
|
||||
@ -9663,7 +9669,7 @@ packages:
|
||||
peerDependencies:
|
||||
react: '>=16.3.0'
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.6
|
||||
'@babel/runtime': 7.24.4
|
||||
hoist-non-react-statics: 3.3.2
|
||||
react: 18.2.0
|
||||
react-is: 16.13.1
|
||||
@ -10511,13 +10517,13 @@ packages:
|
||||
/@react-pdf/fns@2.2.1:
|
||||
resolution: {integrity: sha512-s78aDg0vDYaijU5lLOCsUD+qinQbfOvcNeaoX9AiE7+kZzzCo6B/nX+l48cmt9OosJmvZvE9DWR9cLhrhOi2pA==}
|
||||
dependencies:
|
||||
'@babel/runtime': 7.24.0
|
||||
'@babel/runtime': 7.24.4
|
||||
dev: true
|
||||
|
||||
/@react-pdf/font@2.4.4:
|
||||
resolution: {integrity: sha512-yjK5eSY+LcbxS0m+sOYln8GdgIbUgti4xjwf14kx8OSsOMJQJyHFALHMh2cLcKJR9yZeqVDo1FwCsY6gw1yCkg==}
|
||||
dependencies:
|
||||
'@babel/runtime': 7.24.0
|
||||
'@babel/runtime': 7.24.4
|
||||
'@react-pdf/types': 2.4.1
|
||||
cross-fetch: 3.1.8
|
||||
fontkit: 2.0.2
|
||||
@ -10529,7 +10535,7 @@ packages:
|
||||
/@react-pdf/image@2.3.4:
|
||||
resolution: {integrity: sha512-IE34l7gfTdaxXe3XR9240xMZsFdxF1myIwmEWK28XoeTaucUPAUyOiNcFSGRT59vNuZVBuakYz3BlGGrkvAPVQ==}
|
||||
dependencies:
|
||||
'@babel/runtime': 7.24.0
|
||||
'@babel/runtime': 7.24.4
|
||||
'@react-pdf/png-js': 2.3.1
|
||||
cross-fetch: 3.1.8
|
||||
jay-peg: 1.0.1
|
||||
@ -10540,7 +10546,7 @@ packages:
|
||||
/@react-pdf/layout@3.11.2:
|
||||
resolution: {integrity: sha512-5EiHJ+Eb0odqnkWll9pWbTp+dwH1QRm7mOXDMiklqIWK98eI7e3cEae5Dgr0TtdnB7KgPW9Tvul2CwRJTwq54A==}
|
||||
dependencies:
|
||||
'@babel/runtime': 7.24.0
|
||||
'@babel/runtime': 7.24.4
|
||||
'@react-pdf/fns': 2.2.1
|
||||
'@react-pdf/image': 2.3.4
|
||||
'@react-pdf/pdfkit': 3.1.6
|
||||
@ -10559,7 +10565,7 @@ packages:
|
||||
/@react-pdf/pdfkit@3.1.6:
|
||||
resolution: {integrity: sha512-U96VVhphniDBsLbmeJHgEml15nng8cr90mmEfPATh98gsqg6wev0avBr4k9XPjLdaN1f2xTXD4VdlaMYJZ+n7Q==}
|
||||
dependencies:
|
||||
'@babel/runtime': 7.24.0
|
||||
'@babel/runtime': 7.24.4
|
||||
'@react-pdf/png-js': 2.3.1
|
||||
browserify-zlib: 0.2.0
|
||||
crypto-js: 4.2.0
|
||||
@ -10581,7 +10587,7 @@ packages:
|
||||
/@react-pdf/render@3.4.3:
|
||||
resolution: {integrity: sha512-9LL059vfwrK1gA0uIA4utpQ/pUH9EW/yia4bb7pCoARs8IlupY5UP265jgax15ua0p+MdUwShZzQ9rilu7kGsw==}
|
||||
dependencies:
|
||||
'@babel/runtime': 7.24.0
|
||||
'@babel/runtime': 7.24.4
|
||||
'@react-pdf/fns': 2.2.1
|
||||
'@react-pdf/primitives': 3.1.1
|
||||
'@react-pdf/textkit': 4.4.1
|
||||
@ -10618,7 +10624,7 @@ packages:
|
||||
/@react-pdf/stylesheet@4.2.4:
|
||||
resolution: {integrity: sha512-CgRfDzeMtnV0GL7zSn381NubmgwqKhFKcK1YrWX3azl/KWVh52jjFd3HWi6dvcETNT862mjWz5MnExe4WOBJXA==}
|
||||
dependencies:
|
||||
'@babel/runtime': 7.24.0
|
||||
'@babel/runtime': 7.24.4
|
||||
'@react-pdf/fns': 2.2.1
|
||||
'@react-pdf/types': 2.4.1
|
||||
color-string: 1.9.1
|
||||
@ -10630,7 +10636,7 @@ packages:
|
||||
/@react-pdf/textkit@4.4.1:
|
||||
resolution: {integrity: sha512-Jl9wdTqIvJ5pX+vAGz0EOhP7ut5Two9H6CzTKo/YYPeD79cM2yTXF3JzTERBC28y7LR0Waq9D2LHQjI+b/EYUQ==}
|
||||
dependencies:
|
||||
'@babel/runtime': 7.24.0
|
||||
'@babel/runtime': 7.24.4
|
||||
'@react-pdf/fns': 2.2.1
|
||||
bidi-js: 1.0.3
|
||||
hyphen: 1.10.4
|
||||
@ -13141,7 +13147,7 @@ packages:
|
||||
/@umijs/history@5.3.1:
|
||||
resolution: {integrity: sha512-/e0cEGrR2bIWQD7pRl3dl9dcyRGeC9hoW0OCvUTT/hjY0EfUrkd6G8ZanVghPMpDuY5usxq9GVcvrT8KNXLWvA==}
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.6
|
||||
'@babel/runtime': 7.24.4
|
||||
query-string: 6.14.1
|
||||
|
||||
/@umijs/lint@4.1.10(eslint@8.57.0)(stylelint@14.16.1)(typescript@5.4.5):
|
||||
@ -13578,7 +13584,7 @@ packages:
|
||||
'@babel/plugin-transform-react-jsx-self': 7.24.1(@babel/core@7.24.4)
|
||||
'@babel/plugin-transform-react-jsx-source': 7.24.1(@babel/core@7.24.4)
|
||||
react-refresh: 0.14.0
|
||||
vite: 4.5.2(@types/node@20.12.2)(less@4.1.3)
|
||||
vite: 4.5.2(@types/node@20.12.7)(less@4.1.3)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
@ -13593,7 +13599,7 @@ packages:
|
||||
'@babel/plugin-transform-react-jsx-source': 7.23.3(@babel/core@7.23.6)
|
||||
'@types/babel__core': 7.20.5
|
||||
react-refresh: 0.14.0
|
||||
vite: 5.1.5(@types/node@20.12.7)
|
||||
vite: 5.1.5(@types/node@20.12.7)(sass@1.75.0)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: false
|
||||
@ -17557,7 +17563,7 @@ packages:
|
||||
/dom-helpers@5.2.1:
|
||||
resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==}
|
||||
dependencies:
|
||||
'@babel/runtime': 7.24.0
|
||||
'@babel/runtime': 7.24.4
|
||||
csstype: 3.1.3
|
||||
dev: true
|
||||
|
||||
@ -20257,7 +20263,7 @@ packages:
|
||||
/history@5.3.0:
|
||||
resolution: {integrity: sha512-ZqaKwjjrAYUYfLG+htGaIIZ4nioX2L70ZUMIFysS3xvBsSG4x/n1V6TXV3N8ZYNuFGlDirFg32T7B6WOUPDYcQ==}
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.6
|
||||
'@babel/runtime': 7.24.4
|
||||
|
||||
/hmac-drbg@1.0.1:
|
||||
resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==}
|
||||
@ -20590,6 +20596,10 @@ packages:
|
||||
resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==}
|
||||
dev: true
|
||||
|
||||
/immutable@4.3.5:
|
||||
resolution: {integrity: sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==}
|
||||
dev: false
|
||||
|
||||
/import-fresh@3.3.0:
|
||||
resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
|
||||
engines: {node: '>=6'}
|
||||
@ -25061,7 +25071,7 @@ packages:
|
||||
dependencies:
|
||||
nanoid: 3.3.7
|
||||
picocolors: 1.0.0
|
||||
source-map-js: 1.0.2
|
||||
source-map-js: 1.2.0
|
||||
dev: false
|
||||
|
||||
/postcss@8.4.38:
|
||||
@ -25567,7 +25577,7 @@ packages:
|
||||
react: '>=16.9.0'
|
||||
react-dom: '>=16.9.0'
|
||||
dependencies:
|
||||
'@babel/runtime': 7.24.0
|
||||
'@babel/runtime': 7.24.4
|
||||
classnames: 2.5.1
|
||||
dom-align: 1.12.4
|
||||
rc-util: 5.39.1(react-dom@18.2.0)(react@18.2.0)
|
||||
@ -25895,7 +25905,7 @@ packages:
|
||||
react: '*'
|
||||
react-dom: '*'
|
||||
dependencies:
|
||||
'@babel/runtime': 7.24.0
|
||||
'@babel/runtime': 7.24.4
|
||||
classnames: 2.5.1
|
||||
rc-motion: 2.9.0(react-dom@18.2.0)(react@18.2.0)
|
||||
rc-overflow: 1.3.2(react-dom@18.2.0)(react@18.2.0)
|
||||
@ -26089,7 +26099,7 @@ packages:
|
||||
react: '*'
|
||||
react-dom: '*'
|
||||
dependencies:
|
||||
'@babel/runtime': 7.24.0
|
||||
'@babel/runtime': 7.24.4
|
||||
classnames: 2.5.1
|
||||
rc-motion: 2.9.0(react-dom@18.2.0)(react@18.2.0)
|
||||
rc-util: 5.39.1(react-dom@18.2.0)(react@18.2.0)
|
||||
@ -26136,7 +26146,7 @@ packages:
|
||||
react: '>=16.9.0'
|
||||
react-dom: '>=16.9.0'
|
||||
dependencies:
|
||||
'@babel/runtime': 7.24.0
|
||||
'@babel/runtime': 7.24.4
|
||||
classnames: 2.5.1
|
||||
rc-align: 4.0.15(react-dom@18.2.0)(react@18.2.0)
|
||||
rc-motion: 2.9.0(react-dom@18.2.0)(react@18.2.0)
|
||||
@ -26303,7 +26313,7 @@ packages:
|
||||
peerDependencies:
|
||||
react: '>=16.13.1'
|
||||
dependencies:
|
||||
'@babel/runtime': 7.24.0
|
||||
'@babel/runtime': 7.24.4
|
||||
react: 18.2.0
|
||||
dev: false
|
||||
|
||||
@ -26327,7 +26337,7 @@ packages:
|
||||
react: ^16.6.0 || ^17.0.0 || ^18.0.0
|
||||
react-dom: ^16.6.0 || ^17.0.0 || ^18.0.0
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.6
|
||||
'@babel/runtime': 7.24.4
|
||||
invariant: 2.2.4
|
||||
prop-types: 15.8.1
|
||||
react: 18.1.0
|
||||
@ -26341,7 +26351,7 @@ packages:
|
||||
react: ^16.6.0 || ^17.0.0 || ^18.0.0
|
||||
react-dom: ^16.6.0 || ^17.0.0 || ^18.0.0
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.6
|
||||
'@babel/runtime': 7.24.4
|
||||
invariant: 2.2.4
|
||||
prop-types: 15.8.1
|
||||
react: 18.2.0
|
||||
@ -26459,7 +26469,7 @@ packages:
|
||||
react: '>=16.3.0'
|
||||
react-dom: '>=16.3.0'
|
||||
dependencies:
|
||||
'@babel/runtime': 7.24.0
|
||||
'@babel/runtime': 7.24.4
|
||||
'@popperjs/core': 2.11.8
|
||||
'@restart/hooks': 0.4.15(react@18.2.0)
|
||||
'@types/warning': 3.0.3
|
||||
@ -26523,7 +26533,7 @@ packages:
|
||||
react-native:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@babel/runtime': 7.24.0
|
||||
'@babel/runtime': 7.24.4
|
||||
'@types/react-redux': 7.1.33
|
||||
hoist-non-react-statics: 3.3.2
|
||||
loose-envify: 1.4.0
|
||||
@ -26653,6 +26663,20 @@ packages:
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
|
||||
/react-transition-group@4.4.5(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==}
|
||||
peerDependencies:
|
||||
react: '>=16.6.0'
|
||||
react-dom: '>=16.6.0'
|
||||
dependencies:
|
||||
'@babel/runtime': 7.24.4
|
||||
dom-helpers: 5.2.1
|
||||
loose-envify: 1.4.0
|
||||
prop-types: 15.8.1
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
dev: true
|
||||
|
||||
/react@18.1.0:
|
||||
resolution: {integrity: sha512-4oL8ivCz5ZEPyclFQXaNksK3adutVS8l2xzZU0cqEFrE9Sb7fC0EFK5uEk74wIreL1DERyjvsU915j1pcT2uEQ==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@ -26833,7 +26857,7 @@ packages:
|
||||
/redux@4.2.1:
|
||||
resolution: {integrity: sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==}
|
||||
dependencies:
|
||||
'@babel/runtime': 7.24.0
|
||||
'@babel/runtime': 7.24.4
|
||||
|
||||
/reflect-metadata@0.1.14:
|
||||
resolution: {integrity: sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A==}
|
||||
@ -27464,6 +27488,16 @@ packages:
|
||||
postcss: 8.4.35
|
||||
dev: false
|
||||
|
||||
/sass@1.75.0:
|
||||
resolution: {integrity: sha512-ShMYi3WkrDWxExyxSZPst4/okE9ts46xZmJDSawJQrnte7M1V9fScVB+uNXOVKRBt0PggHOwoZcn8mYX4trnBw==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
chokidar: 3.6.0
|
||||
immutable: 4.3.5
|
||||
source-map-js: 1.2.0
|
||||
dev: false
|
||||
|
||||
/sax@1.3.0:
|
||||
resolution: {integrity: sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==}
|
||||
|
||||
@ -27998,11 +28032,6 @@ packages:
|
||||
is-plain-obj: 4.1.0
|
||||
sort-object-keys: 1.1.3
|
||||
|
||||
/source-map-js@1.0.2:
|
||||
resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: false
|
||||
|
||||
/source-map-js@1.2.0:
|
||||
resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@ -29831,7 +29860,7 @@ packages:
|
||||
peerDependencies:
|
||||
react: '>=15.0.0'
|
||||
dependencies:
|
||||
'@babel/runtime': 7.24.0
|
||||
'@babel/runtime': 7.24.4
|
||||
'@types/react': 18.2.79
|
||||
invariant: 2.2.4
|
||||
react: 18.2.0
|
||||
@ -30378,7 +30407,7 @@ packages:
|
||||
peerDependencies:
|
||||
vite: '>2.0.0-0'
|
||||
dependencies:
|
||||
vite: 5.1.5(@types/node@20.12.7)
|
||||
vite: 5.1.5(@types/node@20.12.7)(sass@1.75.0)
|
||||
dev: false
|
||||
|
||||
/vite-plugin-lib-inject-css@1.2.0(vite@5.1.5):
|
||||
@ -30388,7 +30417,7 @@ packages:
|
||||
dependencies:
|
||||
magic-string: 0.30.8
|
||||
picocolors: 1.0.0
|
||||
vite: 5.1.5(@types/node@20.12.7)
|
||||
vite: 5.1.5(@types/node@20.12.7)(sass@1.75.0)
|
||||
dev: false
|
||||
|
||||
/vite@4.5.2(@types/node@20.12.2)(less@4.1.3):
|
||||
@ -30426,6 +30455,7 @@ packages:
|
||||
rollup: 3.29.4
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.3
|
||||
dev: false
|
||||
|
||||
/vite@4.5.2(@types/node@20.12.7)(less@4.1.3):
|
||||
resolution: {integrity: sha512-tBCZBNSBbHQkaGyhGCDUGqeo2ph8Fstyp6FMSvTtsXeZSPpSMGlviAOav2hxVTqFcx8Hj/twtWKsMJXNY0xI8w==}
|
||||
@ -30462,9 +30492,8 @@ packages:
|
||||
rollup: 3.29.4
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.3
|
||||
dev: true
|
||||
|
||||
/vite@5.1.5(@types/node@20.12.7):
|
||||
/vite@5.1.5(@types/node@20.12.7)(sass@1.75.0):
|
||||
resolution: {integrity: sha512-BdN1xh0Of/oQafhU+FvopafUp6WaYenLU/NFoL5WyJL++GxkNfieKzBhM24H3HVsPQrlAqB7iJYTHabzaRed5Q==}
|
||||
engines: {node: ^18.0.0 || >=20.0.0}
|
||||
hasBin: true
|
||||
@ -30496,6 +30525,7 @@ packages:
|
||||
esbuild: 0.19.9
|
||||
postcss: 8.4.35
|
||||
rollup: 4.9.0
|
||||
sass: 1.75.0
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.3
|
||||
dev: false
|
||||
|
Loading…
Reference in New Issue
Block a user