import { defineComponent , ref , Ref , computed , isReactive , isRef } from 'vue' ; import { CommonFieldPropsDefine } from '../types' ; import { isObject } from '../utils' ; import { useVJSFContext } from '../Context' ; import { useComponent , ThemeLayoutsNames } from '../theme' ; import { getUiSchema } from './common' ; export default defineComponent ( { name : 'ObjectField' , props : CommonFieldPropsDefine , setup ( props ) { const valueRef = ref ( { } ) ; const formContextRef = useVJSFContext ( ) ; const { schema } = props ; if ( ! props . value || ! isObject ( props . value ) ) { if ( schema . default && isObject ( schema . default ) ) { props . onChange ( schema . default ) ; } else if ( ! isObject ( props . value ) ) { props . onChange ( undefined ) ; } } const HeaderRef = useComponent ( ThemeLayoutsNames . Header ) ; const handlePropertyChange = ( k , v ) => { const value = props . value || { } ; if ( v === undefined ) { delete value [ k ] ; } else { /**
                 * since our value is always object and will be nested very deep
                 * we decide to mutate object prop field directly
                 * but we still will trigger `onChange` to notify parent
                 * in case parent have some action to do
                 * it is not recommend to do it this way
                 * but if we force update object filed at top level
                 * it may cause performance issue and also
                 * it will be too complex to manager
                 * we stil not found any problem when we doing so
                 * so we will keep doing it this way
                 */ value [ k ] = v ; } props . onChange ( value ) ; } ; const uiSchemaRef = getUiSchema ( props ) ; const titleRef = computed ( ( ) => { const vjsf = uiSchemaRef . value ; return props . schema . title || ( vjsf ? vjsf . title : '' ) ; } ) ; const propertiesRef = computed ( ( ) => { const { uiSchema , schema } = props ; const properties = schema . properties || { } ; const propertiesOrder = uiSchema && uiSchema . propertiesOrder ; if ( ! propertiesOrder ) return Object . keys ( properties ) ; else { const before = [ ] ; const after = [ ] ; const keys = new Set ( Object . keys ( properties ) ) ; let isBefore = true ; let alreadyHandleLeft = false ; propertiesOrder . forEach ( k => { const arr = isBefore ? before : after ; if ( keys . has ( k ) && k !== '*' ) { arr . push ( k ) ; keys . delete ( k ) ; } else if ( k === '*' ) { isBefore = false ; alreadyHandleLeft = true ; } } ) ; return [ ... before , ... keys , ... after ] ; } } ) ; return ( ) => { const { path , value , schema , rootSchema , uiSchema , errorSchema } = props ; const SchemaItem = formContextRef . value . SchemaItem ; const Header = HeaderRef . value ; const requires = schema . required || [ ] ; if ( ! schema . properties ) { console . warn ( 'schema of type object contain no properties' , props . schema ) ; } const properties = schema . properties || { } ; const title = titleRef . value ; return [ title ? < Header title = { title } type = "object" > < /Header> : null, propertiesRef . value . map ( ( k ) => { const fieldUiSchema = uiSchema && uiSchema . properties ? uiSchema . properties [ k ] || { } : { } ; return ( < SchemaItem id = { `${ props . id }_${ k }` } path = { `${ path }/${ k }` } key = { k } value = { value && ( value as any ) [ k ] } errorSchema = { errorSchema [ k ] || { } } onChange = { ( v ) => handlePropertyChange ( k , v ) } isDependenciesKey = { false } required = { requires . indexOf ( k ) > - 1 } schema = { properties [ k ] as any } rootSchema = { rootSchema } uiSchema = { fieldUiSchema } / > ) ; } ) , ] ; } ; } , } ) ;