import { watch , reactive , ref , Ref } from "vue" ; import isEqual from "lodash-es/isEqual" ; import { Reactive } from "./common" ; export function bindProp < T , K extends string & keyof T > ( props , name , emit , filter ? ) { if ( filter ) { const prop = ref < T [ K ] > ( filter ( props [ name ] ) ) as Ref < T [ K ] > ; const update = ( filtered ) => { if ( ! isEqual ( filtered , prop . value ) ) { prop . value = filtered ; } if ( ! isEqual ( filtered , props [ name ] ) ) { emit ( `update:${ name }` as const , filtered ) ; } } ; watch ( ( ) => filter ( prop . value ) , update ) ; watch ( ( ) => props [ name ] , v => update ( filter ( v ) ) ) ; if ( prop . value !== props [ name ] ) { emit ( `update:${ name }` as const , prop . value ) ; } return prop ; } const prop = ref < T [ K ] > ( props [ name ] ) as Ref < T [ K ] > ; watch ( ( ) => props [ name ] , v => { if ( ! isEqual ( v , prop . value ) ) { prop . value = v ; } } ) ; watch ( prop , v => { if ( ! isEqual ( v , props [ name ] ) ) { emit ( `update:${ name }` as const , v ) ; } } ) ; return prop ; } type KeysOfType < Obj , Val > = { [ K in keyof Obj ] - ? : Obj [ K ] extends Val ? K : never ; } [ keyof Obj ] ; export function bindPropKeySet < T , K extends string & KeysOfType < T , string [ ] > > ( props , name , sourceObject , emit ) { const bound = reactive < Set < string > > ( new Set ( ) ) ; watch ( ( ) => props [ name ] , ( ) => { const prop = props [ name ] as any ; const filtered = prop . filter ( n => n in sourceObject ) ; if ( ! isEqual ( filtered , bound ) ) { bound . clear ( ) ; filtered . forEach ( bound . add , bound ) ; } } , { immediate : true } ) ; watch ( bound , ( ) => { const array = Array . from ( bound ) ; if ( ! isEqual ( props [ name ] , array ) ) { emit ( `update:${ name }` as const , array ) ; } } ) ; return Reactive ( bound ) ; }