react-rnd icon indicating copy to clipboard operation
react-rnd copied to clipboard

Add a default position x,y of "center"

Open tnrich opened this issue 6 years ago • 13 comments

Hey there,

I want to make a dialog that sizes to the elements within it but am having trouble doing that AND getting the dialog to be centered on the page.

It would be awesome if we could pass something like:

default={{x:"center", y:"center"}}

That way the dialog could be centered and that expands to fit the elements inside (up to its specified bounds).

Thanks @bokuweb !

tnrich avatar Sep 01 '18 18:09 tnrich

@bokuweb can you please update to react-draggable 3.2.0 or higher ? That will fix this issue!

Thanks!

tnrich avatar Feb 28 '19 22:02 tnrich

@bokuweb it looks like there are some failing tests with the latest react-rnd:

https://github.com/bokuweb/react-rnd/pull/510

https://circleci.com/gh/bokuweb/react-rnd/1340?utm_campaign=vcs-integration-link&utm_medium=referral&utm_source=github-build-link

I'm not sure why that is. I'll ask @STRML if he knows..?

tnrich avatar Feb 28 '19 22:02 tnrich

It appears there was an inadvertent breaking change in 3.2.0.

Prior to 3.2.0, if a defaultPosition were present, it became the x and y present in the callback on the initial drag and subsequent to that.

In 3.2.0, the x and y received in the callback is relative to the defaultPosition already passed. So if you pass a defaultPosition of x: 100, y:100and initiateonDragStart, the callback will contain {x: 0, y: 0}in the data. This makes sense if you considerdefaultPositionto be something more likeinitialOffset, and is required if your offset is something like, for example, {x: '10%', y: '10%'}`.

I'm going to pull the release for now and work out how to fix this. I may end up renaming defaultPosition and issue a 4.0.

STRML avatar Mar 01 '19 07:03 STRML

I've added my comments here: https://github.com/mzabriskie/react-draggable/issues/391

tnrich avatar Mar 01 '19 18:03 tnrich

@bokuweb I believe this is now possible thanks to this PR: https://github.com/mzabriskie/react-draggable/pull/393

We can now set a positionOffset using percentages

<Draggable positionOffset={{x: '-10%', y: '-10%'}} {...dragHandlers}>
          <div className="box">
            {'I have a default position based on percents {x: \'-10%\', y: \'-10%\'}, so I\'m slightly offset.'}
          </div>
        </Draggable>

tnrich avatar May 17 '19 05:05 tnrich

Hello, Do you know where I come from

wavesbig avatar May 20 '19 01:05 wavesbig

板凳宽板凳长

wavesbig avatar May 20 '19 01:05 wavesbig

@tnrich Thanks :) Is it enough to update to react-draggable3.3? If you are ok could you please create PR with new storybook story??(Please add your story here https://github.com/bokuweb/react-rnd/tree/master/stories)

bokuweb avatar May 20 '19 03:05 bokuweb

Hi @bokuweb So I tried updating react-rnd to version 3.3 of react-draggable but it wasn't enough to just do that. I think because react-rnd calculates a position offset from the parent, the initial % translation from the positionOffset prop gets canceled out. You'll need to take a look at the code I think and tinker with it a bit. I tried editing the react-rnd position offset code but was a little stumped as to how to get it to work perfectly.

tnrich avatar May 20 '19 15:05 tnrich

@tnrich Thanks for your investigation :) I'll try it later. Unfortunately I can not have enough time to fix it(I have a lot of tasks 😭 ) Please wait ...

bokuweb avatar May 20 '19 16:05 bokuweb

@bokuweb any chance you could find some time to tackle this one? Thank you!

tnrich avatar May 20 '20 21:05 tnrich

Hi @bokuweb Any updates on this? Thank you!

nvdarekar avatar Feb 01 '21 12:02 nvdarekar

Here's a link to the hand rolled solution I came up with (in dialog form) to get around this: https://teselagen.github.io/teselagen-react-components/#/ResizableDraggableDialog

And here's a link to the source code: https://github.com/TeselaGen/teselagen-react-components/blob/master/src/ResizableDraggableDialog/index.js

Basically I ended up controlling all the state and do manual checks of the window size and the contents of the dialog:

import React from "react";
import { Dialog, Classes } from "@blueprintjs/core";
import { Rnd } from "react-rnd";
import "./style.css";

const defaultDialogWidth = 400;
const defaultDialogHeight = 450;
export default class ResizableDraggableDialog extends React.Component {
  componentDidMount() {
    window.addEventListener("resize", this.onWindowResize);
    this.setDefaults();
    setTimeout(() => {
      this.setDefaults();
    }, 0);
  }
  state = {
    x: 0,
    y: 0,
    width: defaultDialogWidth,
    height: defaultDialogHeight
  };

  setDefaults = () => {
    const { width, height } = this.props;
    const { windowWidth, windowHeight } = this.getWindowWidthAndHeight();

    let heightToUse;
    if (height) {
      heightToUse = height;
    } else {
      heightToUse = (document.querySelector(".bp3-dialog-body") || {})
        .scrollHeight;
      if (heightToUse) {
        heightToUse = heightToUse + 60;
      } else {
        heightToUse = defaultDialogHeight;
      }
    }
    let widthToUse;
    if (width) {
      widthToUse = width;
    } else {
      widthToUse = defaultDialogWidth;
    }

    this.setState({
      x: Math.round(Math.max((windowWidth - widthToUse) / 2, 0)),
      y: Math.round(Math.max((windowHeight - heightToUse) / 2, 0)),
      width: Math.min(widthToUse, windowWidth),
      height: Math.min(Math.max(defaultDialogHeight, heightToUse), windowHeight)
    });
  };
  onWindowResize = () => {
    this.setDefaults();
  };
  componentWillUnmount() {
    window.removeEventListener("resize", this.onWindowResize);
  }

  getWindowWidthAndHeight = () => {
    const w = window,
      d = document,
      e = d.documentElement,
      g = d.getElementsByTagName("body")[0],
      windowWidth = w.innerWidth || e.clientWidth || g.clientWidth,
      windowHeight = w.innerHeight || e.clientHeight || g.clientHeight;
    return {
      windowWidth,
      windowHeight: windowHeight - 20 //add a small correction here
    };
  };

  render() {
    const { width, height, RndProps, ...rest } = this.props;
    const { windowWidth, windowHeight } = this.getWindowWidthAndHeight();
    return (
      <div
        className="tg-bp3-dialog-resizable-draggable"
        style={{ top: 0, left: 0, position: "fixed" }}
      >
        <Rnd
          enableResizing={{
            bottomLeft: true,
            bottomRight: true,
            topLeft: true,
            topRight: true
          }}
          maxHeight={windowHeight}
          maxWidth={windowWidth}
          bounds="window"
          size={{ width: this.state.width, height: this.state.height }}
          position={{ x: this.state.x, y: this.state.y }}
          onDragStop={(e, d) => {
            this.setState({ x: d.x, y: d.y });
          }}
          onResizeStop={(e, direction, ref, delta, position) => {
            this.setState({
              width: ref.style.width,
              height: ref.style.height,
              ...position
            });
          }}
          dragHandleClassName={Classes.DIALOG_HEADER}
          {...RndProps}
        >
          <Dialog
            enforceFocus={false}
            hasBackdrop={false}
            usePortal={false}
            canEscapeKeyClose={true}
            {...rest}
          />
        </Rnd>
      </div>
    );
  }
}

tnrich avatar Feb 03 '21 02:02 tnrich