import { isPlainObject } from 'is-plain-object' import { nanoid } from 'nanoid' /** * Generate a unique id. * * @example * * ```ts * const id = uniqueId() * ``` * * @public */ export function uniqueId() { return nanoid() } const serializableTypes = new Set(['string', 'number', 'boolean', 'undefined']) /** * Get whether a value is serializable. * * @example * * ```ts * const A = isSerializable(1) // true * const B = isSerializable('a') // true * const C = isSerializable(true) // true * const D = isSerializable(undefined) // false * ``` * * @param value - The value to check. * @public */ export function isSerializable(value: any): boolean { if (serializableTypes.has(typeof value) || value === null) return true if (Array.isArray(value)) return value.every(isSerializable) if (isPlainObject(value)) return Object.values(value).every(isSerializable) return false } /** * Convert a file to base64. * * @example * * ```ts * const A = fileToBase64('./test.png') * ``` * * @param value - The file as a blob. * @public */ export function fileToBase64(file: Blob): Promise { return new Promise((resolve, reject) => { if (file) { const reader = new FileReader() reader.readAsDataURL(file) reader.onload = () => resolve(reader.result as string) reader.onerror = (error) => reject(error) reader.onabort = (error) => reject(error) } }) } /** * Get an incremented name (e.g. New page (2)) from a name (e.g. New page), based on an array of * existing names. * * @param name - The name to increment. * @param others - The array of existing names. * @public */ export function getIncrementedName(name: string, others: string[]) { let result = name const set = new Set(others) while (set.has(result)) { result = /^.*(\d+)$/.exec(result)?.[1] ? result.replace(/(\d+)(?=\D?)$/, (m) => { return (+m + 1).toString() }) : `${result} 1` } return result } /** @public */ export const checkFlag = (flag: boolean | (() => boolean) | undefined) => typeof flag === 'boolean' ? flag : flag?.() /** @public */ export function snapToGrid(n: number, gridSize: number) { return Math.round(n / gridSize) * gridSize }