@@ -474,24 +474,24 @@ class Provider extends Base {
474474 internalSetData ( key , value , originStateProvider ) {
475475 const me = this ;
476476
477- // If the value is a Neo.data.Record, treat it as an atomic value
478- // and set it directly without further recursive processing of its properties.
479- if ( Neo . isRecord ( value ) ) {
480- const
481- ownerDetails = me . getOwnerOfDataProperty ( key ) ,
482- targetProvider = ownerDetails ? ownerDetails . owner : ( originStateProvider || me ) ;
483-
484- me . #setConfigValue( targetProvider , key , value , null ) ;
485- return
486- }
487-
488477 if ( Neo . isObject ( key ) ) {
489478 Object . entries ( key ) . forEach ( ( [ dataKey , dataValue ] ) => {
490479 me . internalSetData ( dataKey , dataValue , originStateProvider )
491480 } ) ;
492481 return
493482 }
494483
484+ // Now 'key' is a string path.
485+ // If 'value' is a plain object, we need to drill down further.
486+ // If the value is a Neo.data.Record, treat it as an atomic value => it will not enter this block.
487+ if ( Neo . typeOf ( value ) === 'Object' ) {
488+ Object . entries ( value ) . forEach ( ( [ nestedKey , nestedValue ] ) => {
489+ const fullPath = `${ key } .${ nestedKey } ` ;
490+ me . internalSetData ( fullPath , nestedValue , originStateProvider ) ;
491+ } ) ;
492+ return // We've delegated the setting to deeper paths.
493+ }
494+
495495 const
496496 ownerDetails = me . getOwnerOfDataProperty ( key ) ,
497497 targetProvider = ownerDetails ? ownerDetails . owner : ( originStateProvider || me ) ;
@@ -522,7 +522,11 @@ class Provider extends Base {
522522 break // Stop if parent is not an object
523523 }
524524 } else {
525- break // Stop if parent config does not exist
525+ // If the parent config doesn't exist, we need to create it to support bubbling.
526+ // This is crucial for creating new nested data structures at runtime.
527+ const newParentValue = { [ leafKey ] : latestValue } ;
528+ me . #setConfigValue( targetProvider , path , newParentValue ) ;
529+ latestValue = newParentValue
526530 }
527531 }
528532 }
@@ -586,8 +590,8 @@ class Provider extends Base {
586590
587591 /**
588592 * @param {Neo.component.Base } component
589- * @param {String } configName
590- * @param {String } storeName
593+ * @param {String } configName
594+ * @param {String } storeName
591595 */
592596 resolveStore ( component , configName , storeName ) {
593597 let store = this . getStore ( storeName ) ;
@@ -602,9 +606,9 @@ class Provider extends Base {
602606 * This method creates a new Config instance if one doesn't exist for the given path,
603607 * or updates an existing one. It also triggers binding effects and calls onDataPropertyChange.
604608 * @param {Neo.state.Provider } provider The StateProvider instance owning the config.
605- * @param {String } path The full path of the data property (e.g., 'user.firstname').
606- * @param {* } newValue The new value to set.
607- * @param {* } oldVal The old value (optional, used for initial setup).
609+ * @param {String } path The full path of the data property (e.g., 'user.firstname').
610+ * @param {* } newValue The new value to set.
611+ * @param {* } [ oldVal] The old value (optional, used for initial setup).
608612 * @private
609613 */
610614 #setConfigValue( provider , path , newValue , oldVal ) {
@@ -633,7 +637,7 @@ class Provider extends Base {
633637 * are run only once.
634638 *
635639 * @param {Object|String } key
636- * @param {* } value
640+ * @param {* } value
637641 */
638642 setData ( key , value ) {
639643 EffectManager . pause ( ) ;
@@ -652,7 +656,7 @@ class Provider extends Base {
652656 * are run only once.
653657 *
654658 * @param {Object|String } key
655- * @param {* } value
659+ * @param {* } value
656660 */
657661 setDataAtSameLevel ( key , value ) {
658662 EffectManager . pause ( ) ;
0 commit comments