image-exporter 0.0.1 → 1.0.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/README.md +137 -2
- package/bun.lockb +0 -0
- package/dist/image-exporter.es.js +499 -612
- package/dist/image-exporter.umd.js +506 -619
- package/package.json +18 -15
- package/src/capture/capture-element.ts +58 -0
- package/src/capture/determine-total-elements.ts +40 -0
- package/src/capture/download-images.ts +69 -0
- package/src/capture/get-image-options.ts +196 -0
- package/src/capture/handle-filenames.ts +52 -0
- package/src/capture/index.ts +99 -0
- package/src/capture/remove-hidden-elements.ts +19 -0
- package/src/config.ts +19 -0
- package/src/cors-proxy/cleanup.ts +43 -0
- package/src/cors-proxy/index.ts +6 -21
- package/src/{utils → cors-proxy}/is-valid-url.ts +5 -3
- package/src/cors-proxy/proxy-css.ts +51 -44
- package/src/cors-proxy/proxy-images.ts +21 -77
- package/src/cors-proxy/run.ts +26 -0
- package/src/index.ts +10 -4
- package/src/logger.ts +61 -0
- package/src/types.d.ts +51 -0
- package/vite.config.js +3 -7
- package/example/example.css +0 -122
- package/example/example.html +0 -152
- package/example/github.jpg +0 -0
- package/example/poll-h.svg +0 -1
- package/src/capture-images.ts +0 -129
- package/src/clean-up.ts +0 -50
- package/src/default-options.ts +0 -58
- package/src/download-images.ts +0 -52
- package/src/get-capture-element.test.html +0 -21
- package/src/get-capture-element.test.ts +0 -36
- package/src/get-capture-element.ts +0 -175
- package/src/get-options/get-input-options.test.html +0 -217
- package/src/get-options/get-input-options.test.ts +0 -109
- package/src/get-options/get-input-options.ts +0 -40
- package/src/get-options/get-item-options.ts +0 -46
- package/src/get-options/get-wrapper-options.test.html +0 -33
- package/src/get-options/get-wrapper-options.test.ts +0 -109
- package/src/get-options/get-wrapper-options.ts +0 -84
- package/src/get-options/index.ts +0 -28
- package/src/image-exporter.ts +0 -108
- package/src/types/image.ts +0 -2
- package/src/types/index.ts +0 -2
- package/src/types/options.ts +0 -69
- package/src/utils/convert-to-slug.ts +0 -15
- package/src/utils/get-attribute-values.ts +0 -68
- package/src/utils/get-date-MMDDYY.ts +0 -11
- package/src/utils/ignore-items.ts +0 -11
- package/src/utils/index.ts +0 -18
- package/src/utils/is-visible.ts +0 -12
- package/src/utils/parse-labels.ts +0 -55
- package/src/utils/push-to-window.ts +0 -3
- package/tests/index.html +0 -88
- package/tests/input-tests.html +0 -169
package/src/cors-proxy/index.ts
CHANGED
|
@@ -1,22 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { proxyImages } from "./proxy-images";
|
|
4
|
-
import { Options } from "../types/options";
|
|
1
|
+
import { runCorsProxy } from "./run";
|
|
2
|
+
import { cleanUpCorsProxy } from "./cleanup";
|
|
5
3
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
export async function runCorsProxy(options: Options): Promise<void> {
|
|
12
|
-
try {
|
|
13
|
-
if (!options.corsProxyBaseUrl || !isValidUrl(options.corsProxyBaseUrl)) return;
|
|
14
|
-
|
|
15
|
-
await proxyCSS(options);
|
|
16
|
-
await proxyImages(options);
|
|
17
|
-
|
|
18
|
-
return;
|
|
19
|
-
} catch (e) {
|
|
20
|
-
console.error("ImageExporter: Error in runCorsProxy", e);
|
|
21
|
-
}
|
|
22
|
-
}
|
|
4
|
+
export const corsProxy = {
|
|
5
|
+
run: runCorsProxy,
|
|
6
|
+
cleanUp: cleanUpCorsProxy,
|
|
7
|
+
};
|
|
@@ -1,14 +1,16 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* isValidUrl
|
|
3
|
+
*
|
|
4
|
+
* Checks if a string is a valid external URL.
|
|
5
|
+
*/
|
|
2
6
|
export function isValidUrl(string: string): boolean {
|
|
3
7
|
try {
|
|
4
8
|
const url = new URL(string);
|
|
5
9
|
|
|
6
|
-
// Check if the URL is a data URL
|
|
7
10
|
if (url.protocol === "data:") {
|
|
8
11
|
return false;
|
|
9
12
|
}
|
|
10
13
|
|
|
11
|
-
// Optionally, check for HTTP and HTTPS protocols specifically
|
|
12
14
|
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
13
15
|
return false;
|
|
14
16
|
}
|
|
@@ -1,52 +1,59 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
1
|
+
import { log } from "../logger";
|
|
2
|
+
import { Config } from "../types";
|
|
3
|
+
import { isValidUrl } from "./is-valid-url";
|
|
4
|
+
|
|
3
5
|
/**
|
|
4
|
-
* proxyCSS
|
|
5
|
-
* Each valid and non-data URL stylesheet's href attribute is updated with the proxy URL.
|
|
6
|
+
* proxyCSS
|
|
6
7
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* - corsProxyBaseURL: String - The base URL of the CORS proxy server.
|
|
10
|
-
* @param {number} proxyPings - Initial count of proxy server pings.
|
|
11
|
-
* @returns {Promise<number>} - Returns the updated count of proxy server pings after processing stylesheets.
|
|
8
|
+
* Proxies all linked CSS files and the absolute URLs inside them, including fonts and images.
|
|
9
|
+
* Upon completion of capture, the links will be restored and the style elements removed.
|
|
12
10
|
*/
|
|
11
|
+
export async function proxyCSS(config: Config) {
|
|
12
|
+
const stylesheetElements = document.querySelectorAll('link[rel="stylesheet"]');
|
|
13
|
+
log.verbose("stylesheet elements to proxy", stylesheetElements.length);
|
|
14
|
+
|
|
15
|
+
for (let stylesheetElement of stylesheetElements) {
|
|
16
|
+
const stylesheetURL = stylesheetElement.getAttribute("href");
|
|
17
|
+
|
|
18
|
+
// Exclude data URLs, invalid URLs, and already proxied URLs
|
|
19
|
+
if (!stylesheetURL) continue;
|
|
20
|
+
if (stylesheetURL.startsWith("data:")) continue;
|
|
21
|
+
if (stylesheetURL.startsWith(config.corsProxyBaseUrl)) continue;
|
|
22
|
+
if (!isValidUrl(stylesheetURL)) continue;
|
|
23
|
+
|
|
24
|
+
stylesheetElement.setAttribute("crossorigin", "anonymous");
|
|
25
|
+
const proxiedURL = config.corsProxyBaseUrl + encodeURIComponent(stylesheetURL);
|
|
13
26
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
) {
|
|
28
|
-
const url = options.corsProxyBaseUrl + encodeURIComponent(stylesheetURL);
|
|
29
|
-
|
|
30
|
-
try {
|
|
31
|
-
// Fetch the CSS content
|
|
32
|
-
const response = await fetch(url);
|
|
33
|
-
const css = await response.text();
|
|
34
|
-
|
|
35
|
-
// Create a <style> element and set its content
|
|
36
|
-
const styleEl = document.createElement("style");
|
|
37
|
-
styleEl.textContent = css;
|
|
38
|
-
|
|
39
|
-
// Append the <style> element to the document's <head>
|
|
40
|
-
document.head.appendChild(styleEl);
|
|
41
|
-
|
|
42
|
-
// Remove the original <link> element
|
|
43
|
-
stylesheetElement.remove();
|
|
44
|
-
} catch (error) {
|
|
45
|
-
console.error("Error fetching CSS:", error);
|
|
27
|
+
try {
|
|
28
|
+
// Fetch the CSS content
|
|
29
|
+
const response = await fetch(proxiedURL);
|
|
30
|
+
let cssContent = await response.text();
|
|
31
|
+
|
|
32
|
+
// Proxy absolute URLs (http/https) within the CSS content
|
|
33
|
+
cssContent = cssContent.replace(
|
|
34
|
+
/url\(['"]?(https?:\/\/[^'")\s]+)['"]?\)/g,
|
|
35
|
+
(match, url) => {
|
|
36
|
+
// Skip if already proxied
|
|
37
|
+
if (url.startsWith(config.corsProxyBaseUrl)) return match;
|
|
38
|
+
// Otherwise return proxied URL
|
|
39
|
+
return `url("${config.corsProxyBaseUrl}${encodeURIComponent(url)}")`;
|
|
46
40
|
}
|
|
47
|
-
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
// Insert the parsed CSS content into a <style> element
|
|
44
|
+
const styleElement = document.createElement("style");
|
|
45
|
+
styleElement.textContent = cssContent;
|
|
46
|
+
styleElement.setAttribute(
|
|
47
|
+
"original-link-element",
|
|
48
|
+
encodeURIComponent(stylesheetElement.outerHTML)
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
// Insert the <style> element directly after the original <link> element to easy restoration
|
|
52
|
+
stylesheetElement.insertAdjacentElement("afterend", styleElement);
|
|
53
|
+
stylesheetElement.remove();
|
|
54
|
+
log.verbose("Proxied: ", stylesheetURL);
|
|
55
|
+
} catch (error) {
|
|
56
|
+
console.error("Error fetching CSS:", error);
|
|
48
57
|
}
|
|
49
|
-
} catch (e) {
|
|
50
|
-
console.error("ImageExporter: Error in proxyCSS", e);
|
|
51
58
|
}
|
|
52
59
|
}
|
|
@@ -1,71 +1,30 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
1
|
+
import { Config } from "../types";
|
|
2
|
+
import { isValidUrl } from "./is-valid-url";
|
|
3
|
+
import { log } from "../logger";
|
|
4
|
+
|
|
3
5
|
/**
|
|
4
|
-
* proxyImages
|
|
5
|
-
* Groups images by their source, fetches and replaces the src with a data URL for duplicates,
|
|
6
|
-
* and prefixes the proxy URL for unique images.
|
|
6
|
+
* proxyImages
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* - wrapperSelector: String - The CSS selector for the wrapper element containing images.
|
|
11
|
-
* - corsProxyBaseURL: String - The base URL of the CORS proxy server.
|
|
12
|
-
* @returns {Promise<number>} - Returns the number of times the proxy server was pinged.
|
|
8
|
+
* Proxies all images inside capture elements.
|
|
9
|
+
* The original src is stored for later restoration.
|
|
13
10
|
*/
|
|
14
|
-
export async function proxyImages(
|
|
11
|
+
export async function proxyImages(
|
|
12
|
+
config: Config,
|
|
13
|
+
elements: HTMLElement[] | NodeListOf<HTMLElement>
|
|
14
|
+
) {
|
|
15
15
|
try {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
link.setAttribute("crossorigin", "anonymous");
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
const wrapper = document.querySelector(options.selectors.wrapper);
|
|
23
|
-
if (!wrapper) {
|
|
24
|
-
console.error("ImageExporter: Wrapper element not found.");
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
const images = Array.from(wrapper.querySelectorAll("img")) as HTMLImageElement[];
|
|
28
|
-
|
|
29
|
-
const srcMap = new Map<string, HTMLImageElement[]>();
|
|
30
|
-
|
|
31
|
-
// Group images by src
|
|
32
|
-
images.forEach((img) => {
|
|
33
|
-
const srcs = srcMap.get(img.src) || [];
|
|
34
|
-
srcs.push(img);
|
|
35
|
-
srcMap.set(img.src, srcs);
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
for (const [src, duplicates] of srcMap) {
|
|
39
|
-
if (
|
|
40
|
-
!isValidUrl(src) ||
|
|
41
|
-
(options.corsProxyBaseUrl && src.startsWith(options.corsProxyBaseUrl))
|
|
42
|
-
) {
|
|
43
|
-
continue;
|
|
44
|
-
}
|
|
45
|
-
if (duplicates.length > 1) {
|
|
46
|
-
// Fetch and replace src for duplicate images
|
|
47
|
-
try {
|
|
48
|
-
const response = await fetch(
|
|
49
|
-
options.corsProxyBaseUrl + encodeURIComponent(src)
|
|
50
|
-
);
|
|
16
|
+
const elementArray = Array.from(elements);
|
|
17
|
+
if (!elementArray.length) return;
|
|
18
|
+
log.verbose("images to proxy", elementArray.length);
|
|
51
19
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
} catch (error) {
|
|
60
|
-
console.error("Error fetching image:", error);
|
|
20
|
+
for (const element of elementArray) {
|
|
21
|
+
const images = Array.from(element.querySelectorAll("img")) as HTMLImageElement[];
|
|
22
|
+
for (const img of images) {
|
|
23
|
+
if (isValidUrl(img.src) && !img.src.startsWith(config.corsProxyBaseUrl)) {
|
|
24
|
+
img.setAttribute("original-src", img.src);
|
|
25
|
+
img.src = config.corsProxyBaseUrl + encodeURIComponent(img.src);
|
|
26
|
+
log.verbose("Proxied: ", img.src);
|
|
61
27
|
}
|
|
62
|
-
} else {
|
|
63
|
-
// Prefix src for unique images
|
|
64
|
-
images.forEach((img) => {
|
|
65
|
-
if (img.src === src) {
|
|
66
|
-
img.src = options.corsProxyBaseUrl + encodeURIComponent(src);
|
|
67
|
-
}
|
|
68
|
-
});
|
|
69
28
|
}
|
|
70
29
|
}
|
|
71
30
|
} catch (e) {
|
|
@@ -73,18 +32,3 @@ export async function proxyImages(options: types.Options) {
|
|
|
73
32
|
return;
|
|
74
33
|
}
|
|
75
34
|
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* blobToDataURL - Converts a Blob object to a data URL.
|
|
79
|
-
*
|
|
80
|
-
* @param {Blob} blob - The Blob object to be converted.
|
|
81
|
-
* @returns {Promise<string>} - Returns a Promise that resolves to a data URL string.
|
|
82
|
-
*/
|
|
83
|
-
function blobToDataURL(blob: Blob): Promise<string> {
|
|
84
|
-
return new Promise((resolve, reject) => {
|
|
85
|
-
const reader = new FileReader();
|
|
86
|
-
reader.onloadend = () => resolve(reader.result as string);
|
|
87
|
-
reader.onerror = reject;
|
|
88
|
-
reader.readAsDataURL(blob);
|
|
89
|
-
});
|
|
90
|
-
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { proxyCSS } from "./proxy-css";
|
|
2
|
+
import { proxyImages } from "./proxy-images";
|
|
3
|
+
import { Config } from "../types";
|
|
4
|
+
import { isValidUrl } from "./is-valid-url";
|
|
5
|
+
import { log } from "../logger";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* runCorsProxy
|
|
9
|
+
*
|
|
10
|
+
* Proxies all images inside capture elements, as well as all linked CSS files and the absolute URLs inside them.
|
|
11
|
+
* Upon completion of capture, these will be reverted to their original state.
|
|
12
|
+
*/
|
|
13
|
+
export async function runCorsProxy(
|
|
14
|
+
config: Config,
|
|
15
|
+
elements: HTMLElement[] | NodeListOf<HTMLElement>
|
|
16
|
+
): Promise<void> {
|
|
17
|
+
try {
|
|
18
|
+
log.verbose("running CORS proxy");
|
|
19
|
+
if (!config.corsProxyBaseUrl || !isValidUrl(config.corsProxyBaseUrl)) return;
|
|
20
|
+
|
|
21
|
+
await proxyCSS(config);
|
|
22
|
+
await proxyImages(config, elements);
|
|
23
|
+
} catch (e) {
|
|
24
|
+
console.error("ImageExporter: Error in runCorsProxy", e);
|
|
25
|
+
}
|
|
26
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
|
-
|
|
1
|
+
/* -------------------------------------------------------------------------- */
|
|
2
|
+
/* Image Exporter */
|
|
3
|
+
/* */
|
|
4
|
+
/* by briantuckerdesign */
|
|
5
|
+
/* -------------------------------------------------------------------------- */
|
|
6
|
+
import { capture } from "./capture";
|
|
2
7
|
|
|
3
|
-
|
|
8
|
+
/** Exports for use in browser */
|
|
4
9
|
if (typeof window !== "undefined") {
|
|
5
|
-
(window as any).
|
|
10
|
+
(window as any).imageExporter = capture;
|
|
6
11
|
}
|
|
7
12
|
|
|
8
|
-
|
|
13
|
+
/** Exports for use as an imported package */
|
|
14
|
+
export { capture };
|
package/src/logger.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { windowLogging, loggingLevel } from "./capture";
|
|
2
|
+
|
|
3
|
+
export const log = {
|
|
4
|
+
info: (...messages: any[]) => logAction(messages, "info"),
|
|
5
|
+
error: (...messages: any[]) => logAction(messages, "error"),
|
|
6
|
+
verbose: (...messages: any[]) => logAction(messages, "verbose"),
|
|
7
|
+
progress: (progress: number, total: number) => logProgress(progress, total),
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
async function logAction(messages: any[], type: LogType = "info") {
|
|
11
|
+
const combinedMessage = messages
|
|
12
|
+
.map((msg) => (typeof msg === "object" ? JSON.stringify(msg) : msg))
|
|
13
|
+
.join(" ");
|
|
14
|
+
|
|
15
|
+
switch (type) {
|
|
16
|
+
case "info":
|
|
17
|
+
if (loggingLevel === "info" || loggingLevel === "verbose") {
|
|
18
|
+
console.log(...messages);
|
|
19
|
+
}
|
|
20
|
+
break;
|
|
21
|
+
case "error":
|
|
22
|
+
if (loggingLevel === "error" || loggingLevel === "verbose") {
|
|
23
|
+
console.error(...messages);
|
|
24
|
+
}
|
|
25
|
+
break;
|
|
26
|
+
case "verbose":
|
|
27
|
+
if (loggingLevel === "verbose") {
|
|
28
|
+
console.log(...messages);
|
|
29
|
+
}
|
|
30
|
+
break;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (windowLogging) window.imageExporterLogs.push({ message: combinedMessage, type });
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async function logProgress(progress: number, total: number) {
|
|
37
|
+
if (windowLogging) {
|
|
38
|
+
window.imageExporterProgress.push([progress, total]);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
type LogType = "info" | "error" | "verbose" | "progress";
|
|
43
|
+
|
|
44
|
+
type Log = {
|
|
45
|
+
message: string;
|
|
46
|
+
type: LogType;
|
|
47
|
+
progress?: number;
|
|
48
|
+
total?: number;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
type Progress = [number, number];
|
|
52
|
+
|
|
53
|
+
declare global {
|
|
54
|
+
interface Window {
|
|
55
|
+
imageExporterLogs: Log[];
|
|
56
|
+
imageExporterProgress: Progress[];
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
window.imageExporterLogs = [];
|
|
61
|
+
window.imageExporterProgress = [];
|
package/src/types.d.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export interface ImageOptions {
|
|
2
|
+
/** Label for image. Does not include file extension or scale. */
|
|
3
|
+
label: Label;
|
|
4
|
+
/** File format, jpg, png, or svg. */
|
|
5
|
+
format: Format;
|
|
6
|
+
/** Scale of image. Can be a number or a comma-separated list of numbers. */
|
|
7
|
+
scale: Scale;
|
|
8
|
+
/** Quality of image. 0.0 to 1.0, only applies to jpg.*/
|
|
9
|
+
quality: Quality;
|
|
10
|
+
/** Include scale in label. True or false. Automatically true if scale is an array. */
|
|
11
|
+
includeScaleInLabel: IncludeScaleInLabel;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface Config extends ImageOptions {
|
|
15
|
+
/** Download images as files upon capture. */
|
|
16
|
+
downloadImages: boolean;
|
|
17
|
+
/** Default label for images. Does not include file extension or scale. */
|
|
18
|
+
defaultImageLabel: string;
|
|
19
|
+
/** Label for zip file. Does not include file extension or scale. */
|
|
20
|
+
zipLabel: Label;
|
|
21
|
+
/** Base URL for CORS proxy used when fetching external images.
|
|
22
|
+
*
|
|
23
|
+
* URLs will be encoded and appended without a `?`. Include your own trailing slash.
|
|
24
|
+
*
|
|
25
|
+
* I recommend [cors-proxy-worker](https://github.com/briantuckerdesign/cors-proxy-worker) for production and [local-cors-proxy-encoded](https://github.com/briantuckerdesign/local-cors-proxy-encoded) for development.
|
|
26
|
+
*
|
|
27
|
+
* Example: `https://cors-proxy.com/` -> `https://cors-proxy.com/https%3A%2F%2FmyEncodedUrl.com`
|
|
28
|
+
*/
|
|
29
|
+
corsProxyBaseUrl: string;
|
|
30
|
+
/** Enable window logging for use by external scripts. */
|
|
31
|
+
enableWindowLogging: boolean;
|
|
32
|
+
/** Enable verbose logging for debugging. */
|
|
33
|
+
loggingLevel: LoggingLevel;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface ParsedImageOptions extends ImageOptions {
|
|
37
|
+
/** After parsing, this will always be a number rather than possibly an array. */
|
|
38
|
+
scale: number;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface Image {
|
|
42
|
+
dataURL: string;
|
|
43
|
+
fileName: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export type Label = string;
|
|
47
|
+
export type Format = "jpg" | "png" | "svg";
|
|
48
|
+
export type Scale = number | number[];
|
|
49
|
+
export type Quality = number;
|
|
50
|
+
export type IncludeScaleInLabel = boolean;
|
|
51
|
+
export type LoggingLevel = "none" | "info" | "error" | "verbose";
|
package/vite.config.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { defineConfig } from "vite";
|
|
2
|
-
import strip from "@rollup/plugin-strip";
|
|
3
2
|
|
|
4
3
|
export default defineConfig({
|
|
4
|
+
test: {
|
|
5
|
+
environment: "jsdom",
|
|
6
|
+
},
|
|
5
7
|
build: {
|
|
6
8
|
outDir: "dist",
|
|
7
9
|
emptyOutDir: true,
|
|
@@ -27,12 +29,6 @@ export default defineConfig({
|
|
|
27
29
|
}
|
|
28
30
|
},
|
|
29
31
|
},
|
|
30
|
-
strip({
|
|
31
|
-
include: "**/*.(js|ts)",
|
|
32
|
-
functions: ["console.log"],
|
|
33
|
-
// Only apply this plugin during build, not during watch
|
|
34
|
-
exclude: process.env.NODE_ENV === "development" ? "**/*" : "",
|
|
35
|
-
}),
|
|
36
32
|
],
|
|
37
33
|
},
|
|
38
34
|
},
|
package/example/example.css
DELETED
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
body {
|
|
2
|
-
display: flex;
|
|
3
|
-
justify-content: center;
|
|
4
|
-
margin: 0;
|
|
5
|
-
background-color: #151224;
|
|
6
|
-
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
|
|
7
|
-
Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue",
|
|
8
|
-
sans-serif;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
.wrapper {
|
|
12
|
-
display: grid;
|
|
13
|
-
width: 800px;
|
|
14
|
-
height: 500px;
|
|
15
|
-
grid-auto-columns: 1fr;
|
|
16
|
-
grid-column-gap: 16px;
|
|
17
|
-
grid-row-gap: 16px;
|
|
18
|
-
grid-template-columns: 1fr 2fr;
|
|
19
|
-
grid-template-rows: auto;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
.input-wrapper {
|
|
23
|
-
display: flex;
|
|
24
|
-
flex-direction: column;
|
|
25
|
-
align-items: flex-start;
|
|
26
|
-
color: #fff;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
.input-label {
|
|
30
|
-
margin-bottom: 0px;
|
|
31
|
-
font-weight: 700;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
.example-input {
|
|
35
|
-
margin-bottom: 1rem;
|
|
36
|
-
padding: 6px;
|
|
37
|
-
-webkit-align-self: stretch;
|
|
38
|
-
-ms-flex-item-align: stretch;
|
|
39
|
-
-ms-grid-row-align: stretch;
|
|
40
|
-
align-self: stretch;
|
|
41
|
-
border: 1px solid #7000ff;
|
|
42
|
-
border-radius: 4px;
|
|
43
|
-
color: #000;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
.example-button {
|
|
47
|
-
display: -webkit-box;
|
|
48
|
-
display: -webkit-flex;
|
|
49
|
-
display: -ms-flexbox;
|
|
50
|
-
display: flex;
|
|
51
|
-
padding: 11px 22px;
|
|
52
|
-
background-color: #7000ff;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
.example-wrapper {
|
|
56
|
-
display: flex;
|
|
57
|
-
flex-direction: column;
|
|
58
|
-
justify-content: center;
|
|
59
|
-
align-items: center;
|
|
60
|
-
grid-column-gap: 16px;
|
|
61
|
-
grid-row-gap: 16px;
|
|
62
|
-
border-style: dashed;
|
|
63
|
-
border-width: 2px;
|
|
64
|
-
border-color: #7000ff;
|
|
65
|
-
border-radius: 8px;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
.example-2 {
|
|
69
|
-
display: flex;
|
|
70
|
-
width: 200px;
|
|
71
|
-
height: 200px;
|
|
72
|
-
padding: 22px;
|
|
73
|
-
justify-content: center;
|
|
74
|
-
align-items: center;
|
|
75
|
-
background-color: #7000ff;
|
|
76
|
-
font-size: 24px;
|
|
77
|
-
line-height: 1;
|
|
78
|
-
font-weight: 700;
|
|
79
|
-
text-align: center;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
.example-1 {
|
|
83
|
-
display: flex;
|
|
84
|
-
width: 400px;
|
|
85
|
-
height: 200px;
|
|
86
|
-
justify-content: center;
|
|
87
|
-
align-items: center;
|
|
88
|
-
background-color: #fff;
|
|
89
|
-
font-size: 24px;
|
|
90
|
-
font-weight: 700;
|
|
91
|
-
text-align: center;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
.example-text-2 {
|
|
95
|
-
color: #fff;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
.example-text-1 {
|
|
99
|
-
color: #7000ff;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
.gf_loader {
|
|
103
|
-
display: none;
|
|
104
|
-
opacity: 0;
|
|
105
|
-
position: absolute;
|
|
106
|
-
width: 100dvw;
|
|
107
|
-
height: 100dvh;
|
|
108
|
-
z-index: 99;
|
|
109
|
-
background-color: rgba(25, 25, 25, 0.9);
|
|
110
|
-
color: #fff;
|
|
111
|
-
}
|
|
112
|
-
.gf_loader-message {
|
|
113
|
-
display: flex;
|
|
114
|
-
width: 100dvw;
|
|
115
|
-
height: 100dvh;
|
|
116
|
-
align-items: center;
|
|
117
|
-
justify-content: center;
|
|
118
|
-
}
|
|
119
|
-
.img {
|
|
120
|
-
max-width: 100%;
|
|
121
|
-
height: 100%;
|
|
122
|
-
}
|