Verified Commit 34b0bcda authored by Théodore Biadala's avatar Théodore Biadala
Browse files

Issue #2998451 by bnjmnm, HOG, lauriii, ndf, gaurav-mathur, Ambient.Impact,...

Issue #2998451 by bnjmnm, HOG, lauriii, ndf, gaurav-mathur, Ambient.Impact, Chi, nod_, andy-blum, droplet: Toolbar tray rendering can result "flickering" resizing of content area to accommodate open trays
parent 0c59ee88
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -356,6 +356,9 @@ function shortcut_toolbar() {
            'keys' => ['shortcut_set_toolbar_links'],
            'contexts' => ['user'],
          ],
          '#lazy_builder_preview' => [
            '#markup' => '<a href="#" class="toolbar-tray-lazy-placeholder-link">&nbsp;</a>',
          ],
        ],
      ],
      '#weight' => -10,
+50 −35
Original line number Diff line number Diff line
@@ -79,23 +79,6 @@
  right: 0;
  left: 0;
}
/* .toolbar-loading is required by Toolbar JavaScript to pre-render markup
 * style to avoid extra reflow & flicker. */
@media (min-width: 61em) {
  .toolbar-loading.toolbar-horizontal .toolbar .toolbar-bar .toolbar-tab:last-child .toolbar-tray {
    position: relative;
    z-index: -999;
    display: block;
    visibility: hidden;
    width: 1px;
  }
  .toolbar-loading.toolbar-horizontal .toolbar .toolbar-bar .toolbar-tab:last-child .toolbar-tray .toolbar-lining {
    width: 999em;
  }
  .toolbar-loading.toolbar-horizontal .toolbar .toolbar-bar .home-toolbar-tab + .toolbar-tab .toolbar-tray {
    display: block;
  }
}

/* Layer the bar just above the trays and above contextual link triggers. */
.toolbar-oriented .toolbar-bar {
@@ -103,13 +86,13 @@
}
/* Position the admin toolbar fixed when the configured standard breakpoint is
 * active. */
body.toolbar-fixed .toolbar-oriented .toolbar-bar {
.toolbar-fixed .toolbar-oriented .toolbar-bar {
  position: fixed;
}
/* When the configured narrow breakpoint is active, the toolbar is sized to wrap
 * around the trays in order to provide a context for scrolling tray content
 * that is taller than the viewport. */
body.toolbar-tray-open.toolbar-fixed.toolbar-vertical .toolbar-oriented {
.toolbar-tray-open.toolbar-fixed.toolbar-vertical .toolbar-oriented {
  bottom: 0;
  width: 240px;
  width: 15rem;
@@ -198,7 +181,7 @@ body.toolbar-tray-open.toolbar-fixed.toolbar-vertical .toolbar-oriented {
 * the tray scroll within the confines of the viewport.
 */
.toolbar .toolbar-tray-vertical.is-active,
body.toolbar-fixed .toolbar .toolbar-tray-vertical {
.toolbar-fixed .toolbar .toolbar-tray-vertical {
  position: fixed;
  overflow-x: hidden;
  overflow-y: auto;
@@ -217,27 +200,16 @@ body.toolbar-fixed .toolbar .toolbar-tray-vertical {
}
/* When the configured standard breakpoint is active, the tray appears to push
 * the page content away from the edge of the viewport. */
body.toolbar-tray-open.toolbar-vertical.toolbar-fixed {
  margin-left: 240px; /* LTR */
  margin-left: 15rem; /* LTR */
.toolbar-tray-open.toolbar-vertical.toolbar-fixed {
  margin-inline-start: 15rem;
}

@media print {
  body.toolbar-tray-open.toolbar-vertical.toolbar-fixed {
    margin-left: 0;
  .toolbar-tray-open.toolbar-vertical.toolbar-fixed {
    margin-inline-start: 0;
  }
}
[dir="rtl"] body.toolbar-tray-open.toolbar-vertical.toolbar-fixed {
  margin-right: 240px;
  margin-right: 15rem;
  margin-left: auto;
}

@media print {
  [dir="rtl"] body.toolbar-tray-open.toolbar-vertical.toolbar-fixed {
    margin-right: 0;
  }
}
/**
 * ToolBar tray orientation toggle.
 */
@@ -278,3 +250,46 @@ body.toolbar-tray-open.toolbar-vertical.toolbar-fixed {
.path-admin .toolbar-bar .home-toolbar-tab {
  display: block;
}

/* Anti flicker styling. */
.toolbar-anti-flicker.toolbar-loading.toolbar-fixed body {
  padding-top: 2.4375rem;
}
.toolbar-anti-flicker.toolbar-loading.toolbar-fixed.toolbar-horizontal.toolbar-tray-open body {
  padding-top: 4.91331rem;
}

.toolbar-anti-flicker.toolbar-loading.toolbar-vertical.toolbar-tray-open .toolbar-tray {
  position: fixed;
  z-index: -1;
  top: 2.4375rem;
  bottom: 0;
  display: block;
  width: 15rem;
  inset-inline-start: 0;
}
.toolbar-tray-lazy-placeholder-link {
  position: relative;
  z-index: 0;
  display: block;
}
.toolbar-tray-open.toolbar-fixed.toolbar-vertical #toolbar-administration {
  margin-inline-start: -15rem;
}
.toolbar .toolbar-tray-vertical > .toolbar-lining::before {
  width: 100%;
}
.toolbar-oriented .toolbar-tray-vertical > .toolbar-lining::before {
  position: fixed;
  z-index: -1;
  top: 0;
  bottom: 0;
  display: block;
  width: 15rem;
  content: "";
  inset-inline-start: 0;
}

.toolbar-anti-flicker.toolbar-vertical.toolbar-tray-open .menu-item + .menu-item {
  border-top: 1px solid #ddd;
}
+80 −4
Original line number Diff line number Diff line
@@ -4,6 +4,39 @@
 */

(function ($, Drupal, drupalSettings) {
  // Set UI-impacting toolbar classes before Drupal behaviors initialize to
  // minimize flickering on load. This is encapsulated in a function to
  // emphasize this having a distinct purpose than the code that follows it.
  (() => {
    if (!sessionStorage.getItem('Drupal.toolbar.toolbarState')) {
      return;
    }
    const toolbarState = JSON.parse(
      sessionStorage.getItem('Drupal.toolbar.toolbarState'),
    );
    const { activeTray, orientation, isOriented } = toolbarState;
    const activeTrayElement = document.querySelector(
      `.toolbar-tray[data-toolbar-tray="${activeTray}"]`,
    );
    const activeTrayToggle = document.querySelector(
      `.toolbar-item[data-toolbar-tray="${activeTray}"]`,
    );

    if (activeTrayElement) {
      activeTrayElement.classList.add(
        `toolbar-tray-${orientation}`,
        'is-active',
      );
      activeTrayToggle.classList.add('is-active');
    }

    if (isOriented) {
      document
        .querySelector('#toolbar-administration')
        .classList.add('toolbar-oriented');
    }
  })();

  // Merge run-time settings with the defaults.
  const options = $.extend(
    {
@@ -150,13 +183,20 @@
            $(document).trigger('drupalToolbarTrayChange', tray);
          });

        // If the toolbar's orientation is horizontal and no active tab is
        // defined then show the tray of the first toolbar tab by default (but
        // not the first 'Home' toolbar tab).
        const toolbarState = sessionStorage.getItem(
          'Drupal.toolbar.toolbarState',
        )
          ? JSON.parse(sessionStorage.getItem('Drupal.toolbar.toolbarState'))
          : {};
        // If the toolbar's orientation is horizontal, no active tab is defined,
        // and the orientation state is not set (which means the user has not
        // yet interacted with the toolbar), then show the tray of the first
        // toolbar tab by default (but not the first 'Home' toolbar tab).
        if (
          Drupal.toolbar.models.toolbarModel.get('orientation') ===
            'horizontal' &&
          Drupal.toolbar.models.toolbarModel.get('activeTab') === null
          Drupal.toolbar.models.toolbarModel.get('activeTab') === null &&
          !toolbarState.orientation
        ) {
          Drupal.toolbar.models.toolbarModel.set({
            activeTab: $(
@@ -190,6 +230,42 @@
          },
        });
      });

      // Add anti-flicker functionality.
      if (
        once('toolbarAntiFlicker', '#toolbar-administration', context).length
      ) {
        Drupal.toolbar.models.toolbarModel.on(
          'change:activeTab change:orientation change:isOriented change:isTrayToggleVisible change:offsets',
          function () {
            const hasActiveTab = !!$(this.get('activeTab')).length > 0;
            const previousToolbarState = sessionStorage.getItem(
              'Drupal.toolbar.toolbarState',
            )
              ? JSON.parse(
                  sessionStorage.getItem('Drupal.toolbar.toolbarState'),
                )
              : {};
            const toolbarState = {
              ...previousToolbarState,
              orientation:
                Drupal.toolbar.models.toolbarModel.get('orientation'),
              hasActiveTab,
              activeTabId: hasActiveTab ? this.get('activeTab').id : null,
              activeTray: $(this.get('activeTab')).attr('data-toolbar-tray'),
              isOriented: this.get('isOriented'),
              isFixed: this.get('isFixed'),
            };
            // Store toolbar UI state in session storage, so it can be accessed
            // by JavaScript that executes before the first paint.
            // @see core/modules/toolbar/js/toolbar.anti-flicker.js
            sessionStorage.setItem(
              'Drupal.toolbar.toolbarState',
              JSON.stringify(toolbarState),
            );
          },
        );
      }
    },
  };

+5 −1
Original line number Diff line number Diff line
@@ -113,7 +113,11 @@
          });
          $item
            .children('.toolbar-box')
            .append(Drupal.theme('toolbarMenuItemToggle', options));
            .append(
              $(Drupal.theme('toolbarMenuItemToggle', options))
                .hide()
                .fadeIn(150),
            );
        }
      });
    }
+13 −0
Original line number Diff line number Diff line
@@ -114,6 +114,16 @@
        this.updateTrayOrientation();
        this.updateBarAttributes();

        $('[data-toolbar-anti-flicker-loading]').remove();
        $('html').removeClass([
          'toolbar-loading',
          'toolbar-horizontal',
          'toolbar-vertical',
          'toolbar-tray-open',
          'toolbar-fixed',
          'toolbar-oriented',
          'toolbar-anti-flicker',
        ]);
        $('body').removeClass('toolbar-loading');

        // Load the subtrees if the orientation of the toolbar is changed to
@@ -208,6 +218,9 @@
        // Deactivate the previous tray.
        $(this.model.previous('activeTray')).removeClass('is-active');

        // The stored active tab is removed as updateTabs() can be called when
        // a tray is explicitly closed, thus not replaced with a new active tab.
        localStorage.removeItem('Drupal.toolbar.activeTabID');
        // Activate the selected tab.
        if ($tab.length > 0) {
          $tab
Loading