Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question: set position in bottom right instead of top left? #871

Open
EduardoBreton opened this issue May 20, 2022 · 5 comments
Open

Question: set position in bottom right instead of top left? #871

EduardoBreton opened this issue May 20, 2022 · 5 comments

Comments

@EduardoBreton
Copy link

I have noticed that by default you can only initially place a Rnd element in a top left position, however, I want to place my element in the bottom right, so I need to set bottom-right to 0 and left the top left undeclared. I wish to know if that particular operation is possible, since it doesn't work with the style parameter.

@EduardoBreton EduardoBreton changed the title Question: set position in bottom right instead of bottom left? Question: set position in bottom right instead of top left? May 20, 2022
@zhllucky
Copy link

I have a same question

@sterlingwalsh
Copy link

sterlingwalsh commented Nov 15, 2022

Ran into this same issue myself. There is no good way to go about this in the library, so I used a wrapper. I know this question is old, but I'll leave this here for anyone needing this feature. Note, theres certainly more going on in my wrapper but I'll try to trim it down to only the relevant things so if a variable was missing, it's probably other options for me but no the core of the solution here.

essentially what is happening is the first layout renders the rnd component and it's children with either defined width and height or 'auto' in the top left corner of the parent container with visibility hidden. once the browser handles that and the rnd component has its browser determined size, the useEffect will run, grab the calculated size as well as the size of the container, run the math based on flex-similar properties to position the still absolutely positioned rnd component around the screen wheerever it's needed if those options are selected and then bottom/right pixel values override that new position. onceall that is done, change visibility to 'visibile'. After that, I'm still using the standard on drag/resize callbacks to control the position with state as described in the documentation here.

`
interface WindowPosition {
top: number;
left: number;
width: number | string;
height: number | string;
}

export interface WindowPositionOptions extends Partial {
bottom?: number;
right?: number;
}

interface WindowPositionState extends Partial {
top?: number;
left?: number;
}

const margin = 5;

export type WindowJustify = 'left' | 'center' | 'right' | 'stretch';
export type WindowAlign = 'top' | 'center' | 'bottom' | 'stretch';

export type WindowProps = Partial &
Partial<Pick<Rnd, 'onResize'>> & {
bottom?: number;
right?: number;

	justify?: WindowJustify;
	align?: WindowAlign;
};

const maxPosition = {
top: margin,
left: margin,
width: calc(100% - ${margin * 2}px,
height: calc(100% - ${margin * 2}px,
};

export const initJustifyAlign = (
incWidth: number,
incHeight: number,
containerWidth: number,
containerHeight: number,
justify?: WindowJustify,
align?: WindowAlign
) => {
const rect: Partial = {};

switch (justify) {
	case 'left':
		rect.left = margin;
		break;
	case 'center':
		rect.left = (containerWidth - incWidth) / 2;
		break;
	case 'right':
		rect.left = containerWidth - incWidth - margin;
		break;
	case 'stretch':
		rect.width = containerWidth - 2 * margin;
		break;
	default:
		break;
}

switch (align) {
	case 'top':
		rect.top = margin;
		break;
	case 'center':
		rect.top = (containerHeight - incHeight) / 2;
		break;
	case 'bottom':
		rect.top = containerHeight - incHeight - margin;
		break;
	case 'stretch':
		rect.height = containerHeight - 2 * margin;
		break;
	default:
		break;
}
return rect;

};

export const Window: RA.FC<WindowProps, true> = ({
title,
top: incTop,
left: incLeft,
width: incWidth,
height: incHeight,
bottom: incBottom,
right: incRight,
...props
}) => {
const [, startTransition] = useTransition();

const top = incTop ?? preset.top,
	left = incLeft ?? preset.left,
	bottom = incBottom ?? preset.bottom,
	right = incRight ?? preset.right,
	width = incWidth ?? preset.width,
	height = incHeight ?? preset.height;

const [position, setPosition] = useState<WindowPositionState>({
	top: top ?? margin,
	left: left ?? margin,
	width: width ?? 'auto',
	height: height ?? 'auto',
});
const ref = useRef<Rnd | null>(null);
const [hasPositioned, setHasPositioned] = useState(false);
useEffect(() => {
	const el = ref.current?.resizableElement.current;
	if (el) {
		const updates: WindowPositionState = {};
		updates.width = width !== undefined && width !== 'auto' ? width : el.offsetWidth;
		updates.height = height !== undefined && height !== 'auto' ? height : el.offsetHeight;

                    const container = stateRef.current.container ?? el.offsetParent;
		if (container) {
			

			Object.assign(updates, initJustifyAlign(el.offsetWidth, el.offsetHeight, container.offsetWidth, container.offsetHeight, justify, align));
			if (bottom !== undefined) updates.top = Math.max(container.offsetHeight - Math.max(margin, bottom) - el.offsetHeight, margin);
			if (right !== undefined) updates.left = Math.max(container.offsetWidth - Math.max(margin, right) - el.offsetWidth, margin);
		}

		startTransition(() => {
			setPosition((p) => ({ ...p, ...updates }));
			setHasPositioned(true);
		});
	}
}, [ref, setPosition, width, height, stateRef, bottom, right, justify, align]);

return !open ? null : (
	<Rnd
		{...props}
		style={{ visibility: hasPositioned ? 'visible' : 'hidden' }}
		size={{ width: currPosition.width!, height: currPosition.height! }}
		maxHeight={`calc(100% - ${margin * 2}px`}
		maxWidth={`calc(100% - ${margin * 2}px`}
		position={{ x: currPosition.left!, y: currPosition.top! }}
		
	>
		...
	</Rnd>
);

};
`

@aszmyd
Copy link

aszmyd commented Mar 20, 2023

I had the same issue and for me, a simple initial effect that changes the position based on the element dimensions and the viewport size did the job:

const rndRef = React.useRef<Rnd>();
const corner: 'top-left' | 'top-right' | 'bottom-right' | 'bottom-left' = 'top-left';

React.useEffect(() => {
        if (rndRef.current && rndRef.current.getSelfElement()) {

            const initialRect = rndRef.current.getSelfElement().getBoundingClientRect();
            const documentWindow = rndRef.current.getSelfElement().ownerDocument.defaultView;

            const [initialX, initialY] = [initialRect.x, initialRect.y];
            const [elementWidth, elementHeight] = [initialRect.width, initialRect.height];
            const [viewportWidth, viewportHeight] = [documentWindow.innerWidth, documentWindow.innerHeight];

            let [newX, newY] = [initialX, initialY];
            switch (corner) {
                case 'top-left':
                    // it's the same as the initial (as react-rnd by default positions in this corner) so no change neede
                    break;
                case 'top-right':
                    newX = viewportWidth - elementWidth - initialX;
                    break;
                case 'bottom-right':
                    newX = viewportWidth - elementWidth - initialX;
                    newY = viewportHeight - elementHeight - initialY;
                    break;
                case 'bottom-left':
                    newY = viewportHeight - elementHeight - initialY;
                    break;
            }

            rndRef.current.updatePosition({
                x: newX,
                y: newY
            });
        }
    }, [rndRef.current]);


  return (
     <Rnd
            default={{
                x: 10,
                y: 10,
                width: 'auto',
                height: 'auto',
            }}
            ref={rndRef}
        >
           ...
       </Rnd>
   )


@baba43
Copy link

baba43 commented May 19, 2023

Thank you. However, I think there should be an easier solution.

@mrskiro
Copy link

mrskiro commented May 28, 2024

I have a same question

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants