brandonmcconnell icon

`stuck` Svelte action

brandonmcconnell | PRO | 10/04/23 08:31:44 PM UTC (Edited) | 0 ⭐ | 7520 👁️ | Never ⏰ | []
TypeScript |

2.38 KB

|

Source Code

|

0 👍

/

0 👎

function getStickyRoot(node: Element) {
  let current = node.parentElement;
  while (current && current !== document.body) {
    const computedStyle = window.getComputedStyle(current);
    const overflow = computedStyle.getPropertyValue('overflow');
 
    if (overflow === 'scroll' || overflow === 'auto') {
      return current;
    }
    current = current.parentElement;
  }
 
  return document.body;
}
 
function isNumber(value: any): value is number {
  // the isFinite() check also suffices for !isNaN()
  return typeof value === 'number' && Number.isFinite(value);
}
 
export function stuck(node: Element) {
  const root = getStickyRoot(node);
  function detectStuck() {
    if (getComputedStyle(node).position !== 'sticky') {
      const dirs = ['', 't', 'r', 'b', 'l', 'x', 'y'];
      for (const dir of dirs) {
        const suffix = dir ? `-${dir}` : '';
        node.classList.remove(`stuck${suffix}`);
      }
    }
    const rect = node.getBoundingClientRect();
    const rootRect = root.getBoundingClientRect();
    const computedStyle = window.getComputedStyle(node);
 
    const top = parseFloat(computedStyle.getPropertyValue('top'));
    const right = parseFloat(computedStyle.getPropertyValue('right'));
    const bottom = parseFloat(computedStyle.getPropertyValue('bottom'));
    const left = parseFloat(computedStyle.getPropertyValue('left'));
 
    const t = isNumber(top) && rect.top - rootRect.top === top;
    const r = isNumber(right) && rootRect.right - rect.right === right;
    const b = isNumber(bottom) && rootRect.bottom - rect.bottom === bottom;
    const l = isNumber(left) && rect.left - rootRect.left === left;
    const x = l || r;
    const y = t || b;
 
    let isStuck: boolean = false;
    for (const [dir, condition] of Object.entries({ t, r, b, l, x, y })) {
      if (condition) {
        node.classList.add(`stuck-${dir}`);
        isStuck = true;
      } else {
        node.classList.remove(`stuck-${dir}`);
      }
    }
    if (isStuck) {
      node.classList.add('stuck');
    } else {
      node.classList.remove('stuck');
    }
  }
 
  root.addEventListener('scroll', detectStuck, { passive: true });
  window.addEventListener('resize', detectStuck, { passive: true });
 
  return {
    destroy() {
      root.removeEventListener('scroll', detectStuck);
      window.removeEventListener('resize', detectStuck);
    },
  };
}
 

Comments

  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎

    
        
  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎