Skip to content

Commit

Permalink
feat: add option to specify handle class
Browse files Browse the repository at this point in the history
  • Loading branch information
KrisVos130 committed Feb 24, 2024
1 parent ad19062 commit 8525ea2
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 6 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## [v0.1.4] - T.B.D.

### Changes

- Add option to only allow dragging when you click a handle element

## [v0.1.3] - 2022-12-07

### Changes
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ Originally created for [Musare](https://github.com/Musare/Musare).
| group | String | | Yes | Name of the group, so you can move items between different lists in the same group. Leaving it empty will disable moving between lists. |
| disabled | Boolean or Function | `false` | Yes | Used to disable dragging inside a list in general, or with a function you can prevent specific items from being dragged. |
| touchTimeout | Number | 250 | Yes | Time in milliseconds that a user is required to hold list item before dragging is started. |
| handleClass | String | N/A | Yes | Class of handle elements. For example: "handle". If specified, only elements with this class can be used to start dragging. |
### Emits
Expand Down
45 changes: 41 additions & 4 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,22 @@
import { reactive } from "vue";
import DraggableList from "./components/DraggableList.vue";
const testArray = reactive([
const testArray1 = reactive([
{
id: 1,
name: "Bob"
},
{
id: 2,
name: "Alice"
},
{
id: 3,
name: "Lisa"
}
]);
const testArray2 = reactive([
{
id: 1,
name: "Bob"
Expand Down Expand Up @@ -31,16 +46,38 @@ const onUpdate = (...args) => {
</script>

<template>
<h1>Example</h1>
<h1>Examples</h1>
<h2>Example 1</h2>
<DraggableList
item-key="id"
v-model:list="testArray1"
@start="onStart"
@end="onEnd"
@update="onUpdate"
>
<template #item="{ element }">
<h3>{{ element.id }} - {{ element.name }}</h3>
</template>
</DraggableList>

<hr />

<h2>Example 2</h2>
<DraggableList
item-key="id"
v-model:list="testArray"
v-model:list="testArray2"
@start="onStart"
@end="onEnd"
@update="onUpdate"
handle-class="handle"
>
<template #item="{ element }">
<h2>{{ element.id }} - {{ element.name }}</h2>
<div class="card">
<div class="handle">
<span>Handle</span>
</div>
<p>{{ element.id }} - {{ element.name }}</p>
</div>
</template>
</DraggableList>
</template>
Expand Down
27 changes: 26 additions & 1 deletion src/components/DraggableList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ const props = defineProps({
tag: { type: String, default: "div" },
group: { type: String, default: "" },
disabled: { type: [Boolean, Function], default: false },
touchTimeout: { type: Number, default: 250 }
touchTimeout: { type: Number, default: 250 },
handleClass: { type: String }

Check warning on line 12 in src/components/DraggableList.vue

View workflow job for this annotation

GitHub Actions / build

Prop 'handleClass' requires default value to be set
});
const listUuid = ref(
Expand Down Expand Up @@ -70,6 +71,30 @@ const onDragStart = (itemIndex: number, event: DragEvent) => {
return;
}
// If we only want to start dragging if the user clicked on a handle element
if (props.handleClass) {
const { x, y } = event;
// Gets all elements at a specific x, y position on the page
const elementsAtPosition = document.elementsFromPoint(x, y);
const clickedHandle = elementsAtPosition.reduce<boolean | null>((clickedHandle, elementAtPosition) => {

Check failure on line 79 in src/components/DraggableList.vue

View workflow job for this annotation

GitHub Actions / build

Insert `⏎············`
// If we already have a boolean result, return that

Check failure on line 80 in src/components/DraggableList.vue

View workflow job for this annotation

GitHub Actions / build

Insert `····`
if (typeof clickedHandle === "boolean") return clickedHandle;

Check failure on line 81 in src/components/DraggableList.vue

View workflow job for this annotation

GitHub Actions / build

Replace `············` with `················`
// If the clicked element (or one of its parents) has the handle class, we clicked the handle

Check failure on line 82 in src/components/DraggableList.vue

View workflow job for this annotation

GitHub Actions / build

Replace `············` with `················`
if (elementAtPosition.classList.contains(props.handleClass!)) return true;

Check failure on line 83 in src/components/DraggableList.vue

View workflow job for this annotation

GitHub Actions / build

Replace `if·(elementAtPosition.classList.contains(props.handleClass!))` with `····if·(elementAtPosition.classList.contains(props.handleClass!))⏎···················`

Check warning on line 83 in src/components/DraggableList.vue

View workflow job for this annotation

GitHub Actions / build

Forbidden non-null assertion
// If we've reached the draggable element itself, we found no handle, so return false to avoid

Check failure on line 84 in src/components/DraggableList.vue

View workflow job for this annotation

GitHub Actions / build

Insert `····`
// accidentally using handles with the same class outside the draggable element

Check failure on line 85 in src/components/DraggableList.vue

View workflow job for this annotation

GitHub Actions / build

Insert `····`
if (elementAtPosition === event.target) return false;

Check failure on line 86 in src/components/DraggableList.vue

View workflow job for this annotation

GitHub Actions / build

Replace `············` with `················`
return null;

Check failure on line 87 in src/components/DraggableList.vue

View workflow job for this annotation

GitHub Actions / build

Insert `····`
}, null);

Check failure on line 88 in src/components/DraggableList.vue

View workflow job for this annotation

GitHub Actions / build

Replace `········},·null` with `············},⏎············null⏎········`
// If no handle was clicked, we don't want to start dragging the element
if (!clickedHandle) {
event.preventDefault();
return;
}
}
// Set the effect of moving an element, which by default is clone. Not being used right now
event.dataTransfer.dropEffect = "move";
Expand Down
20 changes: 19 additions & 1 deletion src/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ h1 {
line-height: 1.1;
}

h2 {
font-size: 2em;
line-height: 1.1;
}

button {
border-radius: 8px;
border: 1px solid transparent;
Expand All @@ -57,7 +62,20 @@ button:focus-visible {
}

.card {
padding: 2em;
padding: 0.25em;
border: 1px solid white;
display: flex;
flex-direction: row;
}

.card > .handle {
display: flex;
align-items: center;
border: 1px dotted white;
}

.card > *:not(.handle) {
flex: 1;
}

#app {
Expand Down

0 comments on commit 8525ea2

Please sign in to comment.