JSFiddle - React, Tailwind, and code Playground

by enyojs

CSS

.moon-marquee-text {
    position:relative;
    width:100%;
    overflow:hidden;
    text-overflow:ellipsis;
    white-space:nowrap;
}
.moon-marquee.moon-marquee-text {
    display:inline-block;
    width:auto;
    -webkit-animation-name: marquee;
    -webkit-animation-timing-function: linear;
}

.moon-marquee-clip {
    overflow:hidden;
    width:100%;
}

@-webkit-keyframes marquee
{
    0%      { left:0; }
}

JavaScript

enyo.dispatcher.listen(document, "webkitAnimationEnd");

enyo.kind({
	name: "moon.MarqueeText",
    classes: "moon-marquee-text",
	published: {
        marqueeSpeed: 60,  // px per sec
		marqueePause: 1000,
        clipInsidePadding: false
	},
    create: function() {
        this.inherited(arguments);
        if (this.clipInsidePadding) {
            this.removeClass("moon-marquee-text");
            this.addClass("moon-marquee-clip");
            this.createChrome([{name:"client", classes:"moon-marquee-text"}]);
            this.marqueeControl = this.$.client;
        } else {
            this.marqueeControl = this;
        }
    },
	events: {
		onMarqueeStarted:"",
		onMarqueeEnded:""
	},
	//*@protected
	handlers: {
		onRequestMarquee: "requestMarquee",
		onRequestMarqueeStart: "requestStart",
		onRequestMarqueeStop: "stopMarquee",
        onwebkitAnimationEnd:"animationEnded"
	},
	//*@public
	startMarquee: function() {
        if (!this.marqueeRequested) {
            this.calcMarqueeDistance();
        }
        if (this.marqueeDistance > 0) {
            this.marqueeControl.applyStyle("left", -this.marqueeDistance + "px");
            this.marqueeControl.applyStyle("-webkit-animation-duration", this.marqueeDistance/this.marqueeSpeed + "s");
            this.marqueeControl.addClass("moon-marquee");
		}
	},
	stopMarquee: function() {
        this.stopJob("marquee");
        this.marqueeControl.applyStyle("left", 0);
        this.marqueeControl.removeClass("moon-marquee");
        this.marqueeRequested = false;
		this.doMarqueeEnded();
    },
	//*@protected
    contentChanged: function() {
        if (this.$.client) {
            this.$.client.setContent(this.content);
        }
    },
    calcMarqueeDistance: function() {
        this.marqueeDistance = this.marqueeControl.hasNode().scrollWidth - this.marqueeControl.hasNode().clientWidth;
    },
    requestMarquee: function(inSender, inEvent) {
		enyo.mixin(this, inEvent);
        this.calcMarqueeDistance();
 ...