refactor: use re-resizeable

pull/31/head
fantasticit 2022-04-27 13:01:09 +08:00
parent bcde9ce598
commit 2095cafec2
4 changed files with 42 additions and 115 deletions

View File

@ -59,7 +59,6 @@
"copy-to-clipboard": "^3.3.1", "copy-to-clipboard": "^3.3.1",
"deep-equal": "^2.0.5", "deep-equal": "^2.0.5",
"dompurify": "^2.3.5", "dompurify": "^2.3.5",
"interactjs": "^1.10.11",
"katex": "^0.15.2", "katex": "^0.15.2",
"kity": "^2.0.4", "kity": "^2.0.4",
"lib0": "^0.2.47", "lib0": "^0.2.47",
@ -75,6 +74,7 @@
"prosemirror-tables": "^1.1.1", "prosemirror-tables": "^1.1.1",
"prosemirror-utils": "^0.9.6", "prosemirror-utils": "^0.9.6",
"prosemirror-view": "^1.23.6", "prosemirror-view": "^1.23.6",
"re-resizable": "^6.9.9",
"react": "17.0.2", "react": "17.0.2",
"react-countdown": "^2.3.2", "react-countdown": "^2.3.2",
"react-dom": "17.0.2", "react-dom": "17.0.2",

View File

@ -1,9 +1,9 @@
import React, { useRef, useEffect } from 'react'; import React, { useCallback, useState } from 'react';
import cls from 'classnames'; import cls from 'classnames';
import { useClickOutside } from 'hooks/use-click-outside';
import interact from 'interactjs';
import styles from './style.module.scss'; import styles from './style.module.scss';
import { Resizable } from 're-resizable';
interface IProps { interface IProps {
width: number; width: number;
height: number; height: number;
@ -15,71 +15,37 @@ interface IProps {
const MIN_WIDTH = 50; const MIN_WIDTH = 50;
const MIN_HEIGHT = 50; const MIN_HEIGHT = 50;
export const Resizeable: React.FC<IProps> = ({ width, height, className, onChange, onChangeEnd, children }) => { export const Resizeable: React.FC<IProps> = ({
const $container = useRef<HTMLDivElement>(null); width: defaultWidth,
const $topLeft = useRef<HTMLDivElement>(null); height: defaultHeight,
const $topRight = useRef<HTMLDivElement>(null); className,
const $bottomLeft = useRef<HTMLDivElement>(null); onChange,
const $bottomRight = useRef<HTMLDivElement>(null); onChangeEnd,
children,
}) => {
const [width, setWidth] = useState(defaultWidth);
const [height, setHeight] = useState(defaultHeight);
useClickOutside($container, { const onResizeStop = useCallback(
in: () => $container.current.classList.add(styles.isActive), (e, direction, ref, d) => {
out: () => $container.current.classList.remove(styles.isActive), const nextWidth = width + d.width;
}); const nextHeight = height + d.height;
setWidth(nextWidth);
useEffect(() => { setHeight(nextHeight);
interact($container.current).resizable({ onChangeEnd({ width: nextWidth, height: nextHeight });
edges: {
top: true,
right: true,
bottom: true,
left: true,
}, },
listeners: { [width, height]
move: function (event) { );
let { x, y } = event.target.dataset;
x = (parseFloat(x) || 0) + event.deltaRect.left;
y = (parseFloat(y) || 0) + event.deltaRect.top;
let { width, height } = event.rect;
width = width < MIN_WIDTH ? MIN_WIDTH : width;
height = height < MIN_HEIGHT ? MIN_HEIGHT : height;
Object.assign(event.target.style, {
width: `${width}px`,
height: `${height}px`,
// transform: `translate(${x}px, ${y}px)`,
});
Object.assign(event.target.dataset, { x, y });
onChange && onChange({ width, height });
},
end: function (event) {
let { width, height } = event.rect;
onChangeEnd && onChangeEnd({ width, height });
},
},
});
}, []);
useEffect(() => {
Object.assign($container.current.style, {
width: `${width}px`,
height: `${height}px`,
});
}, [width, height]);
return ( return (
<div <Resizable
id="js-resizeable-container" size={{ width, height }}
className={cls(className, styles.resizable)} className={cls(className, styles.resizable)}
ref={$container} minWidth={MIN_WIDTH}
style={{ width, height }} minHeight={MIN_HEIGHT}
onResizeStop={onResizeStop}
> >
<span className={styles.resizer + ' ' + styles.topLeft} ref={$topLeft} data-type={'topLeft'}></span>
<span className={styles.resizer + ' ' + styles.topRight} ref={$topRight} data-type={'topRight'}></span>
<span className={styles.resizer + ' ' + styles.bottomLeft} ref={$bottomLeft} data-type={'bottomLeft'}></span>
<span className={styles.resizer + ' ' + styles.bottomRight} ref={$bottomRight} data-type={'bottomRight'}></span>
{children} {children}
</div> </Resizable>
); );
}; };

View File

@ -4,47 +4,8 @@
width: 100px; width: 100px;
height: 100px; height: 100px;
max-width: 100%; max-width: 100%;
box-sizing: border-box;
.resizer {
position: absolute;
z-index: 9999;
width: 10px;
height: 10px;
background: white;
border: 3px solid #4286f4;
border-radius: 50%;
opacity: 0;
box-sizing: border-box;
}
.resizer.topLeft {
top: -5px;
left: -5px;
cursor: nwse-resize;
}
.resizer.topRight {
top: -5px;
right: -5px;
cursor: nesw-resize;
}
.resizer.bottomLeft {
bottom: -5px;
left: -5px;
cursor: nesw-resize;
}
.resizer.bottomRight {
right: -5px;
bottom: -5px;
cursor: nwse-resize;
}
&.isActive { &.isActive {
outline: 1px solid #4286f4;
.resizer { .resizer {
opacity: 1; opacity: 1;
} }

View File

@ -89,7 +89,6 @@ importers:
copy-to-clipboard: ^3.3.1 copy-to-clipboard: ^3.3.1
deep-equal: ^2.0.5 deep-equal: ^2.0.5
dompurify: ^2.3.5 dompurify: ^2.3.5
interactjs: ^1.10.11
katex: ^0.15.2 katex: ^0.15.2
kity: ^2.0.4 kity: ^2.0.4
lib0: ^0.2.47 lib0: ^0.2.47
@ -105,6 +104,7 @@ importers:
prosemirror-tables: ^1.1.1 prosemirror-tables: ^1.1.1
prosemirror-utils: ^0.9.6 prosemirror-utils: ^0.9.6
prosemirror-view: ^1.23.6 prosemirror-view: ^1.23.6
re-resizable: ^6.9.9
react: 17.0.2 react: 17.0.2
react-countdown: ^2.3.2 react-countdown: ^2.3.2
react-dom: 17.0.2 react-dom: 17.0.2
@ -172,7 +172,6 @@ importers:
copy-to-clipboard: 3.3.1 copy-to-clipboard: 3.3.1
deep-equal: 2.0.5 deep-equal: 2.0.5
dompurify: 2.3.5 dompurify: 2.3.5
interactjs: 1.10.11
katex: 0.15.2 katex: 0.15.2
kity: 2.0.4 kity: 2.0.4
lib0: 0.2.47 lib0: 0.2.47
@ -188,6 +187,7 @@ importers:
prosemirror-tables: 1.1.1 prosemirror-tables: 1.1.1
prosemirror-utils: 0.9.6_prosemirror-tables@1.1.1 prosemirror-utils: 0.9.6_prosemirror-tables@1.1.1
prosemirror-view: 1.23.6 prosemirror-view: 1.23.6
re-resizable: 6.9.9_react-dom@17.0.2+react@17.0.2
react: 17.0.2 react: 17.0.2
react-countdown: 2.3.2_react-dom@17.0.2+react@17.0.2 react-countdown: 2.3.2_react-dom@17.0.2+react@17.0.2
react-dom: 17.0.2_react@17.0.2 react-dom: 17.0.2_react@17.0.2
@ -955,10 +955,6 @@ packages:
- y-protocols - y-protocols
dev: false dev: false
/@interactjs/types/1.10.11:
resolution: {integrity: sha512-YRsVFWjL8Gkkvlx3qnjeaxW4fnibSJ9791g8BA7Pv5ANByI64WmtR1vU7A2rXcrOn8XvyCEfY0ss1s8NhZP+MA==}
dev: false
/@ioredis/commands/1.1.1: /@ioredis/commands/1.1.1:
resolution: {integrity: sha512-fsR4P/ROllzf/7lXYyElUJCheWdTJVJvOTps8v9IWKFATxR61ANOlnoPqhH099xYLrJGpc2ZQ28B3rMeUt5VQg==} resolution: {integrity: sha512-fsR4P/ROllzf/7lXYyElUJCheWdTJVJvOTps8v9IWKFATxR61ANOlnoPqhH099xYLrJGpc2ZQ28B3rMeUt5VQg==}
dev: false dev: false
@ -4468,12 +4464,6 @@ packages:
through: 2.3.8 through: 2.3.8
dev: true dev: true
/interactjs/1.10.11:
resolution: {integrity: sha512-VPUWsGAOPmrZe1YF7Fq/4AIBBZ+3FikZRS8bpzT6VsAfUuhxl/CKJY73IAiZHd3fz9p174CXErn0Qs81XEFICA==}
dependencies:
'@interactjs/types': 1.10.11
dev: false
/internal-slot/1.0.3: /internal-slot/1.0.3:
resolution: {integrity: sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==} resolution: {integrity: sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
@ -6707,6 +6697,16 @@ packages:
unpipe: 1.0.0 unpipe: 1.0.0
dev: false dev: false
/re-resizable/6.9.9_react-dom@17.0.2+react@17.0.2:
resolution: {integrity: sha512-l+MBlKZffv/SicxDySKEEh42hR6m5bAHfNu3Tvxks2c4Ah+ldnWjfnVRwxo/nxF27SsUsxDS0raAzFuJNKABXA==}
peerDependencies:
react: ^16.13.1 || ^17.0.0 || ^18.0.0
react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0
dependencies:
react: 17.0.2
react-dom: 17.0.2_react@17.0.2
dev: false
/react-countdown/2.3.2_react-dom@17.0.2+react@17.0.2: /react-countdown/2.3.2_react-dom@17.0.2+react@17.0.2:
resolution: {integrity: sha512-Q4SADotHtgOxNWhDdvgupmKVL0pMB9DvoFcxv5AzjsxVhzOVxnttMbAywgqeOdruwEAmnPhOhNv/awAgkwru2w==} resolution: {integrity: sha512-Q4SADotHtgOxNWhDdvgupmKVL0pMB9DvoFcxv5AzjsxVhzOVxnttMbAywgqeOdruwEAmnPhOhNv/awAgkwru2w==}
peerDependencies: peerDependencies: