DragSource
import { DragSource } from 'cx/widgets'; Copied DragSource wraps elements that can be dragged. The data property specifies what data is passed to the drop zone when the element is dropped.
Example
<div class="flex items-center gap-8">
<DragSource data={{ text: "Drag me!" }}>
<div class="p-4 border-2 border-dashed rounded bg-blue-50 cursor-move hover:bg-blue-100">
Drag me!
</div>
</DragSource>
<DragSource data={{ text: "Or me!" }}>
<div class="p-4 border-2 border-dashed rounded bg-blue-50 cursor-move hover:bg-blue-100">
Or me!
</div>
</DragSource>
<DropZone
onDrop={({ source }) => {
alert(`Dropped: ${source.data.text}`)
}}
>
<div class="p-4 border border-gray-200 rounded bg-green-50 min-w-32 text-center">
Drop here
</div>
</DropZone>
</div> Drag me!
Or me!
Drop here
Dashboard Example
This example demonstrates advanced features:
handled- Only the handle initiates drag, allowing text selectionclone- Custom lightweight widget shown during drag instead of cloning the entire content
<div class="flex flex-col gap-2" controller={PageController}>
<Repeater
records={m.widgets}
recordAlias={m.$widget}
indexAlias={m.$index}
keyField="id"
>
<DropZone
mod="block"
onDrop={({ source }, { store }) => {
let targetIndex = store.get(m.$index)
let widgets = store
.get(m.widgets)
.filter((w) => w.id !== source.data.id)
store.set(m.widgets, [
...widgets.slice(0, targetIndex),
source.data,
...widgets.slice(targetIndex),
])
}}
matchWidth
matchHeight
matchMargin
inflate={100}
/>
<DragSource
data={m.$widget}
handled
clone={
<div
class="p-2 border rounded bg-white shadow-lg opacity-90"
text={m.$widget.title}
/>
}
>
<div class={["p-4 border rounded", m.$widget.color]}>
<div class="flex items-center gap-2 mb-2">
<DragHandle>
<div class="cursor-move text-gray-400 hover:text-gray-600">⋮⋮</div>
</DragHandle>
<div class="font-medium" text={m.$widget.title} />
</div>
<div class="text-2xl font-bold">1,234</div>
<div class="text-sm text-gray-500">Sample metric</div>
</div>
</DragSource>
</Repeater>
<DropZone
mod="block"
matchWidth
matchHeight
matchMargin
onDrop={({ source }, { store }) => {
let widgets = store.get(m.widgets).filter((w) => w.id !== source.data.id)
store.set(m.widgets, [...widgets, source.data])
}}
inflate={100}
>
<div class="h-2" />
</DropZone>
</div> ⋮⋮
Sales
1,234
Sample metric
⋮⋮
Orders
1,234
Sample metric
⋮⋮
Users
1,234
Sample metric
Configuration
| Property | Type | Description |
|---|---|---|
data | Prop | Data passed to the drop zone on drop. |
hideOnDrag | boolean | Hide the source element while dragging. Defaults to false. |
handled | boolean | If true, dragging is initiated only through a DragHandle. Defaults to false. |
onDragStart | function | Callback invoked when drag starts. Return false to cancel. |
onDragEnd | function | Callback invoked when drag ends. |
clone | Config | Custom widget to display during drag instead of cloning the source. |
cloneStyle | Style | CSS styles applied to the drag clone. |
cloneClass | Class | CSS class applied to the drag clone. |
draggedStyle | Style | CSS styles applied to the source element while being dragged. |
draggedClass | Class | CSS class applied to the source element while being dragged. |
id | string | ID attribute for the element. |