signal-desktop/ts/hooks/useAnimated.tsx

93 lines
2 KiB
TypeScript
Raw Normal View History

// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
2022-09-27 20:24:21 +00:00
import { useState, useCallback } from 'react';
import type { SpringValues } from '@react-spring/web';
import { useChain, useSpring, useSpringRef } from '@react-spring/web';
2021-10-14 16:52:42 +00:00
export type ModalConfigType = {
opacity: number;
transform?: string;
marginTop?: string;
2021-10-14 16:52:42 +00:00
};
enum ModalState {
Opening = 'Opening',
Open = 'Open',
Closing = 'Closing',
Closed = 'Closed',
}
2021-10-14 16:52:42 +00:00
export function useAnimated(
onClose: () => unknown,
{
getFrom,
getTo,
}: {
getFrom: (isOpen: boolean) => ModalConfigType;
getTo: (isOpen: boolean) => ModalConfigType;
}
): {
close: () => unknown;
isClosed: boolean;
2021-10-14 16:52:42 +00:00
modalStyles: SpringValues<ModalConfigType>;
overlayStyles: SpringValues<ModalConfigType>;
} {
const [state, setState] = useState(ModalState.Opening);
const shouldShowModal =
state === ModalState.Open || state === ModalState.Opening;
const isClosed = state === ModalState.Closed;
2021-10-14 16:52:42 +00:00
const modalRef = useSpringRef();
const modalStyles = useSpring({
from: getFrom(shouldShowModal),
to: getTo(shouldShowModal),
2021-10-14 16:52:42 +00:00
onRest: () => {
if (state === ModalState.Closing) {
setState(ModalState.Closed);
2021-10-14 16:52:42 +00:00
onClose();
} else if (state === ModalState.Opening) {
setState(ModalState.Open);
2021-10-14 16:52:42 +00:00
}
},
config: {
clamp: true,
friction: 20,
mass: 0.5,
tension: 350,
},
2021-10-14 16:52:42 +00:00
ref: modalRef,
});
const overlayRef = useSpringRef();
const overlayStyles = useSpring({
from: { opacity: 0 },
to: { opacity: shouldShowModal ? 1 : 0 },
config: {
2021-10-14 16:52:42 +00:00
clamp: true,
friction: 22,
tension: 360,
},
2021-10-14 16:52:42 +00:00
ref: overlayRef,
});
useChain(shouldShowModal ? [overlayRef, modalRef] : [modalRef, overlayRef]);
const close = useCallback(() => {
setState(currentState => {
if (currentState === ModalState.Open) {
return ModalState.Closing;
}
return currentState;
});
}, []);
2021-10-14 16:52:42 +00:00
return {
2022-09-27 20:24:21 +00:00
close,
isClosed,
2021-10-14 16:52:42 +00:00
overlayStyles,
modalStyles,
};
}