Skip to content

Commit

Permalink
fix: enable pointer-events: none only when widget is dragged out from…
Browse files Browse the repository at this point in the history
… container (#210)

* fix: enable pointer-events: none only when widget is dragget out from group

* fix: force cursor capture when group changed

* fix: added top and left limits for focus block and used class for base css properties
  • Loading branch information
flops authored Oct 11, 2024
1 parent cd4f706 commit 8c79564
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 4 deletions.
3 changes: 3 additions & 0 deletions src/components/GridItem/GridItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ class GridItem extends React.PureComponent {
id: PropTypes.string,
item: PropTypes.object,
isDragging: PropTypes.bool,
isDraggedOut: PropTypes.bool,
layout: PropTypes.array,

forwardedRef: PropTypes.any,
Expand Down Expand Up @@ -161,6 +162,7 @@ class GridItem extends React.PureComponent {
children,
className,
isDragging,
isDraggedOut,
noOverlay,
focusable,
withCustomHandle,
Expand Down Expand Up @@ -188,6 +190,7 @@ class GridItem extends React.PureComponent {
className={b(
{
'is-dragging': isDragging,
'is-dragged-out': isDraggedOut,
'is-focused': this.state.isFocused,
'with-custom-handle': withCustomHandle,
},
Expand Down
16 changes: 14 additions & 2 deletions src/components/GridItem/GridItem.scss
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@
pointer-events: none;
}
}

// needs for drag n drop between multiple groups
&_is-dragged-out {
pointer-events: none;
}
}

.react-grid-layout {
Expand All @@ -66,8 +71,6 @@
transition: none;
z-index: 3;
will-change: transform;
// needs for drag n drop between multiple groups
pointer-events: none;
}

.react-grid-item.dashkit-grid-item_is-focused {
Expand All @@ -85,6 +88,15 @@
user-select: none;
}

.react-grid-focus-capture {
position: absolute;
display: block;
// Should be the highest between all grid item states
z-index: 6;
max-width: 100%;
max-height: 100%;
}

.react-grid-item .react-resizable-handle {
position: absolute;
width: 20px;
Expand Down
85 changes: 83 additions & 2 deletions src/components/GridLayout/GridLayout.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export default class GridLayout extends React.PureComponent {
isPageHidden: false,
currentDraggingElement: null,
draggedOverGroup: null,
draggedOut: false,
};
}

Expand Down Expand Up @@ -239,7 +240,7 @@ export default class GridLayout extends React.PureComponent {
};
}

updateeDraggingElementState(group, layoutItem, e) {
updateDraggingElementState(group, layoutItem, e) {
let currentDraggingElement = this.state.currentDraggingElement;

if (!currentDraggingElement) {
Expand All @@ -262,6 +263,76 @@ export default class GridLayout extends React.PureComponent {
this.setState({currentDraggingElement, draggedOverGroup: group});
}

_initDragCoordinatesWatcher(element) {
if (!this._parendDragNode) {
this._parendDragNode = element.parentElement;
this.setState({draggedOut: false});
}
}

// When element is going back and prointer-event: none is removed mouse enter event is not fired
// So to trigger it we are forcing this event by adding transparent block under the mouse
_forceCursorCapture(parentElement, position, parentRect) {
const block = document.createElement('div');
block.classList.add('react-grid-focus-capture');

const blockSize = 44;
const offset = blockSize / 2;

// Keeping elemnt inside current grid
const top = Math.min(Math.max(position.top - offset, 0), parentRect.height - blockSize);
const left = Math.min(Math.max(position.left - offset, 0), parentRect.width - blockSize);

block.style.width = `${blockSize}px`;
block.style.height = `${blockSize}px`;
block.style.top = `${top}px`;
block.style.left = `${left}px`;

parentElement.appendChild(block);

setTimeout(() => {
block.remove();
}, 100);
}

_updateDragCoordinates(e) {
const parent = this._parendDragNode;
const parentRect = parent.getBoundingClientRect();
const {clientX, clientY} = e;

let draggedOut = this.state.draggedOut;
if (
clientX < parentRect.left ||
clientX > parentRect.right ||
clientY < parentRect.top ||
clientY > parentRect.bottom
) {
draggedOut = true;
} else {
draggedOut = false;
}

if (draggedOut !== this.state.draggedOut) {
this.setState({draggedOut});

if (!draggedOut) {
this._forceCursorCapture(
parent,
{
top: clientY - parentRect.top,
left: clientX - parentRect.left,
},
parentRect,
);
}
}
}

_resetDragWatcher() {
this._parendDragNode = null;
this.setState({draggedOut: false});
}

_onDragStart(group, _newLayout, layoutItem, _newItem, _placeholder, e, element) {
this.context.onDragStart?.call(
this,
Expand All @@ -276,22 +347,28 @@ export default class GridLayout extends React.PureComponent {
),
);

this._initDragCoordinatesWatcher(element);

if (this.context.dragOverPlugin) {
this.setState({isDragging: true});
} else {
this.updateeDraggingElementState(group, layoutItem, e);
this.updateDraggingElementState(group, layoutItem, e);
this.setState({isDragging: true});
}
}

_onDrag(group, layout, oldItem, newItem, placeholder, e, element) {
this._updateDragCoordinates(e);

this.context.onDrag?.call(
this,
this.prepareDefaultArguments(group, layout, oldItem, newItem, placeholder, e, element),
);
}

_onDragStop(group, layout, oldItem, newItem, placeholder, e, element) {
this._resetDragWatcher();

this._onStop(group, layout);

this.context.onDragStop?.call(
Expand Down Expand Up @@ -561,6 +638,9 @@ export default class GridLayout extends React.PureComponent {
: null)}
>
{renderItems.map((item, i) => {
const isCurrentItem = currentDraggingElement?.item.id === item.id;
const isDraggedOut = isCurrentItem && this.state.draggedOut;

return (
<GridItem
forwardedPluginRef={this.getMemoForwardRefCallback(offset + i)} // forwarded ref to plugin
Expand All @@ -570,6 +650,7 @@ export default class GridLayout extends React.PureComponent {
layout={layout}
adjustWidgetLayout={this.adjustWidgetLayout}
isDragging={this.state.isDragging}
isDraggedOut={isDraggedOut}
noOverlay={noOverlay}
focusable={focusable}
withCustomHandle={Boolean(draggableHandleClassName)}
Expand Down

0 comments on commit 8c79564

Please sign in to comment.