-
Notifications
You must be signed in to change notification settings - Fork 0
/
Wheel.mjs
88 lines (85 loc) · 2.58 KB
/
Wheel.mjs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
const Wheel = {
lastDirection:0,
oncreate(vnode) {
this.onupdate(vnode)
},
onupdate(vnode) {
},
view(vnode) {
const {attrs: {value, options = vnode.children}} = vnode
const extraRows = 25
const selectedIndex = options.findIndex(el => el?.attrs?.value === value)
if (selectedIndex == -1) {
throw new Error('Given value not among options.')
}
const onchange = vnode.attrs.onchange || vnode.attrs.oninput || function(e) {
const cb = vnode.attrs.setValue || vnode.attrs.setvalue
if (!cb) return
cb(e.target.value)
}
const visible = options.slice(
Math.max(selectedIndex-extraRows, 0),
selectedIndex+extraRows+1)
const centerIndex = visible.findIndex(el => el === options[selectedIndex])
const direction = this.lastDirection
this.lastDirection = 0
this.positionWrappers = visible.map((el, i) => ({
...el,
attrs: {
...el.attrs ?? {},
style: {
...el.attrs?.style ?? {},
position: 'absolute',
width: '100%',
top: '50%',
transform: `translateY(${(i-centerIndex)*100-50}%)`,
transition: 'transform .6s ease-out',
},
onclick: e => {
const vnode = this.positionWrappers.find(el => el.dom == e.target)
onchange({target: vnode.attrs})
el.attrs?.onclick?.(e)
},
oncreate: (vnode) => {
el.attrs.oncreate?.(vnode)
vnode.dom.animate([
{transform: `translateY(-50%) translateY(${direction}00vh)`},
{}
], 600)
},
onbeforeremove: (vnode) => {
return Promise.all([
el.attrs.onbeforeremove?.(vnode),
new Promise(resolve=>vnode.dom.animate([
{opacity: `0`},
], 600).onfinish=resolve)
]);
},
},
key: el.key ?? i-centerIndex+selectedIndex,
}))
return m('div', {
style: {
position: 'relative',
overflow: 'hidden',
width: '100%',
height: '100%',
...vnode.attrs?.style ?? {},
},
onwheel: e => {
if (e.deltaY) {
this.lastDirection = (e.deltaY > 0 ? 1 : -1)
let newIndex = selectedIndex + this.lastDirection
while (options[newIndex] && options[newIndex].attrs.value == null) {
newIndex = newIndex + this.lastDirection
}
if (options[newIndex]) {
onchange({target: options[newIndex].attrs})
}
return false
}
},
}, this.positionWrappers)
}
}
export default Wheel