index.ts 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. import DragMoveFoundation, { DragMoveAdapter } from '@douyinfe/semi-foundation/dragMove/foundation';
  2. import BaseComponent from '../_base/baseComponent';
  3. import { ReactNode } from 'react';
  4. import PropTypes from 'prop-types';
  5. import React from 'react';
  6. import { isHTMLElement } from '../_base/reactUtils';
  7. import ReactDOM from 'react-dom';
  8. export interface DragMoveProps {
  9. // The element that triggers the drag event,default is element
  10. handler?: () => ReactNode;
  11. // The element that constrains the movement range, This element requires relative positioning
  12. constrainer?: () => ReactNode | 'parent';
  13. children?: ReactNode | undefined | any;
  14. onMouseDown?: (e: MouseEvent) => void;
  15. onMouseMove?: (e: MouseEvent) => void;
  16. onMouseUp?: (e: MouseEvent) => void;
  17. onTouchStart?: (e: TouchEvent) => void;
  18. onTouchMove?: (e: TouchEvent) => void;
  19. onTouchEnd?: (e: TouchEvent) => void;
  20. onTouchCancel?: (e: TouchEvent) => void;
  21. // Determine whether dragging is triggered when the mouse is pressed.
  22. // Return true to trigger dragging. Return false to not trigger dragging.
  23. allowMove?: (e: MouseEvent | TouchEvent, element: HTMLElement) => boolean;
  24. // customize move behavior
  25. customMove?: (e: HTMLElement, top: number, left: number) => void
  26. }
  27. export default class DragMove extends BaseComponent<DragMoveProps, null> {
  28. static propTypes = {
  29. children: PropTypes.node,
  30. handler: PropTypes.func,
  31. allowInputDrag: PropTypes.bool,
  32. constrainNode: PropTypes.func,
  33. onMouseDown: PropTypes.func,
  34. onMouseMove: PropTypes.func,
  35. onMouseUp: PropTypes.func,
  36. onTouchStart: PropTypes.func,
  37. onTouchMove: PropTypes.func,
  38. onTouchEnd: PropTypes.func,
  39. onTouchCancel: PropTypes.func,
  40. }
  41. static __SemiComponentName__ = "DragMove";
  42. static defaultProps = {
  43. allowInputDrag: false,
  44. };
  45. constructor(props: DragMoveProps) {
  46. super(props);
  47. this.elementRef = React.createRef();
  48. this.foundation = new DragMoveFoundation(this.adapter);
  49. }
  50. elementRef: React.RefObject<unknown>;
  51. foundation: DragMoveFoundation;
  52. get adapter(): DragMoveAdapter<DragMoveProps, null> {
  53. return {
  54. ...super.adapter,
  55. getDragElement: () => {
  56. let elementDom = this.elementRef.current;
  57. if (!isHTMLElement(elementDom)) {
  58. elementDom = ReactDOM.findDOMNode(elementDom as React.ReactInstance);
  59. }
  60. return elementDom as HTMLElement;
  61. },
  62. getConstrainer: () => {
  63. const { constrainer } = this.props;
  64. if (typeof constrainer === 'string' && constrainer === 'parent') {
  65. return (this.elementRef.current as HTMLElement)?.parentNode as HTMLElement;
  66. } else if (typeof constrainer === 'function') {
  67. return constrainer() as any;
  68. } else {
  69. return null;
  70. }
  71. },
  72. getHandler: () => {
  73. const { handler } = this.props;
  74. if (typeof handler === 'function') {
  75. return handler() as any;
  76. } else {
  77. return this.adapter.getDragElement() as HTMLElement;
  78. }
  79. },
  80. notifyMouseDown: (e: MouseEvent) => {
  81. this.props.onMouseDown && this.props.onMouseDown(e);
  82. },
  83. notifyMouseMove: (e: MouseEvent) => {
  84. this.props.onMouseMove && this.props.onMouseMove(e);
  85. },
  86. notifyMouseUp: (e: MouseEvent) => {
  87. this.props.onMouseUp && this.props.onMouseUp(e);
  88. },
  89. notifyTouchStart: (e: TouchEvent) => {
  90. this.props.onTouchStart && this.props.onTouchStart(e);
  91. },
  92. notifyTouchMove: (e: TouchEvent) => {
  93. this.props.onTouchMove && this.props.onTouchMove(e);
  94. },
  95. notifyTouchEnd: (e: TouchEvent) => {
  96. this.props.onTouchEnd && this.props.onTouchEnd(e);
  97. },
  98. notifyTouchCancel: (e: TouchEvent) => {
  99. this.props.onTouchCancel && this.props.onTouchCancel(e);
  100. },
  101. };
  102. }
  103. componentDidMount(): void {
  104. this.foundation.init();
  105. }
  106. componentWillUnmount(): void {
  107. this.foundation.destroy();
  108. }
  109. render() {
  110. const { children } = this.props;
  111. const newChildren = React.cloneElement(children, {
  112. ref: (node: React.ReactNode) => {
  113. (this.elementRef as any).current = node;
  114. // Call the original ref, if any
  115. const { ref } = children as any;
  116. if (typeof ref === 'function') {
  117. ref(node);
  118. } else if (ref && typeof ref === 'object') {
  119. ref.current = node;
  120. }
  121. },
  122. });
  123. return newChildren;
  124. }
  125. }