JSFiddle - React, Tailwind, and code Playground

Paint API border experiment 2

by Travis Almand

HTML

<div class="container">
  container 1
</div>
<div class="container">
  container 2
</div>
<div class="container">
  container 3
</div>
<div class="container">
  container 4
</div>

SCSS

.container {
  align-items: center;
  background-color: white;
  border-radius: 10px;
  box-shadow: 0 0 8px 0 rgba(0, 0, 0, 0.5);
  display: flex;
  height: 100px;
  justify-content: center;
  margin: 50px 20px;
  position: relative;
  overflow: hidden;
  width: 300px;
  
  // you can adjust these
  --decorate-width: 10;
  --decorate-color: rgba(255,0,0,1);
  --decorate-duration: 500;
  
  &.decorate {
    background-image: paint(decorate);
  }
  
  &:nth-child(2) {
    --decorate-width: 20;
    --decorate-duration: 1000;
    height: 150px;
    width: 100px;
  }
  &:nth-child(3) {
    height: 200px;
  }
  &:nth-child(4) {
    border-radius: 0;
    height: 200px;
    width: 200px;
  }
}

JavaScript

function decorateMouseOver (e) {
	this.classList.toggle('decorate');

  let self = this;
  let start = performance.now();
  let rect = self.getBoundingClientRect();
  let x = e.clientX - rect.x;
  let mx = e.movementX < 0 ? e.movementX * -1 : e.movementX;
  let y = e.clientY - rect.y;
  let my = e.movementY < 0 ? e.movementY * -1 : e.movementY;
  let duration = getComputedStyle(self).getPropertyValue('--decorate-duration');

  requestAnimationFrame(function raf(now) {
    const count = Math.floor(now - start);

    self.style.cssText = `--decorate-x: ${x}; --decorate-mx: ${mx}; --decorate-y: ${y}; --decorate-my: ${my}; --decorate-tick: ${count};`;

    if(count > duration) {
      return;
    }
    requestAnimationFrame(raf);
  });
}
function decorateMouseOut (e) {
	this.classList.remove('decorate');
  this.style.cssText = '--decorate-tick: 0';
}

const accountContainers = document.querySelectorAll('.container');

accountContainers.forEach(container => {
  container.addEventListener('mouseover', decorateMouseOver);
  container.addEventListener('mouseout', decorateMouseOut);
});

CSS.registerProperty({
  name: '--decorate-width',
  syntax: '<number>',
  inherits: false,
  initialValue: 10
});
CSS.registerProperty({
  name: '--decorate-color',
  syntax: '<color>',
  inherits: false,
  initialValue: 'rgba(0, 0, 0, 1)'
});
CSS.registerProperty({
  name: '--decorate-duration',
  syntax: '<number>',
  inherits: false,
  initialValue: 500
});

CSS.paintWorklet.addModule(URL.createObjectURL(new Blob([`
  class AccountDecorator {
  static get inputProperties() { return ['--decorate-color', '--decorate-tick', '--decorate-x', '--decorate-mx', '--decorate-y', '--decorate-my', '--decorate-width', '--decorate-duration']; }
   
  paint(ctx, geom, properties) {
    const color = properties.get('--decorate-color').toString();
    const x = parseFloat(properties.get('--decorate-x'));
    const mx = parseFloat(properties.get('--decorate-mx'));
    const y =...