import { MethodNames , ReturnTypeOrNever } from "@adpt/utils" ; import ld from "lodash" ; import { serializeDom } from "../dom_serialize" ; import { Handle , HandleInstanceType } from "../handle" ; import { AdaptElement , ElementPredicate , isApplyStyle , isMountedElement , } from "../jsx" ; import { useAsync } from "./use_async" ; remarks param hand param initial param method param args privateremarks beta export function useMethod < H extends Handle , Instance = HandleInstanceType < H > , MethodName extends MethodNames < Instance > = MethodNames < Instance > , Ret = ReturnTypeOrNever < Instance [ MethodName ] > > ( hand , method ) ; privateremarks beta export function useMethod < Initial , H extends Handle , Instance = HandleInstanceType < H > , MethodName extends MethodNames < Instance > = MethodNames < Instance > , Ret = ReturnTypeOrNever < Instance [ MethodName ] > > ( hand , initial , method , ... args ) ; privateremarks beta export function useMethod < OverrideReturn , H extends Handle = Handle , Instance = HandleInstanceType < H > , MethodName extends MethodNames < Instance > = MethodNames < Instance > > ( hand , method ) ; privateremarks beta export function useMethod < OverrideReturn > ( hand , initial , method , ... args ) ; export function useMethod < Initial , H extends Handle , Instance = HandleInstanceType < H > , MethodName extends MethodNames < Instance > = MethodNames < Instance > , Ret = ReturnTypeOrNever < Instance [ MethodName ] > > ( hand , initialOrMethod , method ? , ... args ) { const mName = method || initialOrMethod as MethodName ; const initial = method ? initialOrMethod as Initial : undefined ; return useAsync < Ret | typeof initial > ( async ( ) => { if ( hand == null ) return initial ; return callInstanceMethod < Ret | typeof initial > ( hand , initial , mName , ... args ) ; } , initial ) ; } export function hasInstanceMethod ( name , skip ? ) { return ( el ) => { if ( el === skip ) return false ; if ( ! isMountedElement ( el ) ) throw new Error ( `Element is not an ElementImpl` ) ; const inst = el . instance ; return ld . isFunction ( inst [ name ] ) ; } ; } export function notReplacedByStyle ( ) { return ( el ) => { if ( ! isMountedElement ( el ) ) throw new Error ( `Element is not an ElementImpl` ) ; const succ = el . buildData . successor ; if ( succ == null ) return true ; if ( ! isApplyStyle ( succ ) ) return true ; return false ; } ; } function _callInstanceMethod < T = any > ( hand , def , methodName , args , options = { } ) { const method = getInstanceValue < ( ... args : any [ ] ) => T > ( hand , ( ) => def , methodName , options ) ; if ( ! ld . isFunction ( method ) ) { const mountedOrig = hand . associated ? hand . mountedOrig : null ; throw new Error ( `${ methodName } exists but is not a function on handle instance:\n` + ( ( mountedOrig != null ) ? serializeDom ( mountedOrig ) : `mountedOrig is ${ mountedOrig }` ) ) ; } return method ( ... args ) ; } remarks If an Element is found that satisfies the search, but method `methodName`
 * does not exist on the Element's instance, an error is thrown.
 *
 * The exact check that is currently used when searching the handle chain is
 * for mounted Elements that satisfy the predicate  notReplacedByStyle .
 * In practice, this only selects Elements that are both mounted and built.
 *
 *  returns beta export function callInstanceMethod < T = any > ( hand , def , methodName , ... args ) { return _callInstanceMethod ( hand , def , methodName , args ) ; } remarks returns beta export function callFirstInstanceWithMethod < T = any > ( hand , def , methodName , ... args ) { const options = { pred : hasInstanceMethod ( methodName ) } ; return _callInstanceMethod ( hand , def , methodName , args , options ) ; } remarks returns beta export function callNextInstanceWithMethod < T = any > ( hand , def , methodName , ... args ) { if ( ! hand . associated ) { throw new Error ( `Cannot find next instance when calling ${ methodName }: handle is not associated with any element` ) ; } const options = { pred : hasInstanceMethod ( methodName , hand . mountedOrig ) } ; return _callInstanceMethod ( hand , def , methodName , args , options ) ; } remarks returns deprecated Renamed to  callNextInstanceWithMethod .
  export const callNextInstanceMethod = callNextInstanceWithMethod ; export const defaultGetInstanceValueOptions = { pred : notReplacedByStyle ( ) , throwOnNoElem : false } ; export interface GetInstanceValueOptions { pred ? : ElementPredicate ; throwOnNoElem ? : boolean ; } beta export function getInstanceValue < T = any > ( hand , def , field , optionsIn ? ) { const options = { ... defaultGetInstanceValueOptions , ... optionsIn } ; const pred = options . pred ; if ( ! hand . associated ) { if ( ! options . throwOnNoElem ) return def ; throw new Error ( `Cannot get instance field ${ field }: Handle is not associated with element` ) ; } const elem = hand . nextMounted ( pred ) ; if ( ! elem ) { if ( ! options . throwOnNoElem ) return def ; throw new Error ( `Cannot get instance field ${ field }: Handle does not point to mounted element` ) ; } if ( ! elem . instance ) { throw new Error ( `Internal Error: Element is mounted but instance is ${ elem . instance }` ) ; } if ( ! ( field in elem . instance ) ) { throw new Error ( `${ field } does not exist on handle instance:\n` + serializeDom ( elem ) ) ; } const val = elem . instance [ field ] ; if ( ld . isFunction ( val ) ) { return val . bind ( elem . instance ) ; } return val ; } remarks beta export function useInstanceValue < T > ( hand , initial , field ) { return useAsync < T > ( async ( ) => getInstanceValue ( hand , initial , field ) , initial ) ; }