@@ -16,7 +16,13 @@ import {
1616 RichText ,
1717} from '@wordpress/block-editor' ;
1818import { useSelect , useDispatch } from '@wordpress/data' ;
19- import { useMemo , useRef , useEffect } from '@wordpress/element' ;
19+ import {
20+ useMemo ,
21+ useRef ,
22+ useEffect ,
23+ useCallback ,
24+ useState ,
25+ } from '@wordpress/element' ;
2026import { decodeEntities } from '@wordpress/html-entities' ;
2127/**
2228 * Internal dependencies
@@ -46,27 +52,44 @@ export default function Edit( {
4652 const { selectBlock } = useDispatch ( blockEditorStore ) ;
4753
4854 const innerBlocksRef = useRef ( null ) ;
49- const labelRef = useRef ( ) ;
5055 const focusRef = useRef ( ) ;
56+ const [ isInitialMount , setIsInitialMount ] = useState ( true ) ;
57+ const labelElementRef = useRef ( null ) ;
5158
5259 const { anchor, label } = attributes ;
5360
54- // Focus the label RichText component when no label exists
55- // and when the block is mounted.
61+ // Callback ref that stores the element and focuses on initial mount.
62+ const labelRef = useCallback (
63+ ( node ) => {
64+ labelElementRef . current = node ;
65+ if ( node && isInitialMount ) {
66+ // Focus immediately when ref is set on initial mount.
67+ const animationId = requestAnimationFrame ( ( ) => {
68+ if ( node ) {
69+ node . focus ( ) ;
70+ }
71+ } ) ;
72+ focusRef . current = animationId ;
73+ setIsInitialMount ( false ) ;
74+ }
75+ } ,
76+ [ isInitialMount ]
77+ ) ;
78+
79+ // Focus the label RichText component when no label exists (after initial mount).
5680 useEffect ( ( ) => {
57- if ( ! label && labelRef . current ) {
81+ if ( ! label && ! isInitialMount && labelElementRef . current ) {
5882 const animationId = requestAnimationFrame ( ( ) => {
59- if ( labelRef . current ) {
60- labelRef . current . focus ( ) ;
83+ if ( labelElementRef . current ) {
84+ labelElementRef . current . focus ( ) ;
6185 }
6286 } ) ;
63-
6487 focusRef . current = animationId ;
6588 return ( ) => cancelAnimationFrame ( focusRef . current ) ;
6689 }
67- } , [ label ] ) ;
90+ } , [ label , isInitialMount ] ) ;
6891
69- // Clean up animation frames on unmount
92+ // Clean up animation frames on unmount.
7093 useEffect ( ( ) => {
7194 return ( ) => {
7295 if ( focusRef . current ) {
@@ -123,6 +146,16 @@ export default function Edit( {
123146 [ clientId ]
124147 ) ;
125148
149+ // Auto-label the first tab when it has no label
150+ // useEffect( () => {
151+ // if ( ! label && blockIndex === 0 ) {
152+ // setAttributes( {
153+ // label: 'Tab 1',
154+ // anchor: 'tab-1',
155+ // } );
156+ // }
157+ // }, [ label, blockIndex, setAttributes ] );
158+
126159 /**
127160 * This hook determines if the current tab is selected. This is true if it is the active tab, or if it is selected directly.
128161 */
@@ -218,7 +251,7 @@ export default function Edit( {
218251 selectBlock ( clientId ) ;
219252 focusRef . current = requestAnimationFrame (
220253 ( ) => {
221- labelRef . current . focus ( ) ;
254+ labelElementRef . current ? .focus ( ) ;
222255 }
223256 ) ;
224257 }
@@ -232,7 +265,9 @@ export default function Edit( {
232265 'core/italic' ,
233266 'core/strikethrough' ,
234267 ] }
235- placeholder = { __ ( 'Add tab label…' ) }
268+ placeholder = {
269+ __ ( 'Tab' ) + ` ${ blockIndex + 1 } …`
270+ }
236271 value = { decodeEntities ( label ) }
237272 onChange = { ( value ) =>
238273 setAttributes ( {
0 commit comments