Enhance DraggableContainer to support initial positioning via corner specification and allow padding in various units. Update SessionUsersPanel2 to utilize new initialCorner prop and adjust padding accordingly.
This commit is contained in:
@@ -2,13 +2,15 @@ import { useEffect, useRef, useState } from "react";
|
||||
import type { ReactNode } from "react";
|
||||
import clsx from "clsx";
|
||||
|
||||
interface Position {
|
||||
top?: number;
|
||||
left?: number;
|
||||
right?: number;
|
||||
bottom?: number;
|
||||
export interface Position {
|
||||
top?: number | string;
|
||||
left?: number | string;
|
||||
right?: number | string;
|
||||
bottom?: number | string;
|
||||
}
|
||||
|
||||
export type Corner = "top-left" | "top-right" | "bottom-left" | "bottom-right";
|
||||
|
||||
interface DraggableContainerProps {
|
||||
/** Содержимое контейнера */
|
||||
children: ReactNode;
|
||||
@@ -18,10 +20,12 @@ interface DraggableContainerProps {
|
||||
autoAlign?: boolean;
|
||||
/** Ограничить перетаскивание границами окна (по умолчанию false) */
|
||||
constrainToBounds?: boolean;
|
||||
/** Начальная позиция контейнера */
|
||||
/** Начальный угол экрана (имеет приоритет над initialPosition) */
|
||||
initialCorner?: Corner;
|
||||
/** Начальная позиция контейнера (используется если не указан initialCorner) */
|
||||
initialPosition?: Position;
|
||||
/** Отступ от краев экрана при снэпинге (по умолчанию 20px) */
|
||||
padding?: number;
|
||||
/** Отступ от краев экрана при снэпинге и начальной позиции (по умолчанию "20px"). Можно указать в px, %, vw, vh */
|
||||
padding?: number | string;
|
||||
/** Дополнительные CSS классы */
|
||||
className?: string;
|
||||
/** Колбэк при изменении позиции */
|
||||
@@ -43,8 +47,20 @@ interface DraggableContainerProps {
|
||||
* </DraggableContainer>
|
||||
*
|
||||
* @example
|
||||
* // С указанием начального угла и отступами в процентах
|
||||
* <DraggableContainer initialCorner="bottom-right" padding="2%">
|
||||
* <YourContent />
|
||||
* </DraggableContainer>
|
||||
*
|
||||
* @example
|
||||
* // С отступами в vw
|
||||
* <DraggableContainer initialCorner="top-left" padding="5vw">
|
||||
* <YourContent />
|
||||
* </DraggableContainer>
|
||||
*
|
||||
* @example
|
||||
* // С ограничением перетаскивания границами окна
|
||||
* <DraggableContainer constrainToBounds={true}>
|
||||
* <DraggableContainer constrainToBounds={true} initialCorner="top-left">
|
||||
* <YourContent />
|
||||
* </DraggableContainer>
|
||||
*
|
||||
@@ -59,8 +75,9 @@ export default function DraggableContainer({
|
||||
enableSnapping = false,
|
||||
autoAlign = false,
|
||||
constrainToBounds = false,
|
||||
initialPosition = { top: 20, right: 20 },
|
||||
padding = 20,
|
||||
initialCorner,
|
||||
initialPosition,
|
||||
padding = "20px",
|
||||
className = "",
|
||||
onPositionChange,
|
||||
}: DraggableContainerProps) {
|
||||
@@ -72,7 +89,33 @@ export default function DraggableContainer({
|
||||
initialPosition: { top: 0, left: 0 },
|
||||
});
|
||||
|
||||
const [position, setPosition] = useState<Position>(initialPosition);
|
||||
// Функция для преобразования угла в позицию
|
||||
const getPositionFromCorner = (corner: Corner): Position => {
|
||||
switch (corner) {
|
||||
case "top-left":
|
||||
return { top: padding, left: padding };
|
||||
case "top-right":
|
||||
return { top: padding, right: padding };
|
||||
case "bottom-left":
|
||||
return { bottom: padding, left: padding };
|
||||
case "bottom-right":
|
||||
return { bottom: padding, right: padding };
|
||||
}
|
||||
};
|
||||
|
||||
// Определяем начальную позицию
|
||||
const getInitialPosition = (): Position => {
|
||||
if (initialCorner) {
|
||||
return getPositionFromCorner(initialCorner);
|
||||
}
|
||||
if (initialPosition) {
|
||||
return initialPosition;
|
||||
}
|
||||
// По умолчанию - верхний правый угол
|
||||
return { top: padding, right: padding };
|
||||
};
|
||||
|
||||
const [position, setPosition] = useState<Position>(getInitialPosition());
|
||||
const [isDragging, setIsDragging] = useState(false);
|
||||
const [dragStartAlignment, setDragStartAlignment] = useState<string>("");
|
||||
|
||||
@@ -256,7 +299,9 @@ export default function DraggableContainer({
|
||||
if (isDragging) {
|
||||
document.addEventListener("mousemove", handleMouseMove);
|
||||
document.addEventListener("mouseup", handleMouseUp);
|
||||
document.addEventListener("touchmove", handleTouchMove, { passive: false });
|
||||
document.addEventListener("touchmove", handleTouchMove, {
|
||||
passive: false,
|
||||
});
|
||||
document.addEventListener("touchend", handleTouchEnd);
|
||||
document.addEventListener("touchcancel", handleTouchEnd);
|
||||
|
||||
@@ -277,10 +322,14 @@ export default function DraggableContainer({
|
||||
zIndex: 1000,
|
||||
};
|
||||
|
||||
if (position.top !== undefined) style.top = `${position.top}px`;
|
||||
if (position.left !== undefined) style.left = `${position.left}px`;
|
||||
if (position.right !== undefined) style.right = `${position.right}px`;
|
||||
if (position.bottom !== undefined) style.bottom = `${position.bottom}px`;
|
||||
const formatValue = (value: number | string): string => {
|
||||
return typeof value === "number" ? `${value}px` : value;
|
||||
};
|
||||
|
||||
if (position.top !== undefined) style.top = formatValue(position.top);
|
||||
if (position.left !== undefined) style.left = formatValue(position.left);
|
||||
if (position.right !== undefined) style.right = formatValue(position.right);
|
||||
if (position.bottom !== undefined) style.bottom = formatValue(position.bottom);
|
||||
|
||||
return style;
|
||||
};
|
||||
|
||||
@@ -35,8 +35,9 @@ function SessionUsersPanel2() {
|
||||
<DraggableContainer
|
||||
enableSnapping={true}
|
||||
autoAlign={true}
|
||||
initialPosition={{ top: 20, left: 20 }}
|
||||
padding={20}
|
||||
// initialPosition={{ top: 20, left: 20 }}
|
||||
initialCorner="bottom-right"
|
||||
padding="1.111vw"
|
||||
className="flex gap-4"
|
||||
>
|
||||
{users.map((user) => (
|
||||
|
||||
Reference in New Issue
Block a user