index-en-US.md 7.8 KB


localeCode: en-US order: 26 category: Plus title: DragMove icon: doc-dragmove dir: column brief: Set elements to change their position by dragging

showNew: true

When to use

It is used to set the element that can be dragged to change its position. It supports limiting the drag range and customizing the elements that trigger dragging.

Demos

How to introduce

DragMove supported from v2.71.0.

import { DragMove } from '@douyinfe/semi-ui';

Basic usage

Elements wrapped by DragMove will be able to change their position by dragging.

Notice

  1. DragMove will set the draggable element to absolute positioning
  2. DragMove needs to apply DOM event listeners to children. If the child element is a custom component, you need to ensure that it can pass properties to the underlying DOM element. The following types of children are supported:

    1. Class Component, it is not mandatory to bind ref, but you need to ensure that props can be transparently transmitted to the real DOM node
    2. Use the functional component wrapped by forwardRef to transparently transmit props and ref to the real DOM node in children
    3. Real DOM nodes, such as span, div, p...

      import React, { useRef, useEffect } from 'react';
      import { DragMove } from '@douyinfe/semi-ui';
      
      function Demo() {
      return (
      <DragMove>
      <div 
      style={{ backgroundColor: 'var(--semi-color-primary)',width: 80, height: 80, 
        display: 'flex', alignItems: 'center',justifyContent: 'center', 
        borderRadius: 10, fontWeight: 500,
        position: 'absolute',  color: 'rgba(var(--semi-white), 1)'
      }} 
      >Drag me</div>
      </DragMove>
      );
      }
      
      

Limit drag range

Passing in constrainer, this function returns the elements that limit the draggable range.

Note: The elements returned by the constrainer need to be positioned relative

import React, { useRef, useEffect } from 'react';
import { DragMove } from '@douyinfe/semi-ui';

function Demo() {
  const containerRef = React.useRef();

  return (
    <div 
      style={{ 
        backgroundColor: 'rgba(var(--semi-grey-2), 1)', 
        width: 300, height: 300, padding: 5, position: 'relative', 
        color: 'rgba(var(--semi-white), 1)', fontWeight: 500,
      }} 
      ref={containerRef}
    >
      <span>Constrainer</span>
      <DragMove
        constrainer={() => containerRef.current}
      >
      <div 
          style={{ backgroundColor: 'var(--semi-color-primary)', 
            width: 80, height: 80, borderRadius: 10,
            display: 'flex', alignItems: 'center', justifyContent: 'center',
            position: 'absolute', top: 80, left: 80,
          }}
        >Drag me</div>
      </DragMove>
    </div>
  )
}

Customize elements that trigger dragging

Passing in handler, this function returns the element that triggered the drag. If not set, you can click anywhere to drag; if set, only the part of the element returned by the handler can be dragged.

import React, { useRef, useEffect } from'react';
import { IconTransparentStroked } from '@douyinfe/semi-icons';
import { DragMove } from '@douyinfe/semi-ui';

function Demo(){
  const handlerRef = React.useRef();
  const containerRef = React.useRef();

  return (
    <div 
      style={{ backgroundColor: 'rgba(var(--semi-grey-2), 1)', 
        width: 300, height: 300, padding: 5, position: 'relative', 
        color: 'rgba(var(--semi-white), 1)', fontWeight: 500,
      }} 
      ref={containerRef}
    >
      <span>Constrainer</span>
      <DragMove
        handler={() => handlerRef.current}
        constrainer={() => containerRef.current}
      >
        <div 
          style={{ 
            backgroundColor: 'var(--semi-color-primary)', 
            width: 80, height: 80, borderRadius: 10,
            position: 'absolute', top: 50, left: 50,
            display: 'flex', alignItems: 'center', justifyContent: 'center',
          }}
        >
          <div 
              style={{ width: 'fit-content', height: 'fit-content' }} 
              ref={handlerRef}
          ><IconTransparentStroked size={'large'}/></div>
        </div>
      </DragMove>
    </div>
  )
}

Customize position processing after dragging

You can customize the position processing after dragging through customMove. After this parameter is set, the DragMove component will only return the calculated position through the parameters without setting it. The user can set the new position as needed.

import React, { useRef, useEffect } from'react';
import { DragMove } from '@douyinfe/semi-ui';

function CustomMove() {
  const containerRef = React.useRef();
  const elementRef = React.useRef();
  const startPoint = React.useRef();

  const customMove = useCallback((element, top, left) => {
    if (left + 100 > containerRef.current.offsetWidth) {
      element.style.right = `${containerRef.current.offsetWidth - left - element.offsetWidth}px`
      element.style.left = 'auto';
    } else {
      element.style.left = left + 'px';
    } 
    element.style.top = top + 'px';
  }, [])

  const onMouseDown = useCallback((e) => {
    startPoint.current = {
      x: e.clientX,
      y: e.clientY,
    }
  }, []);

  const onMouseUp = useCallback((e) => {
    if (startPoint.current) {
      const { x, y } = startPoint.current;
      if (Math.abs(e.clientX - x) < 5 && Math.abs(e.clientY - y) < 5) {
        if (elementRef.current.style.width === '50px') {
          elementRef.current.style.width = '100px';
        } else {
          elementRef.current.style.width = '50px';
        }
      }
    }
    startPoint.current = null;
  }, []);

  return (
    <>
      <span>Click on the blue color block to change the width. The blue color block will not exceed the range limit before and after the change.</span>
      <br /><br />
      <div 
        style={{ 
          backgroundColor: 'rgba(var(--semi-grey-2), 1)', width: 300, height: 300, 
          position: 'relative', padding: 10,
          color: 'rgba(var(--semi-white), 1)', fontWeight: 500,
        }} 
        ref={containerRef}
      >
        <span>Constrainer</span>
        <DragMove
          constrainer={() => containerRef.current}
          customMove={customMove}
        >
          <div
            style={{ backgroundColor: 'var(--semi-color-primary)',width: 50, height: 50,
              display: 'flex', alignItems: 'center',justifyContent: 'center',
              position: 'absolute', top: 50, left: 50, borderRadius: 10, padding: 5
            }}
            onMouseDown={onMouseDown}
            onMouseUp={onMouseUp}
            ref={elementRef}
          >Drag me</div>
        </DragMove>
      </div> 
    </>
  )
}

API

Property Description Type Default value
allowInputDrag Whether to allow dragging when clicking on native input/textarea boolean false
allowMove Determine whether dragging is allowed when clicking/touching. (event: TouchEvent |MouseEvent, element: ReactNode) => boolean -
constrainer Returns the element that limits the draggable range. () => ReactNode | 'parent' -
customMove Customize position processing after dragging (element: ReactNode, top: number, left: number) => void -
handler Returns the element that triggers dragging. () => ReactNode -
onMouseDown Callback when mouse is pressed (e: MouseEvent) => void -
onMouseMove Callback when mouse moves (e: MouseEvent) => void -
onMouseUp Callback when mouse is raised (e: MouseEvent) => void -
onTouchCancel Callback when touch cancels (e: TouchEvent) => void -
onTouchEnd callback when touch ends (e: TouchEvent) => void -
onTouchMove Callback when touch moves (e: TouchEvent) => void -
onTouchStart Callback when touch starts (e: TouchEvent) => void -