remarqueeble 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +15 -0
- package/README.md +129 -0
- package/dist/auto.d.ts +1 -0
- package/dist/remarqueeble-auto.cjs +307 -0
- package/dist/remarqueeble-auto.mjs +306 -0
- package/dist/remarqueeble.cjs +307 -0
- package/dist/remarqueeble.d.ts +52 -0
- package/dist/remarqueeble.mjs +303 -0
- package/dist/remarqueeble.umd.js +29 -0
- package/package.json +81 -0
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
/*! remarqueeble v0.1.0 | (c) 2026 Rémino Rem <https://remino.net/> | ISC Licence */
|
|
2
|
+
//#region src/lib/remarqueeble.ts
|
|
3
|
+
var DEFAULT_DIRECTION = "left";
|
|
4
|
+
var DEFAULT_BEHAVIOR = "scroll";
|
|
5
|
+
var DEFAULT_SCROLL_AMOUNT = 6;
|
|
6
|
+
var DEFAULT_SCROLL_DELAY = 85;
|
|
7
|
+
var MIN_SCROLL_DELAY = 60;
|
|
8
|
+
var DEFAULT_VERTICAL_HEIGHT = "200px";
|
|
9
|
+
var DEFAULT_HOST_WIDTH = "calc(100% - (var(--attr-hspace, 0px) * 2))";
|
|
10
|
+
var ATTR_DIRECTION = "direction";
|
|
11
|
+
var ATTR_BEHAVIOR = "behavior";
|
|
12
|
+
var ATTR_SCROLL_AMOUNT = "scrollamount";
|
|
13
|
+
var ATTR_SCROLL_DELAY = "scrolldelay";
|
|
14
|
+
var ATTR_TRUE_SPEED = "truespeed";
|
|
15
|
+
var ATTR_LOOP = "loop";
|
|
16
|
+
var ATTR_BG_COLOR = "bgcolor";
|
|
17
|
+
var ATTR_WIDTH = "width";
|
|
18
|
+
var ATTR_HEIGHT = "height";
|
|
19
|
+
var ATTR_HSPACE = "hspace";
|
|
20
|
+
var ATTR_VSPACE = "vspace";
|
|
21
|
+
var CSS_VAR_WIDTH = "--attr-width";
|
|
22
|
+
var CSS_VAR_HEIGHT = "--attr-height";
|
|
23
|
+
var CSS_VAR_HSPACE = "--attr-hspace";
|
|
24
|
+
var CSS_VAR_VSPACE = "--attr-vspace";
|
|
25
|
+
var CSS_VAR_BG_COLOR = "--attr-bgcolor";
|
|
26
|
+
var HTMLElementBase = globalThis.HTMLElement ?? class {};
|
|
27
|
+
var parsePresentationalDimension = (value) => {
|
|
28
|
+
if (value === null) return null;
|
|
29
|
+
const trimmed = value.trim();
|
|
30
|
+
if (trimmed === "") return null;
|
|
31
|
+
if (/^[+-]?(?:\d+|\d*\.\d+)$/.test(trimmed)) return `${trimmed}px`;
|
|
32
|
+
return globalThis.CSS?.supports("width", trimmed) ? trimmed : null;
|
|
33
|
+
};
|
|
34
|
+
var parseLegacyColor = (value) => {
|
|
35
|
+
if (value === null) return null;
|
|
36
|
+
const trimmed = value.trim();
|
|
37
|
+
if (trimmed === "") return null;
|
|
38
|
+
return globalThis.CSS?.supports("background-color", trimmed) ? trimmed : null;
|
|
39
|
+
};
|
|
40
|
+
var ATTRIBUTE_HINTS = [
|
|
41
|
+
{
|
|
42
|
+
attribute: ATTR_WIDTH,
|
|
43
|
+
cssVar: CSS_VAR_WIDTH,
|
|
44
|
+
parser: parsePresentationalDimension
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
attribute: ATTR_HEIGHT,
|
|
48
|
+
cssVar: CSS_VAR_HEIGHT,
|
|
49
|
+
parser: parsePresentationalDimension,
|
|
50
|
+
fallback(element) {
|
|
51
|
+
return element.isVerticalDirection && !element.hasAttribute(ATTR_HEIGHT) ? DEFAULT_VERTICAL_HEIGHT : null;
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
attribute: ATTR_HSPACE,
|
|
56
|
+
cssVar: CSS_VAR_HSPACE,
|
|
57
|
+
parser: parsePresentationalDimension
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
attribute: ATTR_VSPACE,
|
|
61
|
+
cssVar: CSS_VAR_VSPACE,
|
|
62
|
+
parser: parsePresentationalDimension
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
attribute: ATTR_BG_COLOR,
|
|
66
|
+
cssVar: CSS_VAR_BG_COLOR,
|
|
67
|
+
parser: parseLegacyColor
|
|
68
|
+
}
|
|
69
|
+
];
|
|
70
|
+
var RemarqueebleElement = class extends HTMLElementBase {
|
|
71
|
+
static observedAttributes = [
|
|
72
|
+
ATTR_DIRECTION,
|
|
73
|
+
ATTR_BEHAVIOR,
|
|
74
|
+
ATTR_SCROLL_AMOUNT,
|
|
75
|
+
ATTR_SCROLL_DELAY,
|
|
76
|
+
ATTR_TRUE_SPEED,
|
|
77
|
+
ATTR_LOOP,
|
|
78
|
+
ATTR_BG_COLOR,
|
|
79
|
+
ATTR_WIDTH,
|
|
80
|
+
ATTR_HEIGHT,
|
|
81
|
+
ATTR_HSPACE,
|
|
82
|
+
ATTR_VSPACE
|
|
83
|
+
];
|
|
84
|
+
track;
|
|
85
|
+
running = false;
|
|
86
|
+
position = 0;
|
|
87
|
+
lastTime = null;
|
|
88
|
+
loopsDone = 0;
|
|
89
|
+
forward = true;
|
|
90
|
+
rafId = null;
|
|
91
|
+
constructor() {
|
|
92
|
+
super();
|
|
93
|
+
const shadowRoot = this.attachShadow({ mode: "open" });
|
|
94
|
+
shadowRoot.innerHTML = `
|
|
95
|
+
<style>
|
|
96
|
+
:host {
|
|
97
|
+
display: inline-block;
|
|
98
|
+
text-align: initial;
|
|
99
|
+
overflow: hidden !important;
|
|
100
|
+
white-space: nowrap;
|
|
101
|
+
width: var(${CSS_VAR_WIDTH}, ${DEFAULT_HOST_WIDTH});
|
|
102
|
+
height: var(${CSS_VAR_HEIGHT}, auto);
|
|
103
|
+
margin-inline: var(${CSS_VAR_HSPACE}, 0px);
|
|
104
|
+
margin-block: var(${CSS_VAR_VSPACE}, 0px);
|
|
105
|
+
background-color: var(${CSS_VAR_BG_COLOR}, transparent);
|
|
106
|
+
box-sizing: border-box;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
:host([direction="up"]),
|
|
110
|
+
:host([direction="down"]) {
|
|
111
|
+
white-space: normal;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.track {
|
|
115
|
+
display: inline-block;
|
|
116
|
+
will-change: transform;
|
|
117
|
+
}
|
|
118
|
+
</style>
|
|
119
|
+
|
|
120
|
+
<span class="track"><slot></slot></span>
|
|
121
|
+
`;
|
|
122
|
+
const track = shadowRoot.querySelector(".track");
|
|
123
|
+
if (!track) throw new Error("Remarqueeble track element was not created.");
|
|
124
|
+
this.track = track;
|
|
125
|
+
}
|
|
126
|
+
connectedCallback() {
|
|
127
|
+
this.running = true;
|
|
128
|
+
this.syncPresentationalHints();
|
|
129
|
+
requestAnimationFrame(() => {
|
|
130
|
+
if (!this.isConnected || !this.running) return;
|
|
131
|
+
this.reset();
|
|
132
|
+
this.tick();
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
disconnectedCallback() {
|
|
136
|
+
this.running = false;
|
|
137
|
+
this.lastTime = null;
|
|
138
|
+
if (this.rafId !== null) {
|
|
139
|
+
cancelAnimationFrame(this.rafId);
|
|
140
|
+
this.rafId = null;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
attributeChangedCallback(_name, oldValue, newValue) {
|
|
144
|
+
if (oldValue === newValue) return;
|
|
145
|
+
this.syncPresentationalHints();
|
|
146
|
+
if (this.isConnected) this.reset();
|
|
147
|
+
}
|
|
148
|
+
get direction() {
|
|
149
|
+
return this.getAttribute(ATTR_DIRECTION) || DEFAULT_DIRECTION;
|
|
150
|
+
}
|
|
151
|
+
get behavior() {
|
|
152
|
+
return this.getAttribute(ATTR_BEHAVIOR) || DEFAULT_BEHAVIOR;
|
|
153
|
+
}
|
|
154
|
+
get scrollAmount() {
|
|
155
|
+
const raw = this.getAttribute(ATTR_SCROLL_AMOUNT);
|
|
156
|
+
const value = raw === null || raw.trim() === "" ? NaN : Number(raw);
|
|
157
|
+
return Number.isFinite(value) && value >= 0 ? value : DEFAULT_SCROLL_AMOUNT;
|
|
158
|
+
}
|
|
159
|
+
get scrollDelay() {
|
|
160
|
+
const raw = this.getAttribute(ATTR_SCROLL_DELAY);
|
|
161
|
+
const value = raw === null || raw.trim() === "" ? NaN : Number(raw);
|
|
162
|
+
const delay = Number.isFinite(value) && value >= 0 ? value : DEFAULT_SCROLL_DELAY;
|
|
163
|
+
if (this.hasAttribute(ATTR_TRUE_SPEED)) return delay;
|
|
164
|
+
return Math.max(delay, MIN_SCROLL_DELAY);
|
|
165
|
+
}
|
|
166
|
+
get loop() {
|
|
167
|
+
const value = this.getAttribute(ATTR_LOOP);
|
|
168
|
+
return value === null ? -1 : Number(value);
|
|
169
|
+
}
|
|
170
|
+
get directionSign() {
|
|
171
|
+
return this.direction === "right" || this.direction === "down" ? 1 : -1;
|
|
172
|
+
}
|
|
173
|
+
get isVerticalDirection() {
|
|
174
|
+
return this.direction === "up" || this.direction === "down";
|
|
175
|
+
}
|
|
176
|
+
start() {
|
|
177
|
+
if (this.running) return;
|
|
178
|
+
this.running = true;
|
|
179
|
+
this.lastTime = null;
|
|
180
|
+
this.tick();
|
|
181
|
+
}
|
|
182
|
+
stop() {
|
|
183
|
+
this.running = false;
|
|
184
|
+
if (this.rafId !== null) {
|
|
185
|
+
cancelAnimationFrame(this.rafId);
|
|
186
|
+
this.rafId = null;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
syncPresentationalHints() {
|
|
190
|
+
for (const hint of ATTRIBUTE_HINTS) this.syncVar(hint);
|
|
191
|
+
}
|
|
192
|
+
syncVar(hint) {
|
|
193
|
+
const raw = this.getAttribute(hint.attribute);
|
|
194
|
+
const value = hint.parser(raw);
|
|
195
|
+
const fallback = hint.fallback ? hint.fallback(this) : null;
|
|
196
|
+
if (value == null) {
|
|
197
|
+
if (fallback == null) this.style.removeProperty(hint.cssVar);
|
|
198
|
+
else this.style.setProperty(hint.cssVar, fallback);
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
this.style.setProperty(hint.cssVar, value);
|
|
202
|
+
}
|
|
203
|
+
reset() {
|
|
204
|
+
const hostSize = this.getHostSize();
|
|
205
|
+
const trackSize = this.getTrackSize();
|
|
206
|
+
this.loopsDone = 0;
|
|
207
|
+
this.forward = true;
|
|
208
|
+
this.position = this.behavior === "alternate" ? this.getAlternateStartPosition(hostSize, trackSize) : this.getStartPosition(hostSize, trackSize);
|
|
209
|
+
this.render();
|
|
210
|
+
}
|
|
211
|
+
getHostSize() {
|
|
212
|
+
return this.isVerticalDirection ? this.clientHeight : this.clientWidth;
|
|
213
|
+
}
|
|
214
|
+
getTrackSize() {
|
|
215
|
+
return this.isVerticalDirection ? this.track.offsetHeight : this.track.offsetWidth;
|
|
216
|
+
}
|
|
217
|
+
getStartPosition(hostSize, trackSize) {
|
|
218
|
+
return this.directionSign < 0 ? hostSize : -trackSize;
|
|
219
|
+
}
|
|
220
|
+
getFlushEndPosition(hostSize, trackSize) {
|
|
221
|
+
return this.directionSign < 0 ? 0 : hostSize - trackSize;
|
|
222
|
+
}
|
|
223
|
+
getOffEndPosition(hostSize, trackSize) {
|
|
224
|
+
return this.directionSign < 0 ? -trackSize : hostSize;
|
|
225
|
+
}
|
|
226
|
+
getSlideEndPosition(hostSize, trackSize) {
|
|
227
|
+
return this.directionSign < 0 ? 0 : hostSize - trackSize;
|
|
228
|
+
}
|
|
229
|
+
getAlternateStartPosition(hostSize, trackSize) {
|
|
230
|
+
return this.directionSign < 0 ? hostSize - trackSize : 0;
|
|
231
|
+
}
|
|
232
|
+
tick(time = performance.now()) {
|
|
233
|
+
if (!this.running) return;
|
|
234
|
+
if (this.lastTime === null) this.lastTime = time;
|
|
235
|
+
if (time - this.lastTime >= this.scrollDelay) {
|
|
236
|
+
this.step();
|
|
237
|
+
this.lastTime = time;
|
|
238
|
+
}
|
|
239
|
+
if (!this.running) return;
|
|
240
|
+
this.rafId = requestAnimationFrame((nextTime) => this.tick(nextTime));
|
|
241
|
+
}
|
|
242
|
+
step() {
|
|
243
|
+
const hostSize = this.getHostSize();
|
|
244
|
+
const trackSize = this.getTrackSize();
|
|
245
|
+
const startPosition = this.getStartPosition(hostSize, trackSize);
|
|
246
|
+
const flushEndPosition = this.getFlushEndPosition(hostSize, trackSize);
|
|
247
|
+
const offEndPosition = this.getOffEndPosition(hostSize, trackSize);
|
|
248
|
+
const slideEndPosition = this.getSlideEndPosition(hostSize, trackSize);
|
|
249
|
+
const alternateStartPosition = this.getAlternateStartPosition(hostSize, trackSize);
|
|
250
|
+
const amount = this.scrollAmount;
|
|
251
|
+
const delta = this.directionSign * amount;
|
|
252
|
+
if (this.behavior === "alternate") {
|
|
253
|
+
this.position += this.forward ? delta : -delta;
|
|
254
|
+
if (this.forward) {
|
|
255
|
+
if (this.directionSign < 0 && this.position <= flushEndPosition || this.directionSign > 0 && this.position >= flushEndPosition) {
|
|
256
|
+
this.position = flushEndPosition;
|
|
257
|
+
this.forward = false;
|
|
258
|
+
this.incrementLoopCount();
|
|
259
|
+
if (this.shouldStopAfterLoop()) this.stop();
|
|
260
|
+
}
|
|
261
|
+
} else if (this.directionSign < 0 && this.position >= alternateStartPosition || this.directionSign > 0 && this.position <= alternateStartPosition) {
|
|
262
|
+
this.position = alternateStartPosition;
|
|
263
|
+
this.forward = true;
|
|
264
|
+
this.incrementLoopCount();
|
|
265
|
+
if (this.shouldStopAfterLoop()) this.stop();
|
|
266
|
+
}
|
|
267
|
+
} else if (this.behavior === "slide") {
|
|
268
|
+
this.position += delta;
|
|
269
|
+
if (this.directionSign < 0 && this.position <= slideEndPosition || this.directionSign > 0 && this.position >= slideEndPosition) {
|
|
270
|
+
this.position = slideEndPosition;
|
|
271
|
+
this.incrementLoopCount();
|
|
272
|
+
if (!this.hasAttribute(ATTR_LOOP) || this.loop <= 0) this.stop();
|
|
273
|
+
else if (this.shouldStopAfterLoop()) this.stop();
|
|
274
|
+
else this.position = startPosition;
|
|
275
|
+
}
|
|
276
|
+
} else {
|
|
277
|
+
this.position += delta;
|
|
278
|
+
if (this.directionSign < 0 && this.position <= offEndPosition || this.directionSign > 0 && this.position >= offEndPosition) {
|
|
279
|
+
this.position = startPosition;
|
|
280
|
+
this.incrementLoopCount();
|
|
281
|
+
if (this.shouldStopAfterLoop()) this.stop();
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
this.render();
|
|
285
|
+
}
|
|
286
|
+
incrementLoopCount() {
|
|
287
|
+
this.loopsDone++;
|
|
288
|
+
}
|
|
289
|
+
shouldStopAfterLoop() {
|
|
290
|
+
return this.hasAttribute(ATTR_LOOP) && this.loop > 0 && this.loopsDone >= this.loop;
|
|
291
|
+
}
|
|
292
|
+
render() {
|
|
293
|
+
if (this.isVerticalDirection) this.track.style.transform = `translateY(${this.position}px)`;
|
|
294
|
+
else this.track.style.transform = `translateX(${this.position}px)`;
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
var defineRemarqueebleElements = () => {
|
|
298
|
+
if (typeof customElements === "undefined") return;
|
|
299
|
+
if (!customElements.get("re-marquee")) customElements.define("re-marquee", RemarqueebleElement);
|
|
300
|
+
if (!customElements.get("re-marquee-ble")) customElements.define("re-marquee-ble", RemarqueebleElement);
|
|
301
|
+
};
|
|
302
|
+
//#endregion
|
|
303
|
+
//#region src/lib/auto.ts
|
|
304
|
+
defineRemarqueebleElements();
|
|
305
|
+
//#endregion
|
|
306
|
+
export { defineRemarqueebleElements };
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
/*! remarqueeble v0.1.0 | (c) 2026 Rémino Rem <https://remino.net/> | ISC Licence */
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
//#region src/lib/remarqueeble.ts
|
|
4
|
+
var DEFAULT_DIRECTION = "left";
|
|
5
|
+
var DEFAULT_BEHAVIOR = "scroll";
|
|
6
|
+
var DEFAULT_SCROLL_AMOUNT = 6;
|
|
7
|
+
var DEFAULT_SCROLL_DELAY = 85;
|
|
8
|
+
var MIN_SCROLL_DELAY = 60;
|
|
9
|
+
var DEFAULT_VERTICAL_HEIGHT = "200px";
|
|
10
|
+
var DEFAULT_HOST_WIDTH = "calc(100% - (var(--attr-hspace, 0px) * 2))";
|
|
11
|
+
var ATTR_DIRECTION = "direction";
|
|
12
|
+
var ATTR_BEHAVIOR = "behavior";
|
|
13
|
+
var ATTR_SCROLL_AMOUNT = "scrollamount";
|
|
14
|
+
var ATTR_SCROLL_DELAY = "scrolldelay";
|
|
15
|
+
var ATTR_TRUE_SPEED = "truespeed";
|
|
16
|
+
var ATTR_LOOP = "loop";
|
|
17
|
+
var ATTR_BG_COLOR = "bgcolor";
|
|
18
|
+
var ATTR_WIDTH = "width";
|
|
19
|
+
var ATTR_HEIGHT = "height";
|
|
20
|
+
var ATTR_HSPACE = "hspace";
|
|
21
|
+
var ATTR_VSPACE = "vspace";
|
|
22
|
+
var CSS_VAR_WIDTH = "--attr-width";
|
|
23
|
+
var CSS_VAR_HEIGHT = "--attr-height";
|
|
24
|
+
var CSS_VAR_HSPACE = "--attr-hspace";
|
|
25
|
+
var CSS_VAR_VSPACE = "--attr-vspace";
|
|
26
|
+
var CSS_VAR_BG_COLOR = "--attr-bgcolor";
|
|
27
|
+
var HTMLElementBase = globalThis.HTMLElement ?? class {};
|
|
28
|
+
var parsePresentationalDimension = (value) => {
|
|
29
|
+
if (value === null) return null;
|
|
30
|
+
const trimmed = value.trim();
|
|
31
|
+
if (trimmed === "") return null;
|
|
32
|
+
if (/^[+-]?(?:\d+|\d*\.\d+)$/.test(trimmed)) return `${trimmed}px`;
|
|
33
|
+
return globalThis.CSS?.supports("width", trimmed) ? trimmed : null;
|
|
34
|
+
};
|
|
35
|
+
var parseLegacyColor = (value) => {
|
|
36
|
+
if (value === null) return null;
|
|
37
|
+
const trimmed = value.trim();
|
|
38
|
+
if (trimmed === "") return null;
|
|
39
|
+
return globalThis.CSS?.supports("background-color", trimmed) ? trimmed : null;
|
|
40
|
+
};
|
|
41
|
+
var ATTRIBUTE_HINTS = [
|
|
42
|
+
{
|
|
43
|
+
attribute: ATTR_WIDTH,
|
|
44
|
+
cssVar: CSS_VAR_WIDTH,
|
|
45
|
+
parser: parsePresentationalDimension
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
attribute: ATTR_HEIGHT,
|
|
49
|
+
cssVar: CSS_VAR_HEIGHT,
|
|
50
|
+
parser: parsePresentationalDimension,
|
|
51
|
+
fallback(element) {
|
|
52
|
+
return element.isVerticalDirection && !element.hasAttribute(ATTR_HEIGHT) ? DEFAULT_VERTICAL_HEIGHT : null;
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
attribute: ATTR_HSPACE,
|
|
57
|
+
cssVar: CSS_VAR_HSPACE,
|
|
58
|
+
parser: parsePresentationalDimension
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
attribute: ATTR_VSPACE,
|
|
62
|
+
cssVar: CSS_VAR_VSPACE,
|
|
63
|
+
parser: parsePresentationalDimension
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
attribute: ATTR_BG_COLOR,
|
|
67
|
+
cssVar: CSS_VAR_BG_COLOR,
|
|
68
|
+
parser: parseLegacyColor
|
|
69
|
+
}
|
|
70
|
+
];
|
|
71
|
+
var RemarqueebleElement = class extends HTMLElementBase {
|
|
72
|
+
static observedAttributes = [
|
|
73
|
+
ATTR_DIRECTION,
|
|
74
|
+
ATTR_BEHAVIOR,
|
|
75
|
+
ATTR_SCROLL_AMOUNT,
|
|
76
|
+
ATTR_SCROLL_DELAY,
|
|
77
|
+
ATTR_TRUE_SPEED,
|
|
78
|
+
ATTR_LOOP,
|
|
79
|
+
ATTR_BG_COLOR,
|
|
80
|
+
ATTR_WIDTH,
|
|
81
|
+
ATTR_HEIGHT,
|
|
82
|
+
ATTR_HSPACE,
|
|
83
|
+
ATTR_VSPACE
|
|
84
|
+
];
|
|
85
|
+
track;
|
|
86
|
+
running = false;
|
|
87
|
+
position = 0;
|
|
88
|
+
lastTime = null;
|
|
89
|
+
loopsDone = 0;
|
|
90
|
+
forward = true;
|
|
91
|
+
rafId = null;
|
|
92
|
+
constructor() {
|
|
93
|
+
super();
|
|
94
|
+
const shadowRoot = this.attachShadow({ mode: "open" });
|
|
95
|
+
shadowRoot.innerHTML = `
|
|
96
|
+
<style>
|
|
97
|
+
:host {
|
|
98
|
+
display: inline-block;
|
|
99
|
+
text-align: initial;
|
|
100
|
+
overflow: hidden !important;
|
|
101
|
+
white-space: nowrap;
|
|
102
|
+
width: var(${CSS_VAR_WIDTH}, ${DEFAULT_HOST_WIDTH});
|
|
103
|
+
height: var(${CSS_VAR_HEIGHT}, auto);
|
|
104
|
+
margin-inline: var(${CSS_VAR_HSPACE}, 0px);
|
|
105
|
+
margin-block: var(${CSS_VAR_VSPACE}, 0px);
|
|
106
|
+
background-color: var(${CSS_VAR_BG_COLOR}, transparent);
|
|
107
|
+
box-sizing: border-box;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
:host([direction="up"]),
|
|
111
|
+
:host([direction="down"]) {
|
|
112
|
+
white-space: normal;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.track {
|
|
116
|
+
display: inline-block;
|
|
117
|
+
will-change: transform;
|
|
118
|
+
}
|
|
119
|
+
</style>
|
|
120
|
+
|
|
121
|
+
<span class="track"><slot></slot></span>
|
|
122
|
+
`;
|
|
123
|
+
const track = shadowRoot.querySelector(".track");
|
|
124
|
+
if (!track) throw new Error("Remarqueeble track element was not created.");
|
|
125
|
+
this.track = track;
|
|
126
|
+
}
|
|
127
|
+
connectedCallback() {
|
|
128
|
+
this.running = true;
|
|
129
|
+
this.syncPresentationalHints();
|
|
130
|
+
requestAnimationFrame(() => {
|
|
131
|
+
if (!this.isConnected || !this.running) return;
|
|
132
|
+
this.reset();
|
|
133
|
+
this.tick();
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
disconnectedCallback() {
|
|
137
|
+
this.running = false;
|
|
138
|
+
this.lastTime = null;
|
|
139
|
+
if (this.rafId !== null) {
|
|
140
|
+
cancelAnimationFrame(this.rafId);
|
|
141
|
+
this.rafId = null;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
attributeChangedCallback(_name, oldValue, newValue) {
|
|
145
|
+
if (oldValue === newValue) return;
|
|
146
|
+
this.syncPresentationalHints();
|
|
147
|
+
if (this.isConnected) this.reset();
|
|
148
|
+
}
|
|
149
|
+
get direction() {
|
|
150
|
+
return this.getAttribute(ATTR_DIRECTION) || DEFAULT_DIRECTION;
|
|
151
|
+
}
|
|
152
|
+
get behavior() {
|
|
153
|
+
return this.getAttribute(ATTR_BEHAVIOR) || DEFAULT_BEHAVIOR;
|
|
154
|
+
}
|
|
155
|
+
get scrollAmount() {
|
|
156
|
+
const raw = this.getAttribute(ATTR_SCROLL_AMOUNT);
|
|
157
|
+
const value = raw === null || raw.trim() === "" ? NaN : Number(raw);
|
|
158
|
+
return Number.isFinite(value) && value >= 0 ? value : DEFAULT_SCROLL_AMOUNT;
|
|
159
|
+
}
|
|
160
|
+
get scrollDelay() {
|
|
161
|
+
const raw = this.getAttribute(ATTR_SCROLL_DELAY);
|
|
162
|
+
const value = raw === null || raw.trim() === "" ? NaN : Number(raw);
|
|
163
|
+
const delay = Number.isFinite(value) && value >= 0 ? value : DEFAULT_SCROLL_DELAY;
|
|
164
|
+
if (this.hasAttribute(ATTR_TRUE_SPEED)) return delay;
|
|
165
|
+
return Math.max(delay, MIN_SCROLL_DELAY);
|
|
166
|
+
}
|
|
167
|
+
get loop() {
|
|
168
|
+
const value = this.getAttribute(ATTR_LOOP);
|
|
169
|
+
return value === null ? -1 : Number(value);
|
|
170
|
+
}
|
|
171
|
+
get directionSign() {
|
|
172
|
+
return this.direction === "right" || this.direction === "down" ? 1 : -1;
|
|
173
|
+
}
|
|
174
|
+
get isVerticalDirection() {
|
|
175
|
+
return this.direction === "up" || this.direction === "down";
|
|
176
|
+
}
|
|
177
|
+
start() {
|
|
178
|
+
if (this.running) return;
|
|
179
|
+
this.running = true;
|
|
180
|
+
this.lastTime = null;
|
|
181
|
+
this.tick();
|
|
182
|
+
}
|
|
183
|
+
stop() {
|
|
184
|
+
this.running = false;
|
|
185
|
+
if (this.rafId !== null) {
|
|
186
|
+
cancelAnimationFrame(this.rafId);
|
|
187
|
+
this.rafId = null;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
syncPresentationalHints() {
|
|
191
|
+
for (const hint of ATTRIBUTE_HINTS) this.syncVar(hint);
|
|
192
|
+
}
|
|
193
|
+
syncVar(hint) {
|
|
194
|
+
const raw = this.getAttribute(hint.attribute);
|
|
195
|
+
const value = hint.parser(raw);
|
|
196
|
+
const fallback = hint.fallback ? hint.fallback(this) : null;
|
|
197
|
+
if (value == null) {
|
|
198
|
+
if (fallback == null) this.style.removeProperty(hint.cssVar);
|
|
199
|
+
else this.style.setProperty(hint.cssVar, fallback);
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
this.style.setProperty(hint.cssVar, value);
|
|
203
|
+
}
|
|
204
|
+
reset() {
|
|
205
|
+
const hostSize = this.getHostSize();
|
|
206
|
+
const trackSize = this.getTrackSize();
|
|
207
|
+
this.loopsDone = 0;
|
|
208
|
+
this.forward = true;
|
|
209
|
+
this.position = this.behavior === "alternate" ? this.getAlternateStartPosition(hostSize, trackSize) : this.getStartPosition(hostSize, trackSize);
|
|
210
|
+
this.render();
|
|
211
|
+
}
|
|
212
|
+
getHostSize() {
|
|
213
|
+
return this.isVerticalDirection ? this.clientHeight : this.clientWidth;
|
|
214
|
+
}
|
|
215
|
+
getTrackSize() {
|
|
216
|
+
return this.isVerticalDirection ? this.track.offsetHeight : this.track.offsetWidth;
|
|
217
|
+
}
|
|
218
|
+
getStartPosition(hostSize, trackSize) {
|
|
219
|
+
return this.directionSign < 0 ? hostSize : -trackSize;
|
|
220
|
+
}
|
|
221
|
+
getFlushEndPosition(hostSize, trackSize) {
|
|
222
|
+
return this.directionSign < 0 ? 0 : hostSize - trackSize;
|
|
223
|
+
}
|
|
224
|
+
getOffEndPosition(hostSize, trackSize) {
|
|
225
|
+
return this.directionSign < 0 ? -trackSize : hostSize;
|
|
226
|
+
}
|
|
227
|
+
getSlideEndPosition(hostSize, trackSize) {
|
|
228
|
+
return this.directionSign < 0 ? 0 : hostSize - trackSize;
|
|
229
|
+
}
|
|
230
|
+
getAlternateStartPosition(hostSize, trackSize) {
|
|
231
|
+
return this.directionSign < 0 ? hostSize - trackSize : 0;
|
|
232
|
+
}
|
|
233
|
+
tick(time = performance.now()) {
|
|
234
|
+
if (!this.running) return;
|
|
235
|
+
if (this.lastTime === null) this.lastTime = time;
|
|
236
|
+
if (time - this.lastTime >= this.scrollDelay) {
|
|
237
|
+
this.step();
|
|
238
|
+
this.lastTime = time;
|
|
239
|
+
}
|
|
240
|
+
if (!this.running) return;
|
|
241
|
+
this.rafId = requestAnimationFrame((nextTime) => this.tick(nextTime));
|
|
242
|
+
}
|
|
243
|
+
step() {
|
|
244
|
+
const hostSize = this.getHostSize();
|
|
245
|
+
const trackSize = this.getTrackSize();
|
|
246
|
+
const startPosition = this.getStartPosition(hostSize, trackSize);
|
|
247
|
+
const flushEndPosition = this.getFlushEndPosition(hostSize, trackSize);
|
|
248
|
+
const offEndPosition = this.getOffEndPosition(hostSize, trackSize);
|
|
249
|
+
const slideEndPosition = this.getSlideEndPosition(hostSize, trackSize);
|
|
250
|
+
const alternateStartPosition = this.getAlternateStartPosition(hostSize, trackSize);
|
|
251
|
+
const amount = this.scrollAmount;
|
|
252
|
+
const delta = this.directionSign * amount;
|
|
253
|
+
if (this.behavior === "alternate") {
|
|
254
|
+
this.position += this.forward ? delta : -delta;
|
|
255
|
+
if (this.forward) {
|
|
256
|
+
if (this.directionSign < 0 && this.position <= flushEndPosition || this.directionSign > 0 && this.position >= flushEndPosition) {
|
|
257
|
+
this.position = flushEndPosition;
|
|
258
|
+
this.forward = false;
|
|
259
|
+
this.incrementLoopCount();
|
|
260
|
+
if (this.shouldStopAfterLoop()) this.stop();
|
|
261
|
+
}
|
|
262
|
+
} else if (this.directionSign < 0 && this.position >= alternateStartPosition || this.directionSign > 0 && this.position <= alternateStartPosition) {
|
|
263
|
+
this.position = alternateStartPosition;
|
|
264
|
+
this.forward = true;
|
|
265
|
+
this.incrementLoopCount();
|
|
266
|
+
if (this.shouldStopAfterLoop()) this.stop();
|
|
267
|
+
}
|
|
268
|
+
} else if (this.behavior === "slide") {
|
|
269
|
+
this.position += delta;
|
|
270
|
+
if (this.directionSign < 0 && this.position <= slideEndPosition || this.directionSign > 0 && this.position >= slideEndPosition) {
|
|
271
|
+
this.position = slideEndPosition;
|
|
272
|
+
this.incrementLoopCount();
|
|
273
|
+
if (!this.hasAttribute(ATTR_LOOP) || this.loop <= 0) this.stop();
|
|
274
|
+
else if (this.shouldStopAfterLoop()) this.stop();
|
|
275
|
+
else this.position = startPosition;
|
|
276
|
+
}
|
|
277
|
+
} else {
|
|
278
|
+
this.position += delta;
|
|
279
|
+
if (this.directionSign < 0 && this.position <= offEndPosition || this.directionSign > 0 && this.position >= offEndPosition) {
|
|
280
|
+
this.position = startPosition;
|
|
281
|
+
this.incrementLoopCount();
|
|
282
|
+
if (this.shouldStopAfterLoop()) this.stop();
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
this.render();
|
|
286
|
+
}
|
|
287
|
+
incrementLoopCount() {
|
|
288
|
+
this.loopsDone++;
|
|
289
|
+
}
|
|
290
|
+
shouldStopAfterLoop() {
|
|
291
|
+
return this.hasAttribute(ATTR_LOOP) && this.loop > 0 && this.loopsDone >= this.loop;
|
|
292
|
+
}
|
|
293
|
+
render() {
|
|
294
|
+
if (this.isVerticalDirection) this.track.style.transform = `translateY(${this.position}px)`;
|
|
295
|
+
else this.track.style.transform = `translateX(${this.position}px)`;
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
var defineRemarqueebleElements = () => {
|
|
299
|
+
if (typeof customElements === "undefined") return;
|
|
300
|
+
if (!customElements.get("re-marquee")) customElements.define("re-marquee", RemarqueebleElement);
|
|
301
|
+
if (!customElements.get("re-marquee-ble")) customElements.define("re-marquee-ble", RemarqueebleElement);
|
|
302
|
+
};
|
|
303
|
+
//#endregion
|
|
304
|
+
exports.RemarqueebleElement = RemarqueebleElement;
|
|
305
|
+
exports.defineRemarqueebleElements = defineRemarqueebleElements;
|
|
306
|
+
exports.parseLegacyColor = parseLegacyColor;
|
|
307
|
+
exports.parsePresentationalDimension = parsePresentationalDimension;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
declare const HTMLElementBase: {
|
|
2
|
+
new (): HTMLElement;
|
|
3
|
+
prototype: HTMLElement;
|
|
4
|
+
};
|
|
5
|
+
export declare const parsePresentationalDimension: (value: string | null) => string | null;
|
|
6
|
+
export declare const parseLegacyColor: (value: string | null) => string | null;
|
|
7
|
+
export declare class RemarqueebleElement extends HTMLElementBase {
|
|
8
|
+
static observedAttributes: string[];
|
|
9
|
+
private readonly track;
|
|
10
|
+
private running;
|
|
11
|
+
private position;
|
|
12
|
+
private lastTime;
|
|
13
|
+
private loopsDone;
|
|
14
|
+
private forward;
|
|
15
|
+
private rafId;
|
|
16
|
+
constructor();
|
|
17
|
+
connectedCallback(): void;
|
|
18
|
+
disconnectedCallback(): void;
|
|
19
|
+
attributeChangedCallback(_name: string, oldValue: string | null, newValue: string | null): void;
|
|
20
|
+
get direction(): string;
|
|
21
|
+
get behavior(): string;
|
|
22
|
+
get scrollAmount(): number;
|
|
23
|
+
get scrollDelay(): number;
|
|
24
|
+
get loop(): number;
|
|
25
|
+
get directionSign(): number;
|
|
26
|
+
get isVerticalDirection(): boolean;
|
|
27
|
+
start(): void;
|
|
28
|
+
stop(): void;
|
|
29
|
+
private syncPresentationalHints;
|
|
30
|
+
private syncVar;
|
|
31
|
+
private reset;
|
|
32
|
+
private getHostSize;
|
|
33
|
+
private getTrackSize;
|
|
34
|
+
private getStartPosition;
|
|
35
|
+
private getFlushEndPosition;
|
|
36
|
+
private getOffEndPosition;
|
|
37
|
+
private getSlideEndPosition;
|
|
38
|
+
private getAlternateStartPosition;
|
|
39
|
+
private tick;
|
|
40
|
+
private step;
|
|
41
|
+
private incrementLoopCount;
|
|
42
|
+
private shouldStopAfterLoop;
|
|
43
|
+
private render;
|
|
44
|
+
}
|
|
45
|
+
export declare const defineRemarqueebleElements: () => void;
|
|
46
|
+
declare global {
|
|
47
|
+
interface HTMLElementTagNameMap {
|
|
48
|
+
're-marquee': RemarqueebleElement;
|
|
49
|
+
're-marquee-ble': RemarqueebleElement;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
export {};
|