import { TableState, Updater } from './types' export type PartialKeys = Omit & Partial> export type RequiredKeys = Omit & Required> export type Overwrite = Omit< T, keyof U > & U export type UnionToIntersection = ( T extends any ? (x: T) => any : never ) extends (x: infer R) => any ? R : never export type IsAny = 1 extends 0 & T ? Y : N export type IsKnown = unknown extends T ? N : Y type ComputeRange< N extends number, Result extends Array = [] > = Result['length'] extends N ? Result : ComputeRange type Index40 = ComputeRange<40>[number] // Is this type a tuple? type IsTuple = T extends readonly any[] & { length: infer Length } ? Length extends Index40 ? T : never : never // If this type is a tuple, what indices are allowed? type AllowedIndexes< Tuple extends ReadonlyArray, Keys extends number = never > = Tuple extends readonly [] ? Keys : Tuple extends readonly [infer _, ...infer Tail] ? AllowedIndexes : Keys export type DeepKeys = unknown extends T ? keyof T : object extends T ? string : T extends readonly any[] & IsTuple ? AllowedIndexes | DeepKeysPrefix> : T extends any[] ? never & 'Dynamic length array indexing is not supported' : T extends Date ? never : T extends object ? (keyof T & string) | DeepKeysPrefix : never type DeepKeysPrefix = TPrefix extends keyof T & (number | string) ? `${TPrefix}.${DeepKeys & string}` : never export type DeepValue = T extends Record ? TProp extends `${infer TBranch}.${infer TDeepProp}` ? DeepValue : T[TProp & string] : never export type NoInfer = [T][T extends any ? 0 : never] export type Getter = () => NoInfer /// export function functionalUpdate(updater: Updater, input: T): T { return typeof updater === 'function' ? (updater as (input: T) => T)(input) : updater } export function noop() { // } export function makeStateUpdater( key: K, instance: unknown ) { return (updater: Updater) => { ;(instance as any).setState((old: TTableState) => { return { ...old, [key]: functionalUpdate(updater, (old as any)[key]), } }) } } type AnyFunction = (...args: any) => any export function isFunction(d: any): d is T { return d instanceof Function } export function flattenBy( arr: TNode[], getChildren: (item: TNode) => TNode[] ) { const flat: TNode[] = [] const recurse = (subArr: TNode[]) => { subArr.forEach(item => { flat.push(item) const children = getChildren(item) if (children?.length) { recurse(children) } }) } recurse(arr) return flat } export function memo( getDeps: () => [...TDeps], fn: (...args: NoInfer<[...TDeps]>) => TResult, opts: { key: any debug?: () => any onChange?: (result: TResult) => void } ): () => TResult { let deps: any[] = [] let result: TResult | undefined return () => { let depTime: number if (opts.key && opts.debug) depTime = Date.now() const newDeps = getDeps() const depsChanged = newDeps.length !== deps.length || newDeps.some((dep: any, index: number) => deps[index] !== dep) if (!depsChanged) { return result! } deps = newDeps let resultTime: number if (opts.key && opts.debug) resultTime = Date.now() result = fn(...newDeps) opts?.onChange?.(result) if (opts.key && opts.debug) { if (opts?.debug()) { const depEndTime = Math.round((Date.now() - depTime!) * 100) / 100 const resultEndTime = Math.round((Date.now() - resultTime!) * 100) / 100 const resultFpsPercentage = resultEndTime / 16 const pad = (str: number | string, num: number) => { str = String(str) while (str.length < num) { str = ' ' + str } return str } console.info( `%c⏱ ${pad(resultEndTime, 5)} /${pad(depEndTime, 5)} ms`, ` font-size: .6rem; font-weight: bold; color: hsl(${Math.max( 0, Math.min(120 - 120 * resultFpsPercentage, 120) )}deg 100% 31%);`, opts?.key ) } } return result! } }