Skip to content
This repository has been archived by the owner on Nov 12, 2024. It is now read-only.

Commit

Permalink
feat: add overlap prop to droppables
Browse files Browse the repository at this point in the history
  • Loading branch information
florian-lefebvre committed Jun 11, 2024
1 parent 129d39f commit bb0c020
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 2 deletions.
5 changes: 5 additions & 0 deletions .changeset/many-ears-give.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"vue-simple-dnd": minor
---

Adds an `overlap` prop to droppables
8 changes: 8 additions & 0 deletions package/src/components/Droppable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ const props = withDefaults(
* @default `true`
*/
acceptSelfDraggables?: boolean;
/**
* Defines how much overlap between the Droppable and the
* Draggable is required to trigger a hover.
*
* @default `0.001`
*/
overlap?: number;
}>(),
{
disabled: false,
Expand All @@ -41,6 +48,7 @@ const { slotProps } = useDroppable({
disabled: computed(() => props.disabled),
acceptSelfDraggables: computed(() => props.acceptSelfDraggables),
onDrop: (data) => emit("drop", data),
overlap: props.overlap ? computed(() => props.overlap) : undefined,
});
</script>

Expand Down
27 changes: 25 additions & 2 deletions package/src/composables/use-droppable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export const useDroppable = ({
onDrop,
disabled = computed(() => false),
acceptSelfDraggables = computed(() => true),
overlap = computed(() => 0.001),
}: {
/**
* A reference to the element acting as the droppable.
Expand All @@ -31,10 +32,17 @@ export const useDroppable = ({
/**
* When enabled, dragging a Draggable from this droppable
* over itself will trigger `dragging`.
*
*
* @default `true`
*/
acceptSelfDraggables?: ComputedRef<boolean>;
/**
* Defines how much overlap between the droppable and the
* draggable is required to trigger a hover.
*
* @default `0.001`
*/
overlap?: ComputedRef<number>;
}) => {
const bounding = useElementBounding(el);
const { machine, bus } = useDragContext();
Expand All @@ -60,6 +68,7 @@ export const useDroppable = ({
snapshot: machine.snapshot,
id,
disabled,
percentage: overlap,
onHoverChange(hovered) {
if (
!acceptSelfDraggables.value &&
Expand Down Expand Up @@ -88,12 +97,14 @@ const useSlotProps = ({
onHoverChange,
id,
disabled,
percentage,
}: {
dimensions: ComputedRef<Dimensions>;
snapshot: ReturnType<typeof useDragContext>["machine"]["snapshot"];
onHoverChange: (hovered: boolean) => void;
id: string;
disabled: ComputedRef<boolean>;
percentage: ComputedRef<number>;
}) => {
const isDragging = computed(() => snapshot.value.matches("dragging"));
const hasOverlap = computed(() => {
Expand All @@ -102,7 +113,19 @@ const useSlotProps = ({
const x1 = dimensions.value;
const x2 = snapshot.value.context.draggable!.dimensions;

return !(x1[0] > x2[2] || x1[2] < x2[0] || x1[1] > x2[3] || x1[3] < x2[1]);
const overlapX = Math.max(
0,
Math.min(x1[2], x2[2]) - Math.max(x1[0], x2[0])
);
const overlapY = Math.max(
0,
Math.min(x1[3], x2[3]) - Math.max(x1[1], x2[1])
);
const overlapArea = overlapX * overlapY;

const draggableArea = (x2[2] - x2[0]) * (x2[3] - x2[1]);

return overlapArea >= percentage.value * draggableArea;
});
const isHovered = computed(() => isDragging.value && hasOverlap.value);
const isNotAllowed = computed(() =>
Expand Down
1 change: 1 addition & 0 deletions playground/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ const onDrop = (zone: Item["zone"], item: Item) => {
v-slot="{ hovered, notAllowed }"
:disabled="getZone(2).length >= 1"
@drop="(e) => onDrop(2, e)"
:overlap="0.5"
>
<div
class="h-32 w-32 bg-gray-800 border-2 relative"
Expand Down

0 comments on commit bb0c020

Please sign in to comment.