personal web client for Bluesky
typescript solidjs bluesky atcute
at trunk 159 lines 3.7 kB view raw
1import { createMemo, untrack } from 'solid-js'; 2 3import { replaceEqualDeep } from '@mary/solid-query'; 4 5const _on = <T, R>(accessor: () => T, callback: (value: T) => R): (() => R) => { 6 return () => { 7 const value = accessor(); 8 return untrack(() => callback(value)); 9 }; 10}; 11 12export const on = <T, R>(accessor: () => T, callback: (value: T) => R): (() => R) => { 13 return createMemo(_on(accessor, callback)); 14}; 15 16type ReconcilableProperties<T> = { [K in keyof T]: T[K] extends string | number ? K : never }[keyof T]; 17export const reconcile = <T = any>( 18 prev: NoInfer<T>[] | undefined, 19 next: T[], 20 key: ReconcilableProperties<T> | ((item: T) => string | number), 21): T[] => { 22 if (prev === undefined) { 23 return next; 24 } 25 26 let equalItems = 0; 27 28 const map = new Map<string | number, T>(); 29 const prevLen = prev.length; 30 const nextLen = next.length; 31 32 for (let idx = 0; idx < prevLen; idx++) { 33 const item = prev[idx]; 34 35 // @ts-expect-error 36 map.set(typeof key === 'function' ? key(item) : item[key], item); 37 } 38 39 const array: T[] = Array.from({ length: next.length }); 40 for (let idx = 0; idx < nextLen; idx++) { 41 const nextItem = next[idx]; 42 // @ts-expect-error 43 const prevItem = map.get(typeof key === 'function' ? key(nextItem) : nextItem[key]); 44 45 if (prevItem !== undefined) { 46 const replaced = replaceEqualDeep(prevItem, nextItem); 47 if (replaced === prevItem) { 48 equalItems++; 49 } 50 51 array[idx] = replaced; 52 } else { 53 array[idx] = nextItem; 54 } 55 } 56 57 return equalItems === 0 ? next : array; 58}; 59 60export const requestIdle = typeof requestIdleCallback === 'function' ? requestIdleCallback : setTimeout; 61 62export const isSetEqual = <T>(a: Set<T>, b: Set<T>): boolean => { 63 if (a.size !== b.size) { 64 return false; 65 } 66 67 if (a.size !== 0) { 68 for (const val of a) { 69 if (!b.has(val)) { 70 return false; 71 } 72 } 73 } 74 75 return true; 76}; 77 78export const omit = <T extends Record<string, any>, K extends keyof T>( 79 obj: T, 80 keys: readonly K[], 81): Omit<T, K> => { 82 const result = { ...obj }; 83 84 for (let i = 0; i < keys.length; i++) { 85 const key = keys[i]; 86 delete result[key]; 87 } 88 89 return result as Omit<T, K>; 90}; 91 92export const throttleLeading = <T extends (...args: any[]) => void>( 93 fn: T, 94 wait: number, 95): ((...args: Parameters<T>) => void) => { 96 let lastCallTime: number | undefined; 97 98 return (...args: Parameters<T>) => { 99 const now = performance.now(); 100 101 if (lastCallTime === undefined || now - lastCallTime >= wait) { 102 lastCallTime = now; 103 fn(...args); 104 } 105 }; 106}; 107 108export const throttleTrailing = <T extends (...args: any[]) => void>( 109 fn: T, 110 wait: number, 111): ((...args: Parameters<T>) => void) => { 112 let timeoutId: ReturnType<typeof setTimeout> | undefined; 113 let lastArgs: Parameters<T> | undefined; 114 115 return (...args: Parameters<T>) => { 116 lastArgs = args; 117 118 if (timeoutId === undefined) { 119 timeoutId = setTimeout(() => { 120 timeoutId = undefined; 121 fn(...lastArgs!); 122 }, wait); 123 } 124 }; 125}; 126 127export const throttle = <T extends (...args: any[]) => void>( 128 fn: T, 129 wait: number, 130): ((...args: Parameters<T>) => void) => { 131 let timeoutId: ReturnType<typeof setTimeout> | undefined; 132 let lastArgs: Parameters<T> | undefined; 133 let lastCallTime: number | undefined; 134 135 return (...args: Parameters<T>) => { 136 const now = performance.now(); 137 const elapsed = lastCallTime !== undefined ? now - lastCallTime : wait; 138 139 if (elapsed >= wait) { 140 if (timeoutId !== undefined) { 141 clearTimeout(timeoutId); 142 timeoutId = undefined; 143 } 144 145 lastCallTime = now; 146 fn(...args); 147 } else { 148 lastArgs = args; 149 150 if (timeoutId === undefined) { 151 timeoutId = setTimeout(() => { 152 timeoutId = undefined; 153 lastCallTime = performance.now(); 154 fn(...lastArgs!); 155 }, wait - elapsed); 156 } 157 } 158 }; 159};