UNPKG

remarqueeble

Version:

Custom element tribute to the cursed glory of marquee.

42 lines (37 loc) 8.99 kB
/*! remarqueeble v0.7.0 | (c) 2026 Rémino Rem <https://remino.net/> | ISC Licence */ (function(){var e=6,t=`${e}px`,n=85,r=60,i=`200px`,a=`calc(100% - (var(--attr-hspace, 0px) * 2))`,o=`direction`,s=`behavior`,c=`animate`,l=`scrollamount`,u=`scrolldelay`,d=`truespeed`,f=`loop`,p=`bgcolor`,m=`width`,h=`height`,g=`hspace`,_=`vspace`,v=`--attr-width`,y=`--attr-height`,b=`--attr-hspace`,x=`--attr-vspace`,S=`--attr-bgcolor`,C=globalThis.HTMLElement??class{},w=e=>{if(e===null)return null;let t=e.trim();return t===``?null:/^[+-]?(?:\d+|\d*\.\d+)$/.test(t)?`${t}px`:globalThis.CSS?.supports(`width`,t)?t:null},T=e=>{if(e===null)return null;let t=e.trim();return t===``?null:/^[+-]?(?:\d+|\d*\.\d+)$/.test(t)?Number(t)>=0?`${t}px`:null:globalThis.CSS?.supports(`width`,t)?t:null},E=[{attribute:m,cssVar:v,parser:w},{attribute:h,cssVar:y,parser:w,fallback(e){return e.isVerticalDirection&&!e.hasAttribute(h)?i:null}},{attribute:g,cssVar:b,parser:w},{attribute:_,cssVar:x,parser:w},{attribute:p,cssVar:S,parser:e=>{if(e===null)return null;let t=e.trim();return t===``?null:globalThis.CSS?.supports(`background-color`,t)?t:null}}],D=class extends C{static observedAttributes=[o,s,c,l,u,d,f,p,m,h,g,_];track;scrollAmountProbe;tickInterval=null;currentPosition=0;currentStepDelta=0;completedIterations=0;hasPosition=!1;running=!1;constructor(){super();let e=this.attachShadow({mode:`open`});e.innerHTML=` <style> :host { display: inline-block; text-align: initial; overflow: hidden !important; white-space: nowrap; width: var(${v}, ${a}); height: var(${y}, auto); margin-inline: var(${b}, 0px); margin-block: var(${x}, 0px); background-color: var(${S}, transparent); box-sizing: border-box; } :host([direction="up"]), :host([direction="down"]) { white-space: normal; } .track { display: inline-block; transform: translate(0px, 0px); will-change: transform; } .scrollamount-probe { block-size: 0; display: block; inline-size: ${t}; overflow: hidden; pointer-events: none; position: absolute; visibility: hidden; } </style> <span class="track"><slot></slot></span> <span class="scrollamount-probe" aria-hidden="true"></span> `;let n=e.querySelector(`.track`);if(!n)throw Error(`Remarqueeble track element was not created.`);let r=e.querySelector(`.scrollamount-probe`);if(!r)throw Error(`Remarqueeble scrollamount probe was not created.`);this.track=n,this.scrollAmountProbe=r}connectedCallback(){this.running=!0,this.syncPresentationalHints(),requestAnimationFrame(()=>{!this.isConnected||!this.running||this.reset()})}disconnectedCallback(){this.running=!1,this.clearTickInterval()}attributeChangedCallback(e,t,n){t!==n&&(this.syncPresentationalHints(),this.isConnected&&(this.hasPosition=!1,this.completedIterations=0,this.reset()))}get direction(){return this.getAttribute(o)||`left`}get behavior(){return this.getAttribute(s)||`scroll`}get scrollAmount(){let n=T(this.getAttribute(l))??t;this.scrollAmountProbe.style.inlineSize=n;let r=this.scrollAmountProbe.getBoundingClientRect().width;return Number.isFinite(r)&&r>=0?r:e}get scrollDelay(){let e=this.getAttribute(u),t=e===null||e.trim()===``?NaN:Number(e),i=Number.isFinite(t)&&t>=0?t:n;return this.hasAttribute(d)?i:Math.max(i,r)}get loop(){let e=this.getAttribute(f);return e===null?-1:Number(e)}get directionSign(){return this.direction===`right`||this.direction===`down`?1:-1}get isVerticalDirection(){return this.direction===`up`||this.direction===`down`}start(){this.running||(this.running=!0,this.reset())}stop(){this.running=!1,this.clearTickInterval()}syncPresentationalHints(){for(let e of E)this.syncVar(e)}syncVar(e){let t=this.getAttribute(e.attribute),n=e.parser(t),r=e.fallback?e.fallback(this):null;if(n==null){r==null?this.style.removeProperty(e.cssVar):this.style.setProperty(e.cssVar,r);return}this.style.setProperty(e.cssVar,n)}reset(){let e=this.syncGeometry();if(this.currentStepDelta=e.stepDelta,this.completedIterations=0,!e.canAnimate){this.syncInactiveState(),this.ensureTicking();return}this.currentPosition=e.startPosition,this.hasPosition=!0,this.syncActiveState(),this.applyCurrentPosition(),this.emitLegacyEvent(`start`),this.restartTicking()}getHostSize(){return this.isVerticalDirection?this.clientHeight:this.clientWidth}getTrackSize(){return this.isVerticalDirection?this.track.offsetHeight:this.track.offsetWidth}getStartPosition(e,t){return this.directionSign<0?e:-t}getFlushEndPosition(e,t){return this.directionSign<0?0:e-t}getOffEndPosition(e,t){return this.directionSign<0?-t:e}getSlideEndPosition(e,t){return this.directionSign<0?Math.min(0,e-t):Math.max(0,e-t)}getAlternateStartPosition(e,t){return this.directionSign<0?e-t:0}syncGeometry(){let e=this.getHostSize(),t=this.getTrackSize(),n=this.shouldAnimate(e,t)&&this.scrollAmount!==0,r=this.behavior===`alternate`?this.getAlternateStartPosition(e,t):this.getStartPosition(e,t),i=this.behavior===`slide`?this.getSlideEndPosition(e,t):this.behavior===`alternate`?this.getFlushEndPosition(e,t):this.getOffEndPosition(e,t);return Math.abs(i-r),{canAnimate:n,endPosition:i,hostSize:e,startPosition:r,stepDelta:this.directionSign<0?-this.scrollAmount:this.scrollAmount,trackSize:t}}shouldAnimate(e,t){return this.animationMode===`never`?!1:this.animationMode===`overflow`?t>e:!0}get animationMode(){let e=this.getAttribute(c);return e===`overflow`||e===`never`?e:`always`}clearTickInterval(){this.tickInterval!==null&&(clearInterval(this.tickInterval),this.tickInterval=null)}hasFiniteAnimation(){return this.behavior===`slide`&&!this.hasAttribute(f)?!0:this.hasAttribute(f)&&Number.isFinite(this.loop)&&this.loop>0}ensureTicking(){!this.running||this.tickInterval!==null||(this.tickInterval=setInterval(()=>{this.tick()},this.scrollDelay))}restartTicking(){this.clearTickInterval(),this.ensureTicking()}tick(){if(!this.running)return;let e=this.syncGeometry();if(!e.canAnimate){this.syncInactiveState();return}if(this.syncActiveState(),!this.hasPosition)this.currentStepDelta=e.stepDelta,this.currentPosition=e.startPosition,this.completedIterations=0,this.hasPosition=!0,this.emitLegacyEvent(`start`);else{if(this.behavior===`alternate`){let t=Math.sign(this.currentStepDelta||e.stepDelta)||1;this.currentStepDelta=Math.abs(e.stepDelta)*t}else this.currentStepDelta=e.stepDelta;this.clampCurrentPosition(e)}if(this.behavior===`alternate`?this.stepAlternate(e.hostSize,e.trackSize):this.stepLinear(e.hostSize,e.trackSize),this.applyCurrentPosition(),!this.running){this.clearTickInterval();return}}stepLinear(e,t){let n=this.getStartPosition(e,t),r=this.behavior===`slide`?this.getSlideEndPosition(e,t):this.getOffEndPosition(e,t),i=this.currentPosition+this.currentStepDelta;if(this.directionSign<0){if(i>r){this.currentPosition=i;return}let e=r-i;if(this.completedIterations+=1,this.hasCompletedIterations()){this.completeFiniteAnimation(r);return}this.currentPosition=this.behavior===`slide`?n:n-e;return}if(i<r){this.currentPosition=i;return}let a=i-r;if(this.completedIterations+=1,this.hasCompletedIterations()){this.completeFiniteAnimation(r);return}this.currentPosition=this.behavior===`slide`?n:n+a}stepAlternate(e,t){let n=Math.min(this.getAlternateStartPosition(e,t),this.getFlushEndPosition(e,t)),r=Math.max(this.getAlternateStartPosition(e,t),this.getFlushEndPosition(e,t)),i=this.currentPosition+this.currentStepDelta;for(;i<n||i>r;)if(i=i<n?n+(n-i):r-(i-r),this.currentStepDelta*=-1,this.completedIterations+=1,this.emitLegacyEvent(`bounce`),this.hasCompletedIterations()){this.completeFiniteAnimation(this.currentStepDelta>0?n:r);return}this.currentPosition=i}hasCompletedIterations(){return this.hasFiniteAnimation()&&this.completedIterations>=Math.max(1,this.loop)}completeFiniteAnimation(e){this.currentPosition=e,this.running=!1,this.emitLegacyEvent(`finish`)}syncInactiveState(){this.track.style.transform=`translate(0px, 0px)`,this.currentPosition=0,this.currentStepDelta=0,this.completedIterations=0,this.hasPosition=!1}syncActiveState(){this.track.style.removeProperty(`animation-name`)}clampCurrentPosition(e){if(this.behavior===`alternate`){let t=Math.min(e.startPosition,e.endPosition),n=Math.max(e.startPosition,e.endPosition);this.currentPosition=Math.min(n,Math.max(t,this.currentPosition));return}if(this.behavior===`slide`){let t=Math.min(e.startPosition,e.endPosition),n=Math.max(e.startPosition,e.endPosition);this.currentPosition=Math.min(n,Math.max(t,this.currentPosition))}}applyCurrentPosition(){if(this.isVerticalDirection){this.track.style.transform=`translate(0px, ${this.currentPosition}px)`;return}this.track.style.transform=`translate(${this.currentPosition}px, 0px)`}emitLegacyEvent(e){this.dispatchEvent(new Event(e))}},O=class extends D{},k=class extends D{};typeof customElements>`u`||(customElements.get(`re-marquee`)||customElements.define(`re-marquee`,O),customElements.get(`re-marquee-ble`)||customElements.define(`re-marquee-ble`,k))})();