Как я могу добавить и удалить макет реагировать и сортировать макет с возможностью изменения размера - PullRequest
0 голосов
/ 15 октября 2018

Я ищу помощь.Я делаю сортируемый и изменяемый размер макета, у меня есть, но теперь мне нужно добавить кнопку для каждого макета, чтобы удалить их, и я не вижу, как я могу это сделать, потому что я не вижу, как я могу взятьключ.Также кнопка для добавления новых макетов.Я использую Rnd lib, реагирование и машинопись.Здесь я даю код, который у меня есть, вся помощь приветствуется, спасибо ^^

Код:

Multicontroller.tsx

    import * as React from "react";
    import { Rnd } from "./index";
    import { style } from "./styles";

    import ClearIcon from '@material-ui/icons/Clear';


    type State = {
      rnds: {
        x: number;
        y: number;
        width: number;
        height: number;
      }[];
    }

    export default class Example extends React.Component<{}, State> {

      constructor(props:any) {
        super(props);

        this.state = {
          rnds: [0,1,2].map(i => ({
            width: 680,
            height: 180,
            x: 100,
            y: 100,
          })),
      }
    }

      add(){
        let z: number;
        z=3
        {[z].map(i => (
          <Rnd
            key={`rnd${i}`}
            style={style}
            size={{
              width: this.state.rnds[i].width,
              height: this.state.rnds[i].height,
            }}
            position={{
              x: this.state.rnds[i].x,
              y: this.state.rnds[i].y,
            }}
            onDragStop={(e, d) => {
              const rnds = [...this.state.rnds];
              rnds[i] = { ...rnds[i], x: d.x, y: d.y };
              this.setState({ rnds });
            }}
            onResize={(e, direction, ref, delta, position) => {
              const rnds = [...this.state.rnds];
              rnds[i] = {
                ...rnds[i],
                width: ref.offsetWidth,
                height: ref.offsetHeight,
                ...position,
              };
              this.setState({
                rnds,
              });
            }}
          >

          <button onClick={(e) => this.remove(e)} value={`rnd${i}`}><ClearIcon></ClearIcon></button>
        </Rnd>
        ))}

      }

      remove(e: React.MouseEvent<HTMLButtonElement>){
        const index = e.currentTarget.getAttribute("value")
        let id: string;
        index ? id = index : id = "no value"
        console.log(id)

      }

      render() {
        return (
          <div style={{ padding: '70px' }}>
            <button onClick={() => this.add()}>Add</button>
            {[0].map(i => (
              <Rnd
                key={`rnd${i}`}
                style={style}
                size={{
                  width: this.state.rnds[i].width,
                  height: this.state.rnds[i].height,
                }}
                position={{
                  x: this.state.rnds[i].x,
                  y: this.state.rnds[i].y,
                }}
                onDragStop={(e, d) => {
                  const rnds = [...this.state.rnds];
                  rnds[i] = { ...rnds[i], x: d.x, y: d.y };
                  this.setState({ rnds });
                }}
                onResize={(e, direction, ref, delta, position) => {
                  const rnds = [...this.state.rnds];
                  rnds[i] = {
                    ...rnds[i],
                    width: ref.offsetWidth,
                    height: ref.offsetHeight,
                    ...position,
                  };
                  this.setState({
                    rnds,
                  });
                }}
              >

              <button onClick={(e) => this.remove(e)} value={`rnd${i}`}><ClearIcon></ClearIcon></button>
            </Rnd>
            ))}

        {[1].map(i => (
              <Rnd
                key={`rnd${i}`}
                style={style}
                size={{
                  width: this.state.rnds[i].width -380,
                  height: this.state.rnds[i].height +120,
                }}
                position={{
                  x: this.state.rnds[i].x,
                  y: this.state.rnds[i].y,
                }}
                onDragStop={(e, d) => {
                  const rnds = [...this.state.rnds];
                  rnds[i] = { ...rnds[i], x: d.x, y: d.y };
                  this.setState({ rnds });
                }}
                onResize={(e, direction, ref, delta, position) => {
                  const rnds = [...this.state.rnds];
                  rnds[i] = {
                    ...rnds[i],
                    width: ref.offsetWidth +380,
                    height: ref.offsetHeight -120,
                    ...position,
                  };
                  this.setState({
                    rnds,
                  });
                }}
              >
              <button onClick={(e) => this.remove(e)} value={`rnd${i}`}><ClearIcon></ClearIcon></button>
            </Rnd>
            ))}
        {[2].map(i => (
              <Rnd
                key={`rnd${i}`}
                style={style}
                size={{
                  width: this.state.rnds[i].width-80,
                  height: this.state.rnds[i].height+100,
                }}
                position={{
                  x: this.state.rnds[i].x,
                  y: this.state.rnds[i].y,
                }}
                onDragStop={(e, d) => {
                  const rnds = [...this.state.rnds];
                  rnds[i] = { ...rnds[i], x: d.x, y: d.y };
                  this.setState({ rnds });
                }}
                onResize={(e, direction, ref, delta, position) => {
                  const rnds = [...this.state.rnds];
                  rnds[i] = {
                    ...rnds[i],
                    width: ref.offsetWidth+80,
                    height: ref.offsetHeight-100,
                    ...position,
                  };
                  this.setState({
                    rnds,
                  });
                }}
              >

              <button onClick={(e) => this.remove(e)} value={`rnd${i}`}><ClearIcon></ClearIcon></button>
            </Rnd>
            ))}
          </div>
        )
      }
    }

style.ts

       export const style = {
        display: "flex",
        alignItems: "center",
        justifyContent: "center",
        border: "solid 1px #ddd",
        background: "#AAAAAA",
      };

      export const parentBoundary = {
        background: "#eee",
        width: "100%",
        height: "100%",
      };

      export const selectorBoundary = {
        background: "#d1d8ff",
        padding: "20px",
        width: "100%",
        height: "100%",
      };
      export const Xbuttons ={
        alignItems:top
      };

index.tsx

        import * as React from "react";
    import Draggable from "react-draggable";
    import Resizable, { ResizableDirection } from "re-resizable";

    export type Grid = [number, number];

    export type Position = {
      x: number;
      y: number;
    };

    export type DraggableData = {
      node: HTMLElement;
      deltaX: number;
      deltaY: number;
      lastX: number;
      lastY: number;
    } & Position;

    export type RndDragCallback = (e: Event, data: DraggableData) => void | false;

    export type RndResizeStartCallback = (
      e: React.MouseEvent<HTMLDivElement> | React.TouchEvent<HTMLDivElement>,
      dir: ResizableDirection,
      elementRef: HTMLDivElement,
    ) => void;

    export type ResizableDelta = {
      width: number;
      height: number;
    };

    export type RndResizeCallback = (
      e: MouseEvent | TouchEvent,
      dir: ResizableDirection,
      elementRef: HTMLDivElement,
      delta: ResizableDelta,
      position: Position,
    ) => void;

    type Size = {
      width: string | number;
      height: string | number;
    };

    type State = {
      original: Position;
      bounds: {
        top: number;
        right: number;
        bottom: number;
        left: number;
      };
      maxWidth?: number | string;
      maxHeight?: number | string;
    };

    type MaxSize = {
      maxWidth: number | string;
      maxHeight: number | string;
    };

    export type ResizeEnable = {
      bottom?: boolean;
      bottomLeft?: boolean;
      bottomRight?: boolean;
      left?: boolean;
      right?: boolean;
      top?: boolean;
      topLeft?: boolean;
      topRight?: boolean;
    };

    export type HandleClasses = {
      bottom?: string;
      bottomLeft?: string;
      bottomRight?: string;
      left?: string;
      right?: string;
      top?: string;
      topLeft?: string;
      topRight?: string;
    };

    export type HandleStyles = {
      bottom?: React.CSSProperties;
      bottomLeft?: React.CSSProperties;
      bottomRight?: React.CSSProperties;
      left?: React.CSSProperties;
      right?: React.CSSProperties;
      top?: React.CSSProperties;
      topLeft?: React.CSSProperties;
      topRight?: React.CSSProperties;
    };

    export interface Props {
      dragGrid?: Grid;
      default?: {
        x: number;
        y: number;
      } & Size;
      position?: {
        x: number;
        y: number;
      };
      size?: Size;
      resizeGrid?: Grid;
      bounds?: string;
      onMouseDown?: (e: MouseEvent) => void;
      onResizeStart?: RndResizeStartCallback;
      onResize?: RndResizeCallback;
      onResizeStop?: RndResizeCallback;
      onDragStart?: RndDragCallback;
      onDrag?: RndDragCallback;
      onDragStop?: RndDragCallback;
      className?: string;
      style?: React.CSSProperties;
      children?: React.ReactNode;
      enableResizing?: ResizeEnable;
      resizeHandleClasses?: HandleClasses;
      resizeHandleStyles?: HandleStyles;
      resizeHandleWrapperClass?: string;
      resizeHandleWrapperStyle?: React.CSSProperties;
      lockAspectRatio?: boolean | number;
      lockAspectRatioExtraWidth?: number;
      lockAspectRatioExtraHeight?: number;
      maxHeight?: number | string;
      maxWidth?: number | string;
      minHeight?: number | string;
      minWidth?: number | string;
      dragAxis?: "x" | "y" | "both" | "none";
      dragHandleClassName?: string;
      disableDragging?: boolean;
      cancel?: string;
      enableUserSelectHack?: boolean;
      [key: string]: any;
    }

    const resizableStyle = {
      width: "auto" as "auto",
      height: "auto" as "auto",
      display: "inline-block" as "inline-block",
      position: "absolute" as "absolute",
      top: 0,
      left: 0,
    };

    export class Rnd extends React.Component<Props, State> {
      static defaultProps = {
        maxWidth: Number.MAX_SAFE_INTEGER,
        maxHeight: Number.MAX_SAFE_INTEGER,
        onResizeStart: () => {},
        onResize: () => {},
        onResizeStop: () => {},
        onDragStart: () => {},
        onDrag: () => {},
        onDragStop: () => {},
      };
      resizable!: Resizable;
      draggable!: Draggable;
      isResizing = false;

      constructor(props: Props) {
        super(props);
        this.state = {
          original: {
            x: 0,
            y: 0,
          },
          bounds: {
            top: 0,
            right: 0,
            bottom: 0,
            left: 0,
          },
          maxWidth: props.maxWidth,
          maxHeight: props.maxHeight,
        };

        this.onResizeStart = this.onResizeStart.bind(this);
        this.onResize = this.onResize.bind(this);
        this.onResizeStop = this.onResizeStop.bind(this);
        this.onDragStart = this.onDragStart.bind(this);
        this.onDrag = this.onDrag.bind(this);
        this.onDragStop = this.onDragStop.bind(this);
        this.getMaxSizesFromProps = this.getMaxSizesFromProps.bind(this);
      }

      componentDidMount() {
        const { left, top } = this.getOffsetFromParent();
        const { x, y } = this.getDraggablePosition();
        this.draggable.setState({
          x: x - left,
          y: y - top,
        });
        // HACK: Apply position adjustment
        this.forceUpdate();
      }

      // HACK: To get `react-draggable` state x and y.
      getDraggablePosition(): { x: number; y: number } {
        const { x, y } = (this.draggable as any).state;
        return { x, y };
      }

      getParent() {
        return this.resizable && (this.resizable as any).parentNode;
      }

      getParentSize(): { width: number; height: number } {
        return (this.resizable as any).getParentSize();
      }

      getMaxSizesFromProps(): MaxSize {
        const maxWidth = typeof this.props.maxWidth === "undefined" ? Number.MAX_SAFE_INTEGER : this.props.maxWidth;
        const maxHeight = typeof this.props.maxHeight === "undefined" ? Number.MAX_SAFE_INTEGER : this.props.maxHeight;
        return { maxWidth, maxHeight };
      }

      getSelfElement(): Element {
        return this.resizable && this.resizable.resizable;
      }

      onDragStart(e: Event, data: DraggableData) {
        if (this.props.onDragStart) {
          this.props.onDragStart(e, data);
        }
        if (!this.props.bounds) return;
        const parent = this.getParent();
        let boundary;
        if (this.props.bounds === "parent") {
          boundary = parent;
        } else if (this.props.bounds === "body") {
          boundary = document.body;
        } else if (this.props.bounds === "window") {
          if (!this.resizable) return;
          return this.setState({
            bounds: {
              top: 0,
              right: window.innerWidth - this.resizable.size.width,
              bottom: window.innerHeight - this.resizable.size.height,
              left: 0,
            },
          });
        } else {
          boundary = document.querySelector(this.props.bounds);
        }
        if (!(boundary instanceof HTMLElement) || !(parent instanceof HTMLElement)) {
          return;
        }
        const boundaryRect = boundary.getBoundingClientRect();
        const boundaryLeft = boundaryRect.left;
        const boundaryTop = boundaryRect.top;
        const parentRect = parent.getBoundingClientRect();
        const parentLeft = parentRect.left;
        const parentTop = parentRect.top;
        const left = boundaryLeft - parentLeft;
        const top = boundaryTop - parentTop;
        if (!this.resizable) return;
        const offset = this.getOffsetFromParent();
        this.setState({
          bounds: {
            top: top - offset.top,
            right: left + (boundary.offsetWidth - this.resizable.size.width) - offset.left,
            bottom: top + (boundary.offsetHeight - this.resizable.size.height) - offset.top,
            left: left - offset.left,
          },
        });
      }

      onDrag(e: Event, data: DraggableData) {
        if (this.props.onDrag) {
          const offset = this.getOffsetFromParent();
          this.props.onDrag(e, { ...data, x: data.x - offset.left, y: data.y - offset.top });
        }
      }

      onDragStop(e: Event, data: DraggableData) {
        if (this.props.onDragStop) {
          const { left, top } = this.getOffsetFromParent();
          this.props.onDragStop(e, { ...data, x: data.x + left, y: data.y + top });
        }
      }

      onResizeStart(
        e: React.MouseEvent<HTMLDivElement> | React.TouchEvent<HTMLDivElement>,
        dir: ResizableDirection,
        elementRef: HTMLDivElement,
      ) {
        e.stopPropagation();
        this.isResizing = true;
        this.setState({
          original: this.getDraggablePosition(),
        });
        if (this.props.bounds) {
          const parent = this.getParent();
          let boundary;
          if (this.props.bounds === "parent") {
            boundary = parent;
          } else if (this.props.bounds === "body") {
            boundary = document.body;
          } else if (this.props.bounds === "window") {
            boundary = window;
          } else {
            boundary = document.querySelector(this.props.bounds);
          }

          const self = this.getSelfElement();
          if (
            self instanceof Element &&
            (boundary instanceof HTMLElement || boundary === window) &&
            parent instanceof HTMLElement
          ) {
            let { maxWidth, maxHeight } = this.getMaxSizesFromProps();
            const parentSize = this.getParentSize();
            if (maxWidth && typeof maxWidth === "string") {
              if (maxWidth.endsWith("%")) {
                const ratio = Number(maxWidth.replace("%", "")) / 100;
                maxWidth = parentSize.width * ratio;
              } else if (maxWidth.endsWith("px")) {
                maxWidth = Number(maxWidth.replace("px", ""));
              }
            }
            if (maxHeight && typeof maxHeight === "string") {
              if (maxHeight.endsWith("%")) {
                const ratio = Number(maxHeight.replace("%", "")) / 100;
                maxHeight = parentSize.width * ratio;
              } else if (maxHeight.endsWith("px")) {
                maxHeight = Number(maxHeight.replace("px", ""));
              }
            }
            const selfRect = self.getBoundingClientRect();
            const selfLeft = selfRect.left;
            const selfTop = selfRect.top;
            const boundaryRect = this.props.bounds === "window" ? { left: 0, top: 0 } : boundary.getBoundingClientRect();
            const boundaryLeft = boundaryRect.left;
            const boundaryTop = boundaryRect.top;
            const offsetWidth = this.props.bounds === "window" ? window.innerWidth : boundary.offsetWidth;
            const offsetHeight = this.props.bounds === "window" ? window.innerHeight : boundary.offsetHeight;
            const hasLeft = dir.toLowerCase().endsWith("left");
            const hasRight = dir.toLowerCase().endsWith("right");
            const hasTop = dir.startsWith("top");
            const hasBottom = dir.startsWith("bottom");
            if (hasLeft && this.resizable) {
              const max = selfLeft - boundaryLeft + this.resizable.size.width;
              this.setState({ maxWidth: max > Number(maxWidth) ? maxWidth : max });
            }
            // INFO: To set bounds in `lock aspect ratio with bounds` case. See also that story.
            if (hasRight || (this.props.lockAspectRatio && !hasLeft)) {
              const max = offsetWidth + (boundaryLeft - selfLeft);
              this.setState({ maxWidth: max > Number(maxWidth) ? maxWidth : max });
            }
            if (hasTop && this.resizable) {
              const max = selfTop - boundaryTop + this.resizable.size.height;
              this.setState({
                maxHeight: max > Number(maxHeight) ? maxHeight : max,
              });
            }
            // INFO: To set bounds in `lock aspect ratio with bounds` case. See also that story.
            if (hasBottom || (this.props.lockAspectRatio && !hasTop)) {
              const max = offsetHeight + (boundaryTop - selfTop);
              this.setState({
                maxHeight: max > Number(maxHeight) ? maxHeight : max,
              });
            }
          }
        } else {
          this.setState({
            maxWidth: this.props.maxWidth,
            maxHeight: this.props.maxHeight,
          });
        }
        if (this.props.onResizeStart) {
          this.props.onResizeStart(e, dir, elementRef);
        }
      }

      onResize(
        e: MouseEvent | TouchEvent,
        direction: ResizableDirection,
        elementRef: HTMLDivElement,
        delta: { height: number; width: number },
      ) {
        let x;
        let y;
        const offset = this.getOffsetFromParent();
        if (/left/i.test(direction)) {
          x = this.state.original.x - delta.width;
          // INFO: If uncontrolled component, apply x position by resize to draggable.
          if (!this.props.position) {
            this.draggable.setState({ x });
          }
          x += offset.left;
        }
        if (/top/i.test(direction)) {
          y = this.state.original.y - delta.height;
          // INFO: If uncontrolled component, apply y position by resize to draggable.
          if (!this.props.position) {
            this.draggable.setState({ y });
          }
          y += offset.top;
        }
        if (this.props.onResize) {
          if (typeof x === "undefined") {
            x = this.getDraggablePosition().x + offset.left;
          }
          if (typeof y === "undefined") {
            y = this.getDraggablePosition().y + offset.top;
          }
          this.props.onResize(e, direction, elementRef, delta, {
            x,
            y,
          });
        }
      }

      onResizeStop(
        e: MouseEvent | TouchEvent,
        direction: ResizableDirection,
        elementRef: HTMLDivElement,
        delta: { height: number; width: number },
      ) {
        this.isResizing = false;
        const { maxWidth, maxHeight } = this.getMaxSizesFromProps();
        this.setState({ maxWidth, maxHeight });
        if (this.props.onResizeStop) {
          const position: Position = this.getDraggablePosition();
          this.props.onResizeStop(e, direction, elementRef, delta, position);
        }
      }

      updateSize(size: { width: number | string; height: number | string }) {
        if (!this.resizable) return;
        this.resizable.updateSize({ width: size.width, height: size.height });
      }

      updatePosition(position: Position) {
        this.draggable.setState(position);
      }

      getOffsetFromParent(): { top: number; left: number } {
        const parent = this.getParent();
        if (!parent) {
          return {
            top: 0,
            left: 0,
          };
        }
        const parentRect = parent.getBoundingClientRect();
        const parentLeft = parentRect.left;
        const parentTop = parentRect.top;
        const selfRect = this.getSelfElement().getBoundingClientRect();
        const position = this.getDraggablePosition();
        return {
          left: selfRect.left - parentLeft - position.x,
          top: selfRect.top - parentTop - position.y,
        };
      }

      render() {
        const {
          disableDragging,
          style,
          dragHandleClassName,
          position,
          onMouseDown,
          dragAxis,
          dragGrid,
          bounds,
          enableUserSelectHack,
          cancel,
          children,
          onResizeStart,
          onResize,
          onResizeStop,
          onDragStart,
          onDrag,
          onDragStop,
          resizeHandleStyles,
          resizeHandleClasses,
          enableResizing,
          resizeGrid,
          resizeHandleWrapperClass,
          resizeHandleWrapperStyle,
          ...resizableProps
        } = this.props;
        const defaultValue = this.props.default ? { ...this.props.default } : undefined;
        // Remove unknown props, see also https://reactjs.org/warnings/unknown-prop.html
        delete resizableProps.default;

        const cursorStyle = disableDragging || dragHandleClassName ? { cursor: "normal" } : { cursor: "move" };
        const innerStyle = {
          ...resizableStyle,
          ...cursorStyle,
          ...style,
        };
        const { left, top } = this.getOffsetFromParent();
        let draggablePosition;
        if (position) {
          draggablePosition = {
            x: position.x - left,
            y: position.y - top,
          };
        }
        return (
          <Draggable
            ref={c => {
              if (c) {
                this.draggable = c;
              }
            }}
            handle={dragHandleClassName ? `.${dragHandleClassName}` : undefined}
            defaultPosition={defaultValue}
            onMouseDown={onMouseDown}
            onStart={this.onDragStart}
            onDrag={this.onDrag}
            onStop={this.onDragStop}
            axis={dragAxis}
            disabled={disableDragging}
            grid={dragGrid}
            bounds={bounds ? this.state.bounds : undefined}
            position={draggablePosition}
            enableUserSelectHack={enableUserSelectHack}
            cancel={cancel}
          >
            <Resizable
              {...resizableProps}
              ref={c => {
                if (c) {
                  this.resizable = c;
                }
              }}
              defaultSize={defaultValue}
              size={this.props.size}
              enable={enableResizing}
              onResizeStart={this.onResizeStart}
              onResize={this.onResize}
              onResizeStop={this.onResizeStop}
              style={innerStyle}
              minWidth={this.props.minWidth}
              minHeight={this.props.minHeight}
              maxWidth={this.isResizing ? this.state.maxWidth : this.props.maxWidth}
              maxHeight={this.isResizing ? this.state.maxHeight : this.props.maxHeight}
              grid={resizeGrid}
              handleWrapperClass={resizeHandleWrapperClass}
              handleWrapperStyle={resizeHandleWrapperStyle}
              lockAspectRatio={this.props.lockAspectRatio}
              lockAspectRatioExtraWidth={this.props.lockAspectRatioExtraWidth}
                  lockAspectRatioExtraHeight{this.props.lockAspectRatioExtraHeight}
              handleStyles={resizeHandleStyles}
              handleClasses={resizeHandleClasses}
            >
              {children}
            </Resizable>
          </Draggable>
        );
      }
    }

Спасибо за помощь!

...