diff --git a/app/test/frontend/static_files_test.dart b/app/test/frontend/static_files_test.dart index f6ce10601a..7f06fd83a8 100644 --- a/app/test/frontend/static_files_test.dart +++ b/app/test/frontend/static_files_test.dart @@ -200,7 +200,7 @@ void main() { test('script.dart.js and parts size check', () { final file = cache.getFile('/static/js/script.dart.js'); expect(file, isNotNull); - expect((file!.bytes.length / 1024).round(), closeTo(313, 1)); + expect((file!.bytes.length / 1024).round(), closeTo(317, 1)); final parts = cache.paths .where((path) => diff --git a/pkg/web_app/lib/src/foldable.dart b/pkg/web_app/lib/src/foldable.dart index 551b262a98..ac4b15520a 100644 --- a/pkg/web_app/lib/src/foldable.dart +++ b/pkg/web_app/lib/src/foldable.dart @@ -2,6 +2,7 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +import 'dart:async'; import 'dart:html'; import 'dart:math' show min, max; @@ -22,41 +23,26 @@ void _setEventForFoldable() { final scrollContainer = _parentWithClass(h, 'scroll-container'); if (content == null) continue; - Future update(bool isActive) async { - // Closing is simple: no measurements, no scrolling. + Future toggle() async { + final isActive = foldable.classes.toggle('-active'); if (!isActive) { - content.style.maxHeight = '0px'; return; } - /// The following coordinate and dimension measurements trigger a reflow, - /// but it is acceptable, as it is local to this event processing and the - /// impact is low. - if (content.style.display != 'block') { - content.style.display = 'block'; - } - // Needs to be empty to measure real dimension. - content.style.maxHeight = ''; - - final contentHeight = content.offsetHeight; - final boundingRect = content.getBoundingClientRect(); - final scrollContainerHeight = scrollContainer?.clientHeight; - final buttonHeight = h.offsetHeight; - - // Reset content state as hidden. - content.style.maxHeight = '0px'; - - // Wait one animation frame before trigger the full height content. - await window.animationFrame; - content.style.maxHeight = '${contentHeight}px'; - num scrollDiff = 0; if (scrollContainer != null) { + // Wait one animation frame before measurements. + await window.animationFrame; + + final boundingRect = content.getBoundingClientRect(); + final scrollContainerHeight = scrollContainer.clientHeight; + final buttonHeight = h.offsetHeight; + /// Calculate the required amount of scrolling in order to have the /// entire content in the view, aligning it at the bottom of the visible /// scroll view. final outsideViewDiff = - boundingRect.top + boundingRect.height - scrollContainerHeight!; + boundingRect.top + boundingRect.height - scrollContainerHeight; /// Limit the maximum scrolling to the screen height minus the button /// component's height, in order to make sure it will be still visible @@ -65,30 +51,31 @@ void _setEventForFoldable() { /// Scroll the smaller amount of the two. scrollDiff = max(0, min(screenLimit, outsideViewDiff)); - } - /// Do not scroll if the difference is small, otherwise scroll in small - /// steps synchronized to the animation frames. - if (scrollDiff > 8) { - final originalScrollTop = scrollContainer!.scrollTop; - final maxSteps = 20; - for (var i = 1; i <= maxSteps; i++) { - if (i > 1) await window.animationFrame; - final nextPos = originalScrollTop + (scrollDiff * i / maxSteps); - scrollContainer.scrollTo(0, nextPos); + /// Do not scroll if the difference is small, otherwise scroll in small + /// steps synchronized to the animation frames. + if (scrollDiff > 8) { + final originalScrollTop = scrollContainer.scrollTop; + final maxSteps = 20; + for (var i = 1; i <= maxSteps; i++) { + if (i > 1) await window.animationFrame; + final nextPos = originalScrollTop + (scrollDiff * i / maxSteps); + scrollContainer.scrollTo(0, nextPos); + } } } - - // Wait one animation frame before enabling the content to resize on its own. - await window.animationFrame; - content.style.maxHeight = 'none'; } + h.querySelector('.foldable-icon')!.attributes['tabindex'] = '0'; + // listen on trigger events h.onClick.listen((e) async { - // Toggle state. - final isActive = foldable.classes.toggle('-active'); - await update(isActive); + e.preventDefault(); + await toggle(); + }); + h.onKeyDown.where((e) => e.key == 'Enter').listen((e) async { + e.preventDefault(); + await toggle(); }); } } diff --git a/pkg/web_css/lib/src/_base.scss b/pkg/web_css/lib/src/_base.scss index f8904f2b9c..14717fb622 100644 --- a/pkg/web_css/lib/src/_base.scss +++ b/pkg/web_css/lib/src/_base.scss @@ -380,8 +380,6 @@ pre { .foldable { .foldable-content { display: none; - overflow: hidden; - transition: max-height 0.6s ease; } &.-active {