This commit is contained in:
2025-10-21 19:42:39 +05:00
2 changed files with 64 additions and 4 deletions
+61 -1
View File
@@ -7,6 +7,7 @@ export interface Position {
left?: number | string; left?: number | string;
right?: number | string; right?: number | string;
bottom?: number | string; bottom?: number | string;
transform?: string;
} }
export type Corner = "top-left" | "top-right" | "bottom-left" | "bottom-right"; export type Corner = "top-left" | "top-right" | "bottom-left" | "bottom-right";
@@ -20,6 +21,10 @@ interface DraggableContainerProps {
autoAlign?: boolean; autoAlign?: boolean;
/** Ограничить перетаскивание границами окна (по умолчанию false) */ /** Ограничить перетаскивание границами окна (по умолчанию false) */
constrainToBounds?: boolean; constrainToBounds?: boolean;
/** Центрировать контейнер по вертикали (имеет приоритет над initialCorner и initialPosition) */
centerVertical?: boolean;
/** Центрировать контейнер по горизонтали (имеет приоритет над initialCorner и initialPosition) */
centerHorizontal?: boolean;
/** Начальный угол экрана (имеет приоритет над initialPosition) */ /** Начальный угол экрана (имеет приоритет над initialPosition) */
initialCorner?: Corner; initialCorner?: Corner;
/** Начальная позиция контейнера (используется если не указан initialCorner) */ /** Начальная позиция контейнера (используется если не указан initialCorner) */
@@ -47,6 +52,24 @@ interface DraggableContainerProps {
* </DraggableContainer> * </DraggableContainer>
* *
* @example * @example
* // Размещение по центру экрана (вертикально и горизонтально)
* <DraggableContainer centerVertical={true} centerHorizontal={true}>
* <YourContent />
* </DraggableContainer>
*
* @example
* // Центрирование только по вертикали
* <DraggableContainer centerVertical={true}>
* <YourContent />
* </DraggableContainer>
*
* @example
* // Центрирование только по горизонтали
* <DraggableContainer centerHorizontal={true}>
* <YourContent />
* </DraggableContainer>
*
* @example
* // С указанием начального угла и отступами в процентах * // С указанием начального угла и отступами в процентах
* <DraggableContainer initialCorner="bottom-right" padding="2%"> * <DraggableContainer initialCorner="bottom-right" padding="2%">
* <YourContent /> * <YourContent />
@@ -75,6 +98,8 @@ export default function DraggableContainer({
enableSnapping = false, enableSnapping = false,
autoAlign = false, autoAlign = false,
constrainToBounds = false, constrainToBounds = false,
centerVertical = false,
centerHorizontal = false,
initialCorner, initialCorner,
initialPosition, initialPosition,
padding = "16px", padding = "16px",
@@ -105,6 +130,32 @@ export default function DraggableContainer({
// Определяем начальную позицию // Определяем начальную позицию
const getInitialPosition = (): Position => { const getInitialPosition = (): Position => {
// Если используется центрирование
if (centerVertical || centerHorizontal) {
const position: Position = {};
const transforms: string[] = [];
if (centerVertical) {
position.top = "50%";
transforms.push("translateY(-50%)");
} else {
position.top = padding;
}
if (centerHorizontal) {
position.left = "50%";
transforms.push("translateX(-50%)");
} else {
position.left = padding;
}
if (transforms.length > 0) {
position.transform = transforms.join(" ");
}
return position;
}
if (initialCorner) { if (initialCorner) {
return getPositionFromCorner(initialCorner); return getPositionFromCorner(initialCorner);
} }
@@ -112,7 +163,7 @@ export default function DraggableContainer({
return initialPosition; return initialPosition;
} }
// По умолчанию - верхний правый угол // По умолчанию - верхний правый угол
return { top: padding, right: padding }; return { top: padding, left: padding };
}; };
const [position, setPosition] = useState<Position>(getInitialPosition()); const [position, setPosition] = useState<Position>(getInitialPosition());
@@ -173,6 +224,14 @@ export default function DraggableContainer({
setDragStartAlignment(getAlignmentClassesFromPosition(position)); setDragStartAlignment(getAlignmentClassesFromPosition(position));
} }
// Если контейнер был по центру с transform, убираем transform и используем абсолютную позицию
if (position.transform) {
setPosition({
top: rect.top,
left: rect.left,
});
}
dragRef.current = { dragRef.current = {
isDragging: true, isDragging: true,
startX: clientX, startX: clientX,
@@ -331,6 +390,7 @@ export default function DraggableContainer({
if (position.right !== undefined) style.right = formatValue(position.right); if (position.right !== undefined) style.right = formatValue(position.right);
if (position.bottom !== undefined) if (position.bottom !== undefined)
style.bottom = formatValue(position.bottom); style.bottom = formatValue(position.bottom);
if (position.transform !== undefined) style.transform = position.transform;
return style; return style;
}; };
+3 -3
View File
@@ -33,7 +33,7 @@ export default function ChatPopup() {
} }
return ( return (
<DraggableContainer constrainToBounds> <DraggableContainer centerVertical>
<PopupWrapper title="Чат" draggable className="sm:overflow-hidden"> <PopupWrapper title="Чат" draggable className="sm:overflow-hidden">
<div className="flex flex-col 2xl:h-[27.778vw] relative 2xl:-m-[1.389vw] -m-5"> <div className="flex flex-col 2xl:h-[27.778vw] relative 2xl:-m-[1.389vw] -m-5">
<MessageFeed messages={messages} /> <MessageFeed messages={messages} />
@@ -111,13 +111,13 @@ function MessageItem({ senderId, timestamp, content }: MessageItemProps) {
)} )}
<div>{content}</div> <div>{content}</div>
</div> </div>
<span className="caption-xs opacity-30">{timestamp}</span> <span className="opacity-30 caption-xs">{timestamp}</span>
</div> </div>
<div className="2xl:size-[2.222vw] size-8 rounded-full"> <div className="2xl:size-[2.222vw] size-8 rounded-full">
<img <img
src="/img/popups/MessageUserPfp.png" src="/img/popups/MessageUserPfp.png"
className="size-full object-cover" className="object-cover size-full"
alt="user" alt="user"
/> />
</div> </div>