Last active
February 27, 2017 16:05
-
-
Save dead-claudia/cfac54f77a4cb4ad7131a33e8a8fc315 to your computer and use it in GitHub Desktop.
Fork of Barney Carroll's Mithril drag component: https://gist.github.com/barneycarroll/decfefa9ed7f21193f55d60436d5d914
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import m from 'mithril' | |
import stream from 'mithril/stream' | |
import pointerStream from 'pointer-stream' | |
function targeted(state) { | |
const node = state._vnode.dom | |
const {x, y} = state._pointer.coords() | |
const child = document.elementFromPoint(x, y) | |
const parent = node.parentNode | |
if (parent != null) { | |
if (!parent.contains(child)) return false | |
if (parent.children.length === state._vnode.domSize) return true | |
} | |
for (let i = 0; i < state._vnode.domSize; i++) { | |
if (node.contains(child)) return true | |
node = node.nextSibling | |
} | |
return false | |
} | |
export default { | |
// Persist vnode data on every draw | |
oncreate(vnode) { this._vnode = vnode }, | |
onupdate(vnode) { this._vnode = vnode }, | |
oninit(vnode) { | |
// This allows us to reliably access the last render's dom and attribute data | |
// Also, create a pointer stream and the drag/drop streams | |
this._vnode = vnode | |
this._pointer = pointerStream() | |
this.drag = stream(false) | |
this.drop = stream(false) | |
// Set up the component API streams: drag & drop | |
if (vnode.attrs.drag) this.drag.map(vnode.attrs.drag) | |
if (vnode.attrs.drop) this.drop.map(vnode.attrs.drop) | |
// When its drag status changes… | |
this._pointer.dragging.map(dragging => { | |
// We have to have the vdom available first | |
if (this._vnode.dom == null) return | |
let redraw = false | |
if (dragging) { | |
// We weren't but are now dragging into here | |
if (!this.drag() && targeted(this)) { | |
redraw = true | |
this.drag(true) | |
} | |
} else { | |
// We were but are no longer dragging | |
if (this.drag()) { | |
redraw = true | |
this.drag(false) | |
} | |
// We ended a drag and did so here | |
if (targeted(this)) { | |
redraw = true | |
this.drop(true) | |
} | |
} | |
if (redraw) m.redraw() | |
}) | |
}, | |
// Drag is view agnostic and provides none of its own: | |
// If a view was supplied as an attribute, we pass the vnode to it so that the state streams can be read from within | |
// Otherwise we simply render the children: stream data can be read by passing in receiving streams as attributes with corresponding keys | |
view(vnode) { | |
return vnode.attrs.view | |
? vnode.attrs.view.apply(this, arguments) | |
: vnode.children | |
}, | |
// Clean up state | |
onremove({attrs}) { | |
// Kill the pointer, each API stream, and applicable supplied streams | |
this._pointer.end(true) | |
this.drag.end(true) | |
if (attrs.drag && attrs.drag.end) attrs.drag.end(true) | |
this.drop.end(true) | |
if (attrs.drop && attrs.drop.end) attrs.drop.end(true) | |
}, | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment