refactor(modules/web): Mirgrat to typescript; fix bugs

This commit is contained in:
Xwite
2024-10-14 21:43:36 +08:00
parent 3eded53041
commit 30b31b9c96
81 changed files with 6396 additions and 3166 deletions

18
modules/web/src/plugins/jump.d.ts vendored Normal file
View File

@@ -0,0 +1,18 @@
export {}
export type Options = {
duration?: number | [(distance: number) => number]
offset?: number
callback?: () => void // "undefined" is a suitable default, and won't be called
easing?: (
timeElapsed: number,
start: number,
distance: number,
duration: number,
) => number
a11y?: boolean
container?: HTMLElement | string
}
export default function (
target: number | string | HTMLElement,
options: Options = {},
): void

View File

@@ -1,51 +1,51 @@
const easeInOutQuad = (t, b, c, d) => {
t /= d / 2;
if (t < 1) return (c / 2) * t * t + b;
t--;
return (-c / 2) * (t * (t - 2) - 1) + b;
};
t /= d / 2
if (t < 1) return (c / 2) * t * t + b
t--
return (-c / 2) * (t * (t - 2) - 1) + b
}
const jumper = () => {
// private variable cache
// no variables are created during a jump, preventing memory leaks
let container; // container element to be scrolled (node)
let element; // element to scroll to (node)
let container // container element to be scrolled (node)
let element // element to scroll to (node)
let start; // where scroll starts (px)
let stop; // where scroll stops (px)
let start // where scroll starts (px)
let stop // where scroll stops (px)
let offset; // adjustment from the stop position (px)
let easing; // easing function (function)
let a11y; // accessibility support flag (boolean)
let offset // adjustment from the stop position (px)
let easing // easing function (function)
let a11y // accessibility support flag (boolean)
let distance; // distance of scroll (px)
let duration; // scroll duration (ms)
let distance // distance of scroll (px)
let duration // scroll duration (ms)
let timeStart; // time scroll started (ms)
let timeElapsed; // time spent scrolling thus far (ms)
let timeStart // time scroll started (ms)
let timeElapsed // time spent scrolling thus far (ms)
let next; // next scroll position (px)
let next // next scroll position (px)
let callback; // to call when done scrolling (function)
let callback // to call when done scrolling (function)
// scroll position helper
function location() {
let top = container.scrollTop || container.scrollY || container.pageYOffset;
top = typeof top === "undefined" ? 0 : top;
return top;
let top = container.scrollTop || container.scrollY || container.pageYOffset
top = typeof top === 'undefined' ? 0 : top
return top
}
// element offset helper
function top(element) {
const elementTop = element.getBoundingClientRect().top;
const elementTop = element.getBoundingClientRect().top
const containerTop = container.getBoundingClientRect
? container.getBoundingClientRect().top
: 0;
: 0
return elementTop - containerTop + start;
return elementTop - containerTop + start
}
// scrollTo helper
@@ -53,7 +53,7 @@ const jumper = () => {
function scrollTo(top) {
container.scrollTo
? container.scrollTo(0, top) // window
: (container.scrollTop = top); // custom container
: (container.scrollTop = top) // custom container
}
// rAF loop helper
@@ -61,126 +61,126 @@ const jumper = () => {
function loop(timeCurrent) {
// store time scroll started, if not started already
if (!timeStart) {
timeStart = timeCurrent;
timeStart = timeCurrent
}
// determine time spent scrolling so far
timeElapsed = timeCurrent - timeStart;
timeElapsed = timeCurrent - timeStart
// calculate next scroll position
next = easing(timeElapsed, start, distance, duration);
next = easing(timeElapsed, start, distance, duration)
// scroll to it
scrollTo(next);
scrollTo(next)
// check progress
timeElapsed < duration
? requestAnimationFrame(loop) // continue scroll loop
: done(); // scrolling is done
: done() // scrolling is done
}
// scroll finished helper
function done() {
// account for rAF time rounding inaccuracies
scrollTo(start + distance);
scrollTo(start + distance)
// if scrolling to an element, and accessibility is enabled
if (element && a11y) {
// add tabindex indicating programmatic focus
element.setAttribute("tabindex", "-1");
element.setAttribute('tabindex', '-1')
// focus the element
element.focus();
element.focus()
}
// if it exists, fire the callback
if (typeof callback === "function") {
callback();
if (typeof callback === 'function') {
callback()
}
// reset time for next jump
timeStart = false;
timeStart = false
}
// API
function jump(target, options = {}) {
// resolve options, or use defaults
duration = options.duration || 1000;
offset = options.offset || 0;
callback = options.callback; // "undefined" is a suitable default, and won't be called
easing = options.easing || easeInOutQuad;
a11y = options.a11y || false;
duration = options.duration || 1000
offset = options.offset || 0
callback = options.callback // "undefined" is a suitable default, and won't be called
easing = options.easing || easeInOutQuad
a11y = options.a11y || false
// resolve container
switch (typeof options.container) {
case "object":
case 'object':
// we assume container is an HTML element (Node)
container = options.container;
break;
container = options.container
break
case "string":
container = document.querySelector(options.container);
break;
case 'string':
container = document.querySelector(options.container)
break
default:
container = window;
container = window
}
// cache starting position
start = location();
start = location()
// resolve target
switch (typeof target) {
// scroll from current position
case "number":
element = undefined; // no element to scroll to
a11y = false; // make sure accessibility is off
stop = start + target;
break;
case 'number':
element = undefined // no element to scroll to
a11y = false // make sure accessibility is off
stop = start + target
break
// scroll to element (node)
// bounding rect is relative to the viewport
case "object":
element = target;
stop = top(element);
break;
case 'object':
element = target
stop = top(element)
break
// scroll to element (selector)
// bounding rect is relative to the viewport
case "string":
element = document.querySelector(target);
stop = top(element);
break;
case 'string':
element = document.querySelector(target)
stop = top(element)
break
}
// resolve scroll distance, accounting for offset
distance = stop - start + offset;
distance = stop - start + offset
// resolve duration
switch (typeof options.duration) {
// number in ms
case "number":
duration = options.duration;
break;
case 'number':
duration = options.duration
break
// function passed the distance of the scroll
case "function":
duration = options.duration(distance);
break;
case 'function':
duration = options.duration(distance)
break
}
// start the loop
requestAnimationFrame(loop);
requestAnimationFrame(loop)
}
// expose only the jump method
return jump;
};
return jump
}
// export singleton
const singleton = jumper();
const singleton = jumper()
export default singleton;
export default singleton