tabIndexed = $config['tabIndexed'] ?? $this; // Initialization $this->setTabIndex( $config['tabIndex'] ?? 0 ); $this->registerConfigCallback( function ( &$config ) { if ( $this->tabIndex !== 0 ) { $config['tabIndex'] = $this->tabIndex; } } ); } /** * Set tab index value. * * @param string|int|null $tabIndex Tab index value or null for no tab index * @return $this */ public function setTabIndex( $tabIndex ) { $tabIndex = preg_match( '/^-?\d+$/', $tabIndex ) ? (int)$tabIndex : null; if ( $this->tabIndex !== $tabIndex ) { $this->tabIndex = $tabIndex; $this->updateTabIndex(); } return $this; } /** * Update the tabIndex attribute, in case of changes to tabIndex or disabled * state. * * @return $this */ public function updateTabIndex() { $disabled = $this->isDisabled(); if ( $this->tabIndex !== null ) { $this->tabIndexed->setAttributes( [ // Do not index over disabled elements 'tabindex' => $disabled ? -1 : $this->tabIndex, // ChromeVox and NVDA do not seem to inherit this from parent elements 'aria-disabled' => ( $disabled ? 'true' : 'false' ) ] ); } else { $this->tabIndexed->removeAttributes( [ 'tabindex', 'aria-disabled' ] ); } return $this; } /** * Get tab index value. * * @return int|null Tab index value */ public function getTabIndex() { return $this->tabIndex; } /** * Get an ID of a focusable element of this widget, if any, to be used for `