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:
Cats Juice
2024-01-18 02:14:27 +00:00
parent ee8ec47a4f
commit 2b92b27f8f
7 changed files with 555 additions and 1 deletions
@@ -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',
});