UNPKG

@tldraw/utils

Version:

tldraw infinite canvas SDK (private utilities).

120 lines (108 loc) 2.86 kB
/** * Rotate the contents of an array. * * @public */ export function rotateArray<T>(arr: T[], offset: number): T[] { return arr.map((_, i) => arr[(i + offset) % arr.length]) } /** * Deduplicate the items in an array * * @public */ export function dedupe<T>(input: T[], equals?: (a: any, b: any) => boolean): T[] { const result: T[] = [] mainLoop: for (const item of input) { for (const existing of result) { if (equals ? equals(item, existing) : item === existing) { continue mainLoop } } result.push(item) } return result } /** @internal */ export function compact<T>(arr: T[]): NonNullable<T>[] { return arr.filter((i) => i !== undefined && i !== null) as any } /** @internal */ export function last<T>(arr: readonly T[]): T | undefined { return arr[arr.length - 1] } /** @internal */ export function minBy<T>(arr: readonly T[], fn: (item: T) => number): T | undefined { let min: T | undefined let minVal = Infinity for (const item of arr) { const val = fn(item) if (val < minVal) { min = item minVal = val } } return min } /** @internal */ export function maxBy<T>(arr: readonly T[], fn: (item: T) => number): T | undefined { let max: T | undefined let maxVal: number = -Infinity for (const item of arr) { const val = fn(item) if (val > maxVal) { max = item maxVal = val } } return max } /** * Partitions an array into two arrays, one with items that satisfy the predicate, and one with * items that do not. * * @param arr - The array to partition * @param predicate - The predicate to use to partition the array * @returns A tuple of two arrays, the first one with items that satisfy the predicate and the * second one with the ones that dont * @internal */ export function partition<T>(arr: T[], predicate: (item: T) => boolean): [T[], T[]] { const satisfies: T[] = [] const doesNotSatisfy: T[] = [] for (const item of arr) { if (predicate(item)) { satisfies.push(item) } else { doesNotSatisfy.push(item) } } return [satisfies, doesNotSatisfy] } /** @internal */ export function areArraysShallowEqual<T>(arr1: readonly T[], arr2: readonly T[]): boolean { if (arr1 === arr2) return true if (arr1.length !== arr2.length) return false for (let i = 0; i < arr1.length; i++) { if (!Object.is(arr1[i], arr2[i])) { return false } } return true } /** @internal */ export function mergeArraysAndReplaceDefaults< const Key extends string, T extends { [K in Key]: string }, >(key: Key, customEntries: readonly T[], defaults: readonly T[]) { const overrideTypes = new Set(customEntries.map((entry) => entry[key])) const result = [] for (const defaultEntry of defaults) { if (overrideTypes.has(defaultEntry[key])) continue result.push(defaultEntry) } for (const customEntry of customEntries) { result.push(customEntry) } return result }