From 0884605b62761c0b8aa5365d74d8778562ddbea6 Mon Sep 17 00:00:00 2001
From: かっこかり <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Sun, 4 May 2025 14:06:43 +0900
Subject: fix(frontend): MkFolderのアニメーションにフォールバックを追加
 (#15937)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* fix(frontend): Chrome系以外のブラウザでMkFolderがアニメーションしない問題を修正

* fix

* Update Changelog

* fix
---
 packages/frontend/src/components/MkFolder.vue | 56 +++++++++++++++++++++++++--
 1 file changed, 53 insertions(+), 3 deletions(-)

(limited to 'packages/frontend/src/components/MkFolder.vue')

diff --git a/packages/frontend/src/components/MkFolder.vue b/packages/frontend/src/components/MkFolder.vue
index 1236b843f2..e86861c874 100644
--- a/packages/frontend/src/components/MkFolder.vue
+++ b/packages/frontend/src/components/MkFolder.vue
@@ -31,6 +31,10 @@ SPDX-License-Identifier: AGPL-3.0-only
 				:leaveActiveClass="prefer.s.animation ? $style.transition_toggle_leaveActive : ''"
 				:enterFromClass="prefer.s.animation ? $style.transition_toggle_enterFrom : ''"
 				:leaveToClass="prefer.s.animation ? $style.transition_toggle_leaveTo : ''"
+				@enter="enter"
+				@afterEnter="afterEnter"
+				@leave="leave"
+				@afterLeave="afterLeave"
 			>
 				<KeepAlive>
 					<div v-show="opened">
@@ -86,6 +90,42 @@ const bgSame = ref(false);
 const opened = ref(props.defaultOpen);
 const openedAtLeastOnce = ref(props.defaultOpen);
 
+//#region interpolate-sizeに対応していないブラウザ向け（TODO: 主要ブラウザが対応したら消す）
+function enter(el: Element) {
+	if (CSS.supports('interpolate-size', 'allow-keywords')) return;
+	if (!(el instanceof HTMLElement)) return;
+
+	const elementHeight = el.getBoundingClientRect().height;
+	el.style.height = '0';
+	el.offsetHeight; // reflow
+	el.style.height = `${Math.min(elementHeight, props.maxHeight ?? Infinity)}px`;
+}
+
+function afterEnter(el: Element) {
+	if (CSS.supports('interpolate-size', 'allow-keywords')) return;
+	if (!(el instanceof HTMLElement)) return;
+
+	el.style.height = '';
+}
+
+function leave(el: Element) {
+	if (CSS.supports('interpolate-size', 'allow-keywords')) return;
+	if (!(el instanceof HTMLElement)) return;
+
+	const elementHeight = el.getBoundingClientRect().height;
+	el.style.height = `${elementHeight}px`;
+	el.offsetHeight; // reflow
+	el.style.height = '0';
+}
+
+function afterLeave(el: Element) {
+	if (CSS.supports('interpolate-size', 'allow-keywords')) return;
+	if (!(el instanceof HTMLElement)) return;
+
+	el.style.height = '';
+}
+//#endregion
+
 function toggle() {
 	if (!opened.value) {
 		openedAtLeastOnce.value = true;
@@ -108,17 +148,27 @@ onMounted(() => {
 .transition_toggle_enterActive,
 .transition_toggle_leaveActive {
 	overflow-y: hidden; // 子要素のmarginが突き出るため clip を使ってはいけない
-	transition: opacity 0.3s, height 0.3s !important;
+	transition: opacity 0.3s, height 0.3s;
 }
+
+@supports (interpolate-size: allow-keywords) {
+	.transition_toggle_enterFrom,
+	.transition_toggle_leaveTo {
+		height: 0;
+	}
+
+	.root {
+		interpolate-size: allow-keywords; // heightのtransitionを動作させるために必要
+	}
+}
+
 .transition_toggle_enterFrom,
 .transition_toggle_leaveTo {
 	opacity: 0;
-	height: 0;
 }
 
 .root {
 	display: block;
-	interpolate-size: allow-keywords; // heightのtransitionを動作させるために必要
 }
 
 .header {
-- 
cgit v1.2.3-freya

