diff --git a/core/modules/media_library/css/media_library.theme.css b/core/modules/media_library/css/media_library.theme.css index 197c3f0bd3..0e066d8887 100644 --- a/core/modules/media_library/css/media_library.theme.css +++ b/core/modules/media_library/css/media_library.theme.css @@ -27,8 +27,10 @@ margin: 0; } -/* @todo Use a class instead of the li element. - https://www.drupal.org/project/drupal/issues/3029227 */ +/** + * @todo Use a class instead of the li element. + * https://www.drupal.org/project/drupal/issues/3029227 + */ .media-library-menu li { display: block; } @@ -84,10 +86,6 @@ } /* Generic media add form styles. */ -.media-library-add-form-wrapper { - outline: none; -} - .media-library-add-form--without-input .form-item { margin: 0 0 1em; } @@ -95,8 +93,8 @@ /** * Remove outline from added media container. * - * The added media container receives focus after adding new media, but doesn't - * need the outline. + * The added media container receives focus after adding new media, but since + * it is not an interactive element it does not need an outline. */ .media-library-add-form__added-media { outline: none; @@ -137,8 +135,10 @@ width: 100%; } -/* @todo Remove .button when styles are moved to the seven theme in - https://www.drupal.org/project/drupal/issues/2980769 */ +/** + * @todo Remove .button when styles are moved to the seven theme in + * https://www.drupal.org/project/drupal/issues/2980769 + */ .button.media-library-add-form-oembed-submit { align-self: center; } @@ -166,8 +166,13 @@ margin: 0.75em 0; } -/* Override the table display of the visually hidden labels so they won't take - up space. */ +/** + * Override the table display of the visually hidden labels. + * + * The width, height and overflow properties in the styles for the + * .visually-hidden class do not work correctly if the element has a table + * display. + */ .media-library-item label { display: inline-block; } @@ -180,8 +185,10 @@ justify-content: space-between; } -/* @todo Remove order and reorder the views header and filters via a views - template in https://www.drupal.org/project/drupal/issues/3035994 */ +/** + * @todo Remove order and reorder the views header and filters via a views + * template in https://www.drupal.org/project/drupal/issues/3035994 + */ .media-library-wrapper .view-header { order: 2; align-self: flex-end; @@ -192,21 +199,27 @@ text-align: left; } -/* @todo Remove order and reorder the views header and filters via a views - template in https://www.drupal.org/project/drupal/issues/3035994 */ +/** + * @todo Remove order and reorder the views header and filters via a views + * template in https://www.drupal.org/project/drupal/issues/3035994 + */ .media-library-wrapper .media-library-view .view-filters { order: 1; } -/* @todo Remove order and reorder the views header and filters via a views - template in https://www.drupal.org/project/drupal/issues/3035994 */ +/** + * @todo Remove order and reorder the views header and filters via a views + * template in https://www.drupal.org/project/drupal/issues/3035994 + */ .media-library-wrapper .media-library-view .view-content { flex: 0 0 100%; order: 3; } -/* @todo Remove order and reorder the views header and filters via a views - template in https://www.drupal.org/project/drupal/issues/3035994 */ +/** + * @todo Remove order and reorder the views header and filters via a views + * template in https://www.drupal.org/project/drupal/issues/3035994 + */ .media-library-wrapper .media-library-view .pager { order: 4; } @@ -417,8 +430,10 @@ position: relative; } -/* @todo Change to .media-library-open-button when styles are moved to the - seven theme in https://www.drupal.org/project/drupal/issues/2980769 */ +/** + * @todo Change to .media-library-open-button when styles are moved to the + * seven theme in https://www.drupal.org/project/drupal/issues/2980769 + */ .button.media-library-open-button { margin-left: 0; /* LTR */ } @@ -478,12 +493,19 @@ border-color: #40b6ff; } -/* Style the wrappers around new media and files. */ +/** + * Style the added media item container. + * + * The added media container receives screen reader focus since it is has the + * role 'listitem'. Since it is not an interactive element, it does not need + * an outline. + */ .media-library-add-form__media { position: relative; display: flex; padding: 20px 0 20px 0; border-bottom: 1px solid #c0c0c0; + outline: none; } /* Do not show the top padding for the first item. */ @@ -491,8 +513,12 @@ padding-top: 0; } -/* The first item doesn't have a top padding, change the location of the remove - button as well. */ +/** + * Change the position of the remove button for the first item. + * + * The first item doesn't have a top padding, change the location of the remove + * button as well. + */ .media-library-add-form__media:first-child .media-library-add-form__remove-button[type="submit"] { top: 5px; } @@ -525,8 +551,10 @@ margin-left: 20px; } -/* @todo Remove [type="submit"] when styles are moved to the seven theme in - https://www.drupal.org/project/drupal/issues/2980769 */ +/** + * @todo Remove [type="submit"] when styles are moved to the seven theme in + * https://www.drupal.org/project/drupal/issues/2980769 + */ .media-library-add-form__remove-button[type="submit"] { position: absolute; top: 25px; diff --git a/core/modules/media_library/src/Form/AddFormBase.php b/core/modules/media_library/src/Form/AddFormBase.php index 7391879582..c4f4452828 100644 --- a/core/modules/media_library/src/Form/AddFormBase.php +++ b/core/modules/media_library/src/Form/AddFormBase.php @@ -146,10 +146,14 @@ public function buildForm(array $form, FormStateInterface $form_state) { 'class' => [ 'media-library-add-form__added-media', ], - // Add the tabindex '-1' to allow the focus to be shifted to the - // container. - 'tabindex' => -1, 'aria-label' => $this->t('Added media items'), + 'role' => 'list', + // Add the tabindex '-1' to allow the focus to be shifted to the added + // media wrapper when items are added. We set focus to the container + // because a media item does not necessarily have required fields and + // we do not want to set focus to the remove button automatically. + // @see ::updateFormCallback() + 'tabindex' => '-1', ], ]; @@ -211,6 +215,14 @@ protected function buildEntityFormElement(MediaInterface $media, array $form, Fo 'class' => [ 'media-library-add-form__media', ], + 'aria-label' => $media->getName(), + 'role' => 'listitem', + // Add the tabindex '-1' to allow the focus to be shifted to the next + // media item when an item is removed. We set focus to the container + // because a media item does not necessarily have required fields and we + // do not want to set focus to the remove button automatically. + // @see ::updateFormCallback() + 'tabindex' => '-1', ], 'preview' => [ '#type' => 'container', @@ -436,10 +448,21 @@ public function updateFormCallback(array &$form, FormStateInterface $form_state) $response->addCommand(new ReplaceCommand('#media-library-add-form-wrapper', $this->buildMediaLibraryUi($form_state))); $response->addCommand(new InvokeCommand('#media-library-add-form-wrapper :tabbable', 'focus')); } - // When there are still more items, the AJAX system automatically sets - // focus to the next remove button. + // When there are still more items, update the form and shift the focus to + // the next media item. This is technically the item with the same delta + // as the one that has been removed. If the last list item is removed, + // shift focus to the previous item. else { $response->addCommand(new ReplaceCommand("#$wrapper_id", $form)); + + // We need to add 1 to the delta to shift focus to the next item, + // because the 'nth-child' selector starts counting with 1 and the delta + // starts with 0. + $delta = array_slice($triggering_element['#array_parents'], -2, 1)[0]; + if (isset($added_media[$delta])) { + $delta++; + } + $response->addCommand(new InvokeCommand(".media-library-add-form__media:nth-child($delta)", 'focus')); } } // Update the form and shift focus to the added media items.