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

Components: Add types to Draggable #29792

Merged
merged 2 commits into from
Mar 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 32 additions & 4 deletions packages/components/src/draggable/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,28 @@ const cloneHeightTransformationBreakpoint = 700;
const clonePadding = 0;
const bodyClass = 'is-dragging-components-draggable';

/**
* @typedef RenderProp
* @property {(event: import('react').DragEvent) => void} onDraggableStart `onDragStart` handler.
* @property {(event: import('react').DragEvent) => void} onDraggableEnd `onDragEnd` handler.
*/

/**
* @typedef Props
* @property {(props: RenderProp) => JSX.Element | null} children Children.
* @property {(event: import('react').DragEvent) => void} [onDragStart] Callback when dragging starts.
* @property {(event: import('react').DragEvent) => void} [onDragOver] Callback when dragging happens over the document.
* @property {(event: import('react').DragEvent) => void} [onDragEnd] Callback when dragging ends.
* @property {string} [cloneClassname] Classname for the cloned element.
* @property {string} [elementId] ID for the element.
* @property {any} [transferData] Transfer data for the drag event.
sarayourfriend marked this conversation as resolved.
Show resolved Hide resolved
* @property {import('react').ReactNode} __experimentalDragComponent Component to show when dragging.
*/

/**
* @param {Props} props
* @return {JSX.Element} A draggable component.
*/
export default function Draggable( {
children,
onDragStart,
Expand All @@ -19,19 +41,20 @@ export default function Draggable( {
transferData,
__experimentalDragComponent: dragComponent,
} ) {
const dragComponentRef = useRef();
/** @type {import('react').MutableRefObject<HTMLDivElement | null>} */
const dragComponentRef = useRef( null );
const cleanup = useRef( () => {} );

/**
* Removes the element clone, resets cursor, and removes drag listener.
*
* @param {Object} event The non-custom DragEvent.
* @param {import('react').DragEvent} event The non-custom DragEvent.
*/
function end( event ) {
event.preventDefault();
cleanup.current();

if ( onDragOver ) {
if ( onDragEnd ) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That seems like an existing bug. Wondering how/what it does.. Looking at: https://github.com/WordPress/gutenberg/pull/26897/files

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm also not sure about this one. Any suggestions on how to test its impact?

Copy link
Contributor Author

@sarayourfriend sarayourfriend Mar 12, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I should have mentioned this in the PR description, I totally glossed over that this was a fix.

Not sure how to measure its impact, but theoretically any onDragEnd event that was supposed to be fired was not being fired due to the lack of an onDragOver. That sounds pretty bad in the context of this component 😬

I did some digging and it doens't look like Draggable is even used in the Gutenberg codebase so there's no way to test it here 😕

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe if we ping the author of the original code?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ellatrix As you did the original refactor to a function component, do you mind chiming in on this? Is there a good way to test the result of this bug fix?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is used:

Drag and drop is hard to test, but manually by testing the block drag handle.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I don't know how I missed those usages!

Luckily, this bug would never have affected those two usages. One does not use the onDrag* events passed to Draggable at all and the other passes both onDragOver and onDragEnd meaning that this bug wouldn't have affected it.

Block dragging continues to work as expected.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's good. No tests required imo.

onDragEnd( event );
}
}
Expand All @@ -44,9 +67,10 @@ export default function Draggable( {
* - Sets transfer data.
* - Adds dragover listener.
*
* @param {Object} event The non-custom DragEvent.
* @param {import('react').DragEvent} event The non-custom DragEvent.
*/
function start( event ) {
// @ts-ignore We know that ownerDocument does exist on an Element
const { ownerDocument } = event.target;

event.dataTransfer.setData( 'text', JSON.stringify( transferData ) );
Expand Down Expand Up @@ -130,6 +154,9 @@ export default function Draggable( {
let cursorLeft = event.clientX;
let cursorTop = event.clientY;

/**
* @param {import('react').DragEvent} e
*/
function over( e ) {
cloneWrapper.style.top = `${
parseInt( cloneWrapper.style.top, 10 ) + e.clientY - cursorTop
Expand All @@ -156,6 +183,7 @@ export default function Draggable( {
// https://reactjs.org/docs/events.html#event-pooling
event.persist();

/** @type {number | undefined} */
let timerId;

if ( onDragStart ) {
Expand Down
1 change: 1 addition & 0 deletions packages/components/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"src/animate/**/*",
"src/base-control/**/*",
"src/dashicon/**/*",
"src/draggable/**/*",
"src/flex/**/*",
"src/form-group/**/*",
"src/shortcut/**/*",
Expand Down