import { TableOptionsResolved, 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 = TDepth['length'] extends 5 ? never : unknown extends T ? string : T extends readonly any[] & IsTuple ? AllowedIndexes | DeepKeysPrefix, TDepth> : T extends any[] ? DeepKeys : T extends Date ? never : T extends object ? (keyof T & string) | DeepKeysPrefix : never type DeepKeysPrefix< T, TPrefix, TDepth extends any[], > = 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 isNumberArray(d: any): d is number[] { return Array.isArray(d) && d.every(val => typeof val === 'number') } 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: (depArgs?: TDepArgs) => [...TDeps], fn: (...args: NoInfer<[...TDeps]>) => TResult, opts: { key: any debug?: () => any onChange?: (result: TResult) => void } ): (depArgs?: TDepArgs) => TResult { let deps: any[] = [] let result: TResult | undefined return depArgs => { let depTime: number if (opts.key && opts.debug) depTime = Date.now() const newDeps = getDeps(depArgs) 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! } } export function getMemoOptions( tableOptions: Partial>, debugLevel: | 'debugAll' | 'debugCells' | 'debugTable' | 'debugColumns' | 'debugRows' | 'debugHeaders', key: string, onChange?: (result: any) => void ) { return { debug: () => tableOptions?.debugAll ?? tableOptions[debugLevel], key: process.env.NODE_ENV === 'development' && key, onChange, } }