mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-19 19:16:29 +08:00
feat(component): new week-date-picker component (#5477)
<picture> <source media="(prefers-color-scheme: dark)" srcset="https://github.com/toeverything/AFFiNE/assets/39363750/49d7a1ee-2832-4b61-a427-e627dae92952"> <img height="100" alt="" src="https://github.com/toeverything/AFFiNE/assets/39363750/819d6ee9-38e0-4537-ad0f-ec9faf96f505"> </picture>
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
import clsx from 'clsx';
|
||||
import {
|
||||
type HTMLAttributes,
|
||||
type PropsWithChildren,
|
||||
useEffect,
|
||||
useRef,
|
||||
} from 'react';
|
||||
|
||||
import * as styles from './styles.css';
|
||||
|
||||
export interface ResizePanelProps
|
||||
extends PropsWithChildren,
|
||||
HTMLAttributes<HTMLDivElement> {
|
||||
horizontal?: boolean;
|
||||
vertical?: boolean;
|
||||
width?: number;
|
||||
height?: number;
|
||||
minWidth?: number;
|
||||
minHeight?: number;
|
||||
maxWidth?: number;
|
||||
maxHeight?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* This component is used for debugging responsive layout in storybook
|
||||
* @internal
|
||||
*/
|
||||
export const ResizePanel = ({
|
||||
width,
|
||||
height,
|
||||
children,
|
||||
minHeight,
|
||||
minWidth,
|
||||
maxHeight,
|
||||
maxWidth,
|
||||
className,
|
||||
horizontal = true,
|
||||
vertical = true,
|
||||
|
||||
...attrs
|
||||
}: ResizePanelProps) => {
|
||||
const containerRef = useRef<HTMLDivElement | null>(null);
|
||||
const cornerHandleRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!containerRef.current || !cornerHandleRef.current) return;
|
||||
|
||||
const containerEl = containerRef.current;
|
||||
const cornerHandleEl = cornerHandleRef.current;
|
||||
|
||||
let startPos: [number, number] = [0, 0];
|
||||
let startSize: [number, number] = [0, 0];
|
||||
|
||||
const onDragStart = (e: MouseEvent) => {
|
||||
startPos = [e.clientX, e.clientY];
|
||||
startSize = [containerEl.offsetWidth, containerEl.offsetHeight];
|
||||
document.addEventListener('mousemove', onDrag);
|
||||
document.addEventListener('mouseup', onDragEnd);
|
||||
};
|
||||
|
||||
const onDrag = (e: MouseEvent) => {
|
||||
const pos = [e.clientX, e.clientY];
|
||||
const delta = [pos[0] - startPos[0], pos[1] - startPos[1]];
|
||||
const newSize = [startSize[0] + delta[0], startSize[1] + delta[1]];
|
||||
updateSize(newSize);
|
||||
};
|
||||
|
||||
const onDragEnd = () => {
|
||||
document.removeEventListener('mousemove', onDrag);
|
||||
document.removeEventListener('mouseup', onDragEnd);
|
||||
};
|
||||
|
||||
const updateSize = (size: number[]) => {
|
||||
if (!containerEl) return;
|
||||
|
||||
if (horizontal) {
|
||||
const width = Math.max(
|
||||
Math.min(size[0], maxWidth ?? Infinity),
|
||||
minWidth ?? 0
|
||||
);
|
||||
containerEl.style.width = `${width}px`;
|
||||
}
|
||||
|
||||
if (vertical) {
|
||||
const height = Math.max(
|
||||
Math.min(size[1], maxHeight ?? Infinity),
|
||||
minHeight ?? 0
|
||||
);
|
||||
containerEl.style.height = `${height}px`;
|
||||
}
|
||||
};
|
||||
|
||||
updateSize([width ?? 400, height ?? 200]);
|
||||
cornerHandleEl.addEventListener('mousedown', onDragStart);
|
||||
|
||||
return () => {
|
||||
cornerHandleEl.removeEventListener('mousedown', onDragStart);
|
||||
document.removeEventListener('mousemove', onDrag);
|
||||
document.removeEventListener('mouseup', onDragEnd);
|
||||
};
|
||||
}, [
|
||||
height,
|
||||
horizontal,
|
||||
maxHeight,
|
||||
maxWidth,
|
||||
minHeight,
|
||||
minWidth,
|
||||
vertical,
|
||||
width,
|
||||
]);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={containerRef}
|
||||
className={clsx(styles.container, className)}
|
||||
{...attrs}
|
||||
>
|
||||
{children}
|
||||
<div ref={cornerHandleRef} className={styles.cornerHandle}></div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,26 @@
|
||||
import { style } from '@vanilla-extract/css';
|
||||
|
||||
const HANDLE_SIZE = 24;
|
||||
|
||||
export const container = style({
|
||||
position: 'relative',
|
||||
border: '1px solid rgba(100, 100, 100, 0.2)',
|
||||
padding: 8,
|
||||
borderRadius: 4,
|
||||
borderBottomRightRadius: HANDLE_SIZE / 2,
|
||||
});
|
||||
|
||||
export const cornerHandle = style({
|
||||
position: 'absolute',
|
||||
top: `calc(100% - ${HANDLE_SIZE / 1.5}px)`,
|
||||
left: `calc(100% - ${HANDLE_SIZE / 1.5}px)`,
|
||||
width: HANDLE_SIZE,
|
||||
height: HANDLE_SIZE,
|
||||
|
||||
borderRadius: '50%',
|
||||
border: '2px solid transparent',
|
||||
borderRightColor: 'rgba(100, 100, 100, 0.3)',
|
||||
transform: 'rotate(45deg)',
|
||||
|
||||
cursor: 'nwse-resize',
|
||||
});
|
||||
Reference in New Issue
Block a user