Transition: Tiny updates

This commit is contained in:
Alexander Zinchuk 2023-04-15 13:50:41 +02:00
parent 01cf273b92
commit c467da8680
3 changed files with 154 additions and 114 deletions

View File

@ -1,9 +1,12 @@
.Transition {
position: relative;
width: 100%;
height: 100%;
> .Transition__slide {
width: 100%;
height: 100%;
animation-fill-mode: forwards !important;
&.from,
@ -25,9 +28,6 @@
transition: none !important;
}
/*
* slide
*/
&.slide-optimized,
&.slide-optimized-rtl {
contain: strict;
@ -40,8 +40,9 @@
position: absolute;
top: 0;
left: 0;
transition: transform var(--slide-transition);
transform: scale(0);
transition: transform var(--slide-transition);
}
}
@ -109,10 +110,6 @@
}
}
/*
* slide-vertical
*/
&.slide-vertical {
> .to {
transform: translateY(100%);
@ -145,10 +142,6 @@
}
}
/*
* slide-vertical-fade
*/
&.slide-vertical-fade {
> .to {
transform: translateY(100%);
@ -181,10 +174,6 @@
}
}
/*
* mv-slide
*/
&.mv-slide {
> .Transition__slide > div {
animation-fill-mode: forwards !important;
@ -221,19 +210,18 @@
}
}
/*
* slide-fade
*/
&.slide-fade {
> .from {
transform-origin: left;
transform: translateX(0);
transform-origin: left;
opacity: 1;
}
> .to {
transform-origin: left;
transform: translateX(1.5rem);
transform-origin: left;
opacity: 0;
}
@ -251,39 +239,40 @@
&.slide-fade.backwards {
> .from {
transform: translateX(0);
opacity: 1;
}
> .to {
transform: translateX(-1.5rem);
opacity: 0;
}
&.animating {
> .from {
animation: fade-in-backwards-opacity var(--slide-transition),
slide-fade-in-backwards-move var(--slide-transition);
slide-fade-in-backwards-move var(--slide-transition);
}
> .to {
animation: fade-out-backwards-opacity var(--slide-transition),
slide-fade-out-backwards-move var(--slide-transition);
slide-fade-out-backwards-move var(--slide-transition);
}
}
}
/*
* zoom-fade
*/
&.zoom-fade {
> .from {
transform-origin: center;
transform: scale(1);
transform-origin: center;
opacity: 1;
}
> .to {
transform-origin: center;
opacity: 0;
// We can omit `transform: scale(1.1);` here because `opacity` is 0.
// We need to for proper position calculation in `InfiniteScroll`.
@ -320,9 +309,6 @@
}
}
/*
* fade
*/
&.fade {
> .from {
opacity: 1;
@ -343,12 +329,49 @@
}
}
/*
* slide-layers
*/
&.semi-fade {
> .Transition__slide {
isolation: isolate;
}
> .from {
opacity: 1;
}
> .to {
opacity: 0;
}
&.animating {
> .to {
animation: fade-in-opacity 250ms ease;
}
}
}
&.semi-fade.backwards {
> .from {
opacity: 1;
}
> .to {
opacity: 1;
}
&.animating {
> .from {
animation: fade-in-backwards-opacity 250ms ease;
}
> .to {
animation: none !important;
}
}
}
&.slide-layers {
--background-color: var(--color-background);
background: black !important;
> .Transition__slide {
@ -373,6 +396,7 @@
&.slide-layers.backwards {
> .to {
transform: translateX(-20%);
opacity: 0.75;
}
@ -387,18 +411,15 @@
}
}
/*
* push-slide
*/
&.push-slide {
> .Transition__slide {
background: var(--color-background);
}
> .from {
transform-origin: center;
transform: scale(1);
transform-origin: center;
opacity: 1;
.custom-scroll {
@ -428,6 +449,7 @@
&.push-slide.backwards {
> .to {
transform: scale(0.7);
opacity: 0;
}
@ -442,9 +464,6 @@
}
}
/*
* slide-fade
*/
&.reveal {
> .to {
clip-path: inset(0 100% 0 0);
@ -478,9 +497,6 @@
}
}
/*
* common
*/
@keyframes fade-in-opacity {
0% {
opacity: 0;
@ -517,9 +533,6 @@
}
}
/*
* slide
*/
@keyframes slide-in {
0% {
transform: translateX(100%);
@ -556,9 +569,6 @@
}
}
/*
* slide-vertical
*/
@keyframes slide-vertical-in {
0% {
transform: translateY(100%);
@ -595,17 +605,15 @@
}
}
/*
* slide-vertical-fade
*/
@keyframes slide-vertical-fade-in {
0% {
transform: translateY(100%);
opacity: 0;
}
100% {
transform: translateY(0);
opacity: 1;
}
}
@ -613,10 +621,12 @@
@keyframes slide-vertical-fade-out {
0% {
transform: translateY(0);
opacity: 1;
}
100% {
transform: translateY(-100%);
opacity: 0;
}
}
@ -624,10 +634,12 @@
@keyframes slide-vertical-fade-in-backwards {
0% {
transform: translateY(0);
opacity: 1;
}
100% {
transform: translateY(100%);
opacity: 0;
}
}
@ -635,18 +647,16 @@
@keyframes slide-vertical-fade-out-backwards {
0% {
transform: translateY(-100%);
opacity: 0;
}
100% {
transform: translateY(0);
opacity: 1;
}
}
/*
* mv-slide
*/
@keyframes mv-slide-in {
0% {
transform: translateX(100vw);
@ -683,9 +693,6 @@
}
}
/*
* slide-fade
*/
@keyframes slide-fade-in-move {
0% {
transform: translateX(1.5rem);
@ -722,9 +729,6 @@
}
}
/*
* zoom-fade
*/
@keyframes zoom-fade-in-move {
0% {
transform: scale(1.1);
@ -752,16 +756,15 @@
}
}
/*
* slide-layers
*/
@keyframes slide-layers-out {
0% {
transform: translateX(0);
opacity: 1;
}
100% {
transform: translateX(-20%);
opacity: calc(1 - var(--layer-blackout-opacity));
}
}
@ -769,25 +772,25 @@
@keyframes slide-layers-out-backwards {
0% {
transform: translateX(-20%);
opacity: calc(1 - var(--layer-blackout-opacity));
}
100% {
transform: translateX(0);
opacity: 1;
}
}
/*
* push-slide
*/
@keyframes push-out {
0% {
transform: scale(1);
opacity: 1;
}
100% {
transform: scale(0.7);
opacity: 0;
}
}
@ -795,17 +798,16 @@
@keyframes push-out-backwards {
0% {
transform: scale(0.7);
opacity: 0;
}
100% {
transform: scale(1);
opacity: 1;
}
}
/*
* slide
*/
@keyframes slide-in-200 {
0% {
transform: translateX(200%);
@ -824,9 +826,6 @@
}
}
/*
* slide
*/
@keyframes reveal-in {
0% {
clip-path: inset(0 100% 0 0);
@ -836,9 +835,6 @@
}
}
/*
* slide
*/
@keyframes reveal-in-backwards {
0% {
clip-path: inset(0 0 0 0);

View File

@ -1,5 +1,4 @@
import type { RefObject } from 'react';
import type { FC } from '../../lib/teact/teact';
import React, { useLayoutEffect, useRef } from '../../lib/teact/teact';
import { addExtraClass, removeExtraClass, toggleExtraClass } from '../../lib/teact/teact-dom';
import { getGlobal } from '../../global';
@ -19,10 +18,11 @@ export type ChildrenFn = (isActive: boolean, isFrom: boolean, currentKey: number
export type TransitionProps = {
ref?: RefObject<HTMLDivElement>;
activeKey: number;
nextKey?: number;
name: (
'none' | 'slide' | 'slide-rtl' | 'mv-slide' | 'slide-fade' | 'zoom-fade' | 'slide-layers'
| 'fade' | 'push-slide' | 'reveal' | 'slide-optimized' | 'slide-optimized-rtl' | 'slide-vertical'
| 'slide-vertical-fade'
| 'fade' | 'push-slide' | 'reveal' | 'slide-optimized' | 'slide-optimized-rtl' | 'semi-fade'
| 'slide-vertical' | 'slide-vertical-fade'
);
direction?: 'auto' | 'inverse' | 1 | -1;
renderCount?: number;
@ -32,9 +32,9 @@ export type TransitionProps = {
// Used by async components which are usually remounted during first animation
shouldWrap?: boolean;
wrapExceptionKey?: number;
isDisabled?: boolean;
id?: string;
className?: string;
slideClassName?: string;
onStart?: NoneToVoidFunction;
onStop?: NoneToVoidFunction;
children: React.ReactNode | ChildrenFn;
@ -48,9 +48,10 @@ const CLASSES = {
afterSlides: 'Transition__after-slides',
};
const Transition: FC<TransitionProps> = ({
function Transition({
ref,
activeKey,
nextKey,
name,
direction = 'auto',
renderCount,
@ -61,11 +62,12 @@ const Transition: FC<TransitionProps> = ({
wrapExceptionKey,
id,
className,
slideClassName,
onStart,
onStop,
children,
afterChildren,
}) => {
}: TransitionProps) {
// No need for a container to update on change
const { animationLevel } = getGlobal().settings.byKey;
const currentKeyRef = useRef<number>();
@ -87,6 +89,9 @@ const Transition: FC<TransitionProps> = ({
}
rendersRef.current[activeKey] = children;
if (nextKey) {
rendersRef.current[nextKey] = children;
}
useLayoutEffect(() => {
function cleanup() {
@ -102,30 +107,38 @@ const Transition: FC<TransitionProps> = ({
}
const container = containerRef.current!;
const childElements = (Array.from(container.children) as HTMLElement[])
.filter((el) => !el.classList.contains(CLASSES.afterSlides));
childElements.forEach((el) => {
addExtraClass(el, CLASSES.slide);
});
if (childElements.length === 1 && !activeKeyChanged) {
const firstChild = childElements[0];
if (name.startsWith('slide-optimized')) {
firstChild.style.transition = 'none';
firstChild.style.transform = 'translate3d(0, 0, 0)';
}
addExtraClass(firstChild, CLASSES.active);
return;
}
const keys = Object.keys(rendersRef.current).map(Number);
const prevActiveIndex = renderCount ? prevActiveKey : keys.indexOf(prevActiveKey);
const activeIndex = renderCount ? activeKey : keys.indexOf(activeKey);
const childNodes = Array.from(container.childNodes)
.filter((el) => !(el instanceof HTMLElement && el.classList.contains(CLASSES.afterSlides)));
if (!childNodes.length) {
return;
}
const childElements = (Array.from(container.children) as HTMLElement[])
.filter((el) => !el.classList.contains(CLASSES.afterSlides));
childElements.forEach((el) => {
addExtraClass(el, CLASSES.slide);
if (slideClassName) {
addExtraClass(el, slideClassName);
}
});
if (!activeKeyChanged) {
if (childElements.length === 1 || (nextKey !== undefined && childElements.length === 2)) {
const firstChild = childNodes[activeIndex] as HTMLElement;
if (name.startsWith('slide-optimized')) {
firstChild.style.transition = 'none';
firstChild.style.transform = 'translate3d(0, 0, 0)';
}
addExtraClass(firstChild, CLASSES.active);
}
if (!activeKeyChanged || !childNodes.length) {
return;
}
@ -137,10 +150,6 @@ const Transition: FC<TransitionProps> = ({
|| (direction === 'inverse' && prevActiveKey < activeKey)
);
const keys = Object.keys(rendersRef.current).map(Number);
const prevActiveIndex = renderCount ? prevActiveKey : keys.indexOf(prevActiveKey);
const activeIndex = renderCount ? activeKey : keys.indexOf(activeKey);
if (name === 'slide-optimized' || name === 'slide-optimized-rtl') {
performSlideOptimized(
animationLevel,
@ -243,6 +252,7 @@ const Transition: FC<TransitionProps> = ({
});
}, [
activeKey,
nextKey,
prevActiveKey,
activeKeyChanged,
direction,
@ -252,6 +262,7 @@ const Transition: FC<TransitionProps> = ({
renderCount,
shouldRestoreHeight,
shouldCleanup,
slideClassName,
cleanupExceptionKey,
animationLevel,
forceUpdate,
@ -307,7 +318,7 @@ const Transition: FC<TransitionProps> = ({
{contents}
</div>
);
};
}
export default Transition;

View File

@ -700,7 +700,18 @@ function updateClassName(element: HTMLElement, value: string) {
element.className = extraArray.join(' ');
}
export function addExtraClass(element: HTMLElement, className: string) {
export function addExtraClass(element: HTMLElement, className: string, forceSingle = false) {
if (!forceSingle) {
const classNames = className.split(' ');
if (className.length > 1) {
classNames.forEach((cn) => {
addExtraClass(element, cn, true);
});
return;
}
}
element.classList.add(className);
const classList = extraClasses.get(element);
@ -711,7 +722,18 @@ export function addExtraClass(element: HTMLElement, className: string) {
}
}
export function removeExtraClass(element: HTMLElement, className: string) {
export function removeExtraClass(element: HTMLElement, className: string, forceSingle = false) {
if (!forceSingle) {
const classNames = className.split(' ');
if (className.length > 1) {
classNames.forEach((cn) => {
removeExtraClass(element, cn, true);
});
return;
}
}
element.classList.remove(className);
const classList = extraClasses.get(element);
@ -724,7 +746,18 @@ export function removeExtraClass(element: HTMLElement, className: string) {
}
}
export function toggleExtraClass(element: HTMLElement, className: string, force?: boolean) {
export function toggleExtraClass(element: HTMLElement, className: string, force?: boolean, forceSingle = false) {
if (!forceSingle) {
const classNames = className.split(' ');
if (className.length > 1) {
classNames.forEach((cn) => {
toggleExtraClass(element, cn, force, true);
});
return;
}
}
element.classList.toggle(className, force);
if (element.classList.contains(className)) {