import slugify from "@sindresorhus/slugify";
/** Copy given string to clipboard. Returns true if successful, false if failed. */
export function copyToClipboard(text: string): boolean {
const textArea = document.createElement("textarea");
textArea.style.position = "fixed";
textArea.style.left = "-9999px";
textArea.value = text;
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
try {
document.execCommand("copy");
} catch (error) {
console.error("Failed to copy text:", error);
return false;
}
document.body.removeChild(textArea);
return true;
}
export function downloadCanvasImage(canvas: HTMLCanvasElement, filename: string): void {
const image = canvas.toDataURL();
const link = document.createElement("a");
link.download = filename;
link.href = image;
link.click();
}
export const copyImageSupported = "ClipboardItem" in window && navigator.clipboard && "write" in navigator.clipboard;
export function copyCanvasImage(canvas: HTMLCanvasElement): boolean {
if (!copyImageSupported) {
throw Error("Copying images not supported on this browser");
}
canvas.toBlob((blob) =>
(navigator.clipboard as any).write([new (window as any).ClipboardItem({ "image/png": blob })]),
);
return true;
}
export function ellipsis(text: string, startLength: number, endLength: number): string {
if (startLength + endLength + 2 >= text.length) {
// +2 because there's reason to ellide something shorter than "..."
return text;
}
return text.substr(0, startLength) + "..." + text.substr(text.length - endLength, text.length);
}
export function truncateDid(did: string, maxCharCount = 20): string {
const overMaxCount = did.length > maxCharCount;
return did.includes("did:web") ? did : overMaxCount ? hexEllipsis(did) : did;
}
/** Finds where "0x" hex value starts and takes start length from there. */
export function hexEllipsis(text: string, startLength = 4, endLength = 4): string {
const addressIndex = text.indexOf("0x") === -1 ? text.lastIndexOf(":") + 1 : text.indexOf("0x") + 2;
return ellipsis(text, addressIndex + startLength, endLength);
}
export function dateTimeFormat(date: Date): any {
const year = new Intl.DateTimeFormat("en", { year: "numeric" }).format(date);
const month = new Intl.DateTimeFormat("en", { month: "short" }).format(date);
const day = new Intl.DateTimeFormat("en", { day: "2-digit" }).format(date);
const dateFormatted = ` ${month} ${day}, ${year}`;
const timeFormatted = new Intl.DateTimeFormat("en-US", { hour: "numeric", minute: "numeric" }).format(date);
return { dateFormatted, timeFormatted };
}
/** element requires a nonstandard time format ("yyyy-MM-ddThh:mm"). This converts from ISO datetime string into that format. */
export function isoToDatetimeLocal(isoString: string): string {
const offset = new Date().getTimezoneOffset() * 1000 * 60;
const offsetDate = new Date(isoString).valueOf() - offset;
return new Date(offsetDate).toISOString().substring(0, 16);
}
export function convertToCamelCase(s: string): string {
return slugify(s).replace(/-./g, (x) => x.replace("-", "").toUpperCase());
}
export function convertToPascalCase(s: string): string {
return slugify(s).replace(/(^|-)./g, (x) => x.replace("-", "").toUpperCase());
}
export function getAllUrlSearchParam(name: string): string[] {
if (window.URLSearchParams) {
const urlParams = new URLSearchParams(window.location.search.slice(1));
return urlParams.getAll(name);
} else {
// eslint-disable-next-line no-useless-escape
const nameForRegex = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
const regex = new RegExp("[\\?&]" + nameForRegex + "=([^]*)", "g");
const output : any[] = [];
let results: RegExpExecArray | null;
// eslint-disable-next-line no-constant-condition
while (true) {
results = regex.exec(window.location.search);
if (!results) {
break;
}
output.push(decodeURIComponent(results[1].replace(/\+/g, " ")));
}
return output;
}
}
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export const createMockApiRequest = (response?: any): ((...args: any[]) => Promise) => {
return (async (...args: any[]) => {
return new Promise((resolve) =>
setTimeout(() => {
console.log("SertoUiContext mock API request resolving. Request args:", ...args);
resolve(response);
}, 500),
);
}) as any;
};
export interface NftIdentifierResult {
contractAddress: string;
tokenId: string;
error: string;
}
export function getNftIdentifiersFromUrl(url: string): NftIdentifierResult {
let contractAddress = "";
let tokenId = "";
let error = "";
if (url) {
const splitVal = url.split("?");
if (splitVal && splitVal.length > 0) {
url = splitVal[0];
}
const splitURL = url.split("/");
const length = splitURL.length;
if (length < 2) {
error = "Contract Address or TokenID not found on URL";
} else {
const theorizedAddress = splitURL[length - 2];
const addressMatch = theorizedAddress.startsWith("0x") && theorizedAddress.length == 42;
if (!addressMatch) {
error = "Unable to find Contract Address in provided URL";
} else {
contractAddress = theorizedAddress;
const tokenIdMatch = splitURL[length - 1].match("[0-9]+");
if (!tokenIdMatch || tokenIdMatch.length == 0) {
error = "Unable to find Token ID in provided URL";
} else {
tokenId = tokenIdMatch[0];
}
}
}
}
return { contractAddress, tokenId, error };
}