@@ -1324,6 +1324,132 @@ public function test_tangible_fields_renderer_list_view_handles_repeater(): void
13241324 $ this ->assertStringContainsString ( '2 item(s) ' , $ html );
13251325 }
13261326
1327+ public function test_layout_sections_within_tabs_structure (): void {
1328+ $ dataset = new DataSet ();
1329+ $ dataset ->add_string ( 'name ' );
1330+ $ dataset ->add_string ( 'email ' );
1331+
1332+ $ layout = new \Tangible \EditorLayout \Layout ( $ dataset );
1333+ $ layout ->tabs ( function ( $ tabs ) {
1334+ $ tabs ->tab ( 'General ' , function ( $ tab ) {
1335+ $ tab ->section ( 'Contact Information ' , function ( $ section ) {
1336+ $ section ->field ( 'name ' );
1337+ $ section ->field ( 'email ' );
1338+ } );
1339+ } );
1340+ } );
1341+
1342+ $ structure = $ layout ->get_structure ();
1343+
1344+ // Verify the structure has tabs with nested sections.
1345+ $ this ->assertCount ( 1 , $ structure ['items ' ] );
1346+ $ this ->assertEquals ( 'tabs ' , $ structure ['items ' ][0 ]['type ' ] );
1347+
1348+ $ tab = $ structure ['items ' ][0 ]['tabs ' ][0 ];
1349+ $ this ->assertEquals ( 'General ' , $ tab ['label ' ] );
1350+ $ this ->assertArrayHasKey ( 'items ' , $ tab );
1351+ $ this ->assertCount ( 1 , $ tab ['items ' ] );
1352+
1353+ $ section = $ tab ['items ' ][0 ];
1354+ $ this ->assertEquals ( 'section ' , $ section ['type ' ] );
1355+ $ this ->assertEquals ( 'Contact Information ' , $ section ['label ' ] );
1356+ $ this ->assertCount ( 2 , $ section ['fields ' ] );
1357+ }
1358+
1359+ public function test_layout_sidebar_actions_structure (): void {
1360+ $ dataset = new DataSet ();
1361+ $ dataset ->add_string ( 'name ' );
1362+
1363+ $ layout = new \Tangible \EditorLayout \Layout ( $ dataset );
1364+ $ layout ->section ( 'Main ' , function ( $ section ) {
1365+ $ section ->field ( 'name ' );
1366+ } );
1367+ $ layout ->sidebar ( function ( $ sidebar ) {
1368+ $ sidebar ->actions ( [ 'save ' , 'delete ' ] );
1369+ } );
1370+
1371+ $ structure = $ layout ->get_structure ();
1372+
1373+ // Verify the sidebar has actions.
1374+ $ this ->assertArrayHasKey ( 'sidebar ' , $ structure );
1375+ $ this ->assertArrayHasKey ( 'actions ' , $ structure ['sidebar ' ] );
1376+ $ this ->assertEquals ( [ 'save ' , 'delete ' ], $ structure ['sidebar ' ]['actions ' ] );
1377+ }
1378+
1379+ public function test_renderer_extract_fields_preserves_section_structure (): void {
1380+ $ dataset = new DataSet ();
1381+ $ dataset ->add_string ( 'name ' );
1382+ $ dataset ->add_string ( 'email ' );
1383+
1384+ $ layout = new \Tangible \EditorLayout \Layout ( $ dataset );
1385+ $ layout ->tabs ( function ( $ tabs ) {
1386+ $ tabs ->tab ( 'General ' , function ( $ tab ) {
1387+ $ tab ->section ( 'Contact Info ' , function ( $ section ) {
1388+ $ section ->field ( 'name ' );
1389+ $ section ->field ( 'email ' );
1390+ } );
1391+ } );
1392+ } );
1393+
1394+ $ renderer = new \Tangible \Renderer \TangibleFieldsRenderer ();
1395+
1396+ // Set up the renderer's internal state via reflection.
1397+ $ layoutProp = new \ReflectionProperty ( $ renderer , 'layout ' );
1398+ $ layoutProp ->setAccessible ( true );
1399+ $ layoutProp ->setValue ( $ renderer , $ layout );
1400+
1401+ $ dataProp = new \ReflectionProperty ( $ renderer , 'data ' );
1402+ $ dataProp ->setAccessible ( true );
1403+ $ dataProp ->setValue ( $ renderer , [ 'name ' => '' , 'email ' => '' ] );
1404+
1405+ // Test the protected method.
1406+ $ method = new \ReflectionMethod ( $ renderer , 'extract_fields_from_item ' );
1407+ $ method ->setAccessible ( true );
1408+
1409+ $ structure = $ layout ->get_structure ();
1410+ $ section_item = $ structure ['items ' ][0 ]['tabs ' ][0 ]['items ' ][0 ];
1411+
1412+ $ result = $ method ->invoke ( $ renderer , $ section_item );
1413+
1414+ // Should return an accordion config that preserves the section label.
1415+ $ this ->assertCount ( 1 , $ result );
1416+ $ this ->assertEquals ( 'accordion ' , $ result [0 ]['type ' ] );
1417+ $ this ->assertEquals ( 'Contact Info ' , $ result [0 ]['label ' ] );
1418+ $ this ->assertTrue ( $ result [0 ]['value ' ] ); // Expanded by default.
1419+ $ this ->assertArrayHasKey ( 'fields ' , $ result [0 ] );
1420+ $ this ->assertCount ( 2 , $ result [0 ]['fields ' ] );
1421+ }
1422+
1423+ public function test_renderer_action_buttons_output_html (): void {
1424+ $ renderer = new \Tangible \Renderer \TangibleFieldsRenderer ();
1425+
1426+ // Test the protected method.
1427+ $ method = new \ReflectionMethod ( $ renderer , 'render_action ' );
1428+ $ method ->setAccessible ( true );
1429+
1430+ // Test save button.
1431+ $ save_html = $ method ->invoke ( $ renderer , 'save ' );
1432+ $ this ->assertStringContainsString ( '<button ' , $ save_html );
1433+ $ this ->assertStringContainsString ( 'type="submit" ' , $ save_html );
1434+ $ this ->assertStringContainsString ( 'name="action" ' , $ save_html );
1435+ $ this ->assertStringContainsString ( 'value="save" ' , $ save_html );
1436+ $ this ->assertStringContainsString ( '>Save</button> ' , $ save_html );
1437+
1438+ // Test delete button.
1439+ $ delete_html = $ method ->invoke ( $ renderer , 'delete ' );
1440+ $ this ->assertStringContainsString ( '<button ' , $ delete_html );
1441+ $ this ->assertStringContainsString ( 'type="submit" ' , $ delete_html );
1442+ $ this ->assertStringContainsString ( 'value="delete" ' , $ delete_html );
1443+ $ this ->assertStringContainsString ( '>Delete</button> ' , $ delete_html );
1444+ $ this ->assertStringContainsString ( 'onclick= ' , $ delete_html );
1445+
1446+ // Test custom action.
1447+ $ custom_html = $ method ->invoke ( $ renderer , 'archive ' );
1448+ $ this ->assertStringContainsString ( '<button ' , $ custom_html );
1449+ $ this ->assertStringContainsString ( 'value="archive" ' , $ custom_html );
1450+ $ this ->assertStringContainsString ( '>Archive</button> ' , $ custom_html );
1451+ }
1452+
13271453 /**
13281454 * ==========================================================================
13291455 * DataView with TangibleFieldsRenderer Tests
0 commit comments