File size: 2,524 Bytes
c2ea21f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
const menubox = document.querySelector('.menubox');
const menulabel = menubox.querySelector('.menubox__label');
const menuchecks = menubox.querySelectorAll('input[type=checkbox]');
const menuboxRect = menubox.getBoundingClientRect();
const menulabelRect = menulabel.getBoundingClientRect();
const frameTime = 1000 / 60;
const duration = 350;
const frames = Math.ceil(duration / frameTime);
const slideHeight = menuboxRect.height - menulabelRect.height;
let timer = null;
let currentItem = 0;
const debouncedFn = (fn) => {
  timer && clearTimeout(timer);
  timer = setTimeout(fn, 250);
}
const documentAnimateHeight = (e) => {
  if (e.target === menubox || menubox.contains(e.target)) {
    e.stopPropagation();
    return;
  }
  
  debouncedFn(() => {
    animateHeight(true);
  });
};
document.addEventListener('click', documentAnimateHeight);
function animateHeight (collapsing, done) {
  let i = 0;
  
  function __animate () {
    // const scale = (collapsing ? frames - (i++) : i++) / frames;
    // const height = menulabelRect.height + (scale * slideHeight);
    
    const factor = Math.pow((i++) / frames - 1, 3) + 1;
    const height = 2 + menulabelRect.height + (collapsing ? 1 - factor : factor) * slideHeight;

    menubox.style.maxHeight = `${height}px`;

    if (i <= frames) {
      requestAnimationFrame(__animate);
    } else {
      if (collapsing) {
        const transitionEnded = () => {
          menubox.removeEventListener('transitionend', transitionEnded);
          document.removeEventListener('click', documentAnimateHeight);

          (typeof done === 'function') && done();
        }

        menubox.classList.add('menubox--collapsed');
        menubox.addEventListener('transitionend', transitionEnded, false);
      } else {
        menuchecks.item(currentItem = currentItem || 0).focus();
        (typeof done === 'function') && done();
      }
      
      timer && clearTimeout(timer);
      timer = null;
    }
  }
  if (collapsing) {
    requestAnimationFrame(__animate);
  } else {
    const transitionEnded = () => {
      menubox.removeEventListener('transitionend', transitionEnded);
      requestAnimationFrame(__animate);
    }
    
    menubox.classList.remove('menubox--collapsed');
    menubox.addEventListener('transitionend', transitionEnded, false);
      
    document.addEventListener('click', documentAnimateHeight);
  }
}
menulabel.addEventListener('click', () => {
  debouncedFn(() => {
    animateHeight(!menubox.classList.contains('menubox--collapsed'));
  });
});