@unlazy/core
Version:
Universal lazy loading library for placeholder images leveraging native browser APIs
134 lines (133 loc) • 2.98 kB
JavaScript
//#region src/constants.ts
const DEFAULT_IMAGE_PLACEHOLDER = `data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1 1'%3E%3C/svg%3E`;
//#endregion
//#region src/utils/png.ts
/**
* Encodes an RGBA image to a PNG data URI. RGB should not be premultiplied by A.
*
* @remarks
* This is optimized for speed and simplicity and does not optimize for size
* at all. This does not do any compression (all values are stored uncompressed).
*
* @see https://github.com/evanw/thumbhash
* @author Evan Wallace
* @license MIT
*/
function rgbaToDataUri(w, h, rgba) {
const row = w * 4 + 1;
const idat = 6 + h * (5 + row);
const bytes = [
137,
80,
78,
71,
13,
10,
26,
10,
0,
0,
0,
13,
73,
72,
68,
82,
0,
0,
w >> 8,
w & 255,
0,
0,
h >> 8,
h & 255,
8,
6,
0,
0,
0,
0,
0,
0,
0,
idat >>> 24,
idat >> 16 & 255,
idat >> 8 & 255,
idat & 255,
73,
68,
65,
84,
120,
1
];
const table = [
0,
498536548,
997073096,
651767980,
1994146192,
1802195444,
1303535960,
1342533948,
-306674912,
-267414716,
-690576408,
-882789492,
-1687895376,
-2032938284,
-1609899400,
-1111625188
];
let a = 1;
let b = 0;
for (let y = 0, i = 0, end = row - 1; y < h; y++, end += row - 1) {
bytes.push(y + 1 < h ? 0 : 1, row & 255, row >> 8, ~row & 255, row >> 8 ^ 255, 0);
for (b = (b + a) % 65521; i < end; i++) {
const u = rgba[i] & 255;
bytes.push(u);
a = (a + u) % 65521;
b = (b + a) % 65521;
}
}
bytes.push(b >> 8, b & 255, a >> 8, a & 255, 0, 0, 0, 0, 0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130);
for (let [start, end] of [[12, 29], [37, 41 + idat]]) {
let c = -1;
for (let i = start; i < end; i++) {
c ^= bytes[i];
c = c >>> 4 ^ table[c & 15];
c = c >>> 4 ^ table[c & 15];
}
c = ~c;
bytes[end++] = c >>> 24;
bytes[end++] = c >> 16 & 255;
bytes[end++] = c >> 8 & 255;
bytes[end++] = c & 255;
}
return `data:image/png;base64,${globalThis.btoa(String.fromCharCode(...bytes))}`;
}
//#endregion
//#region src/utils/index.ts
const isSSR = typeof window === "undefined";
const isCrawler = !isSSR && (!("onscroll" in window) || /(?:gle|ing|ro)bot|crawl|spider/i.test(navigator.userAgent));
function toElementArray(target, parentElement = document) {
if (typeof target === "string") return [...parentElement.querySelectorAll(target)];
if (target instanceof Element) return [target];
return [...target];
}
function createIndexedImagePlaceholder(index) {
const now = Date.now();
return DEFAULT_IMAGE_PLACEHOLDER.replace(/\s/, ` data-id='${now}-${index}' `);
}
function debounce(fn, delay) {
let timeoutId;
return function(...args) {
if (timeoutId != null) clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
fn(...args);
timeoutId = void 0;
}, delay);
};
}
//#endregion
export { toElementArray as a, isSSR as i, debounce as n, rgbaToDataUri as o, isCrawler as r, createIndexedImagePlaceholder as t };