From 8149f97c005ba018429f035a3b4da16162a073c9 Mon Sep 17 00:00:00 2001
From: Lauri Eskola <lauri.eskola@acquia.com>
Date: Wed, 3 May 2023 17:45:25 +0300
Subject: [PATCH] Issue #3351356 by bnjmnm, longwave, dww, jan kellermann,
 smustgrave: Reduce toolbar user button related browser reflow

---
 core/modules/toolbar/js/toolbar.js                        | 2 ++
 .../src/FunctionalJavascript/ToolbarStoredStateTest.php   | 8 ++++++++
 core/modules/toolbar/toolbar.module                       | 7 +++++++
 3 files changed, 17 insertions(+)

diff --git a/core/modules/toolbar/js/toolbar.js b/core/modules/toolbar/js/toolbar.js
index a3cf46a98223..c7eba1e805ea 100644
--- a/core/modules/toolbar/js/toolbar.js
+++ b/core/modules/toolbar/js/toolbar.js
@@ -238,6 +238,7 @@
         Drupal.toolbar.models.toolbarModel.on(
           'change:activeTab change:orientation change:isOriented change:isTrayToggleVisible change:offsets',
           function () {
+            const userButton = document.querySelector('#toolbar-item-user');
             const hasActiveTab = !!$(this.get('activeTab')).length > 0;
             const previousToolbarState = sessionStorage.getItem(
               'Drupal.toolbar.toolbarState',
@@ -255,6 +256,7 @@
               activeTray: $(this.get('activeTab')).attr('data-toolbar-tray'),
               isOriented: this.get('isOriented'),
               isFixed: this.get('isFixed'),
+              userButtonMinWidth: userButton ? userButton.clientWidth : 0,
             };
             // Store toolbar UI state in session storage, so it can be accessed
             // by JavaScript that executes before the first paint.
diff --git a/core/modules/toolbar/tests/src/FunctionalJavascript/ToolbarStoredStateTest.php b/core/modules/toolbar/tests/src/FunctionalJavascript/ToolbarStoredStateTest.php
index cdb5960b0f25..ad8e59aa1a58 100644
--- a/core/modules/toolbar/tests/src/FunctionalJavascript/ToolbarStoredStateTest.php
+++ b/core/modules/toolbar/tests/src/FunctionalJavascript/ToolbarStoredStateTest.php
@@ -54,6 +54,14 @@ public function testToolbarStoredState() {
       $this->getSession()->evaluateScript("sessionStorage.getItem('Drupal.toolbar.toolbarState')")
     );
 
+    // The userButtonMinWidth property will differ depending on the length of
+    // the test-generated username, so it is checked differently and the value
+    // is copied to the expected value array.
+    $this->assertNotNull($toolbar_stored_state['userButtonMinWidth']);
+    $this->assertIsNumeric($toolbar_stored_state['userButtonMinWidth']);
+    $this->assertGreaterThan(60, $toolbar_stored_state['userButtonMinWidth']);
+    $expected['userButtonMinWidth'] = $toolbar_stored_state['userButtonMinWidth'];
+
     $this->assertSame($expected, $toolbar_stored_state);
 
     $page->clickLink('toolbar-item-user');
diff --git a/core/modules/toolbar/toolbar.module b/core/modules/toolbar/toolbar.module
index 7b3e5d097688..e5ebb050393b 100644
--- a/core/modules/toolbar/toolbar.module
+++ b/core/modules/toolbar/toolbar.module
@@ -76,6 +76,7 @@ function toolbar_page_attachments(array &$page) {
       activeTray,
       activeTabId,
       isOriented,
+      userButtonMinWidth
     } = toolbarState;
 
     classesToAdd.push(
@@ -114,6 +115,12 @@ classesToAdd.push('toolbar-oriented');
       style.textContent = styleContent;
       style.setAttribute('data-toolbar-anti-flicker-loading', true);
       document.querySelector('head').appendChild(style);
+
+      if (userButtonMinWidth) {
+        const userButtonStyle = document.createElement('style');
+        userButtonStyle.textContent = `#toolbar-item-user {min-width: ` + userButtonMinWidth +`px;}`
+        document.querySelector('head').appendChild(userButtonStyle);
+      }
     }
   }
   document.querySelector('html').classList.add(...classesToAdd);
-- 
GitLab