Skip to content

Commit

Permalink
fix(sheet): sheet animation
Browse files Browse the repository at this point in the history
  • Loading branch information
BQXBQX committed Mar 30, 2024
1 parent f2d7684 commit d124864
Show file tree
Hide file tree
Showing 6 changed files with 201 additions and 130 deletions.
3 changes: 1 addition & 2 deletions packages/ui-react/lib/Sheet/Sheet.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ export const ShowSheet = () => {
onCancel={() => setVisible(false)}
/>
</>

);
);
};

<ShowSheet />
142 changes: 80 additions & 62 deletions packages/ui-react/lib/Sheet/Sheet.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,71 +9,96 @@ $padding-left-right-distance: 20px;
animation-fill-mode: forwards;
}

.base {
@property --blur {
syntax: '<length>';
inherits: false;
initial-value: 0px;
}

@property --opacity-background {
syntax: '<percentage>';
inherits: false;
initial-value: 0%;
}

@property --opacity-sheet {
syntax: '<percentage>';
inherits: false;
initial-value: 0%;
}

@property --slide {
syntax: '<percentage>';
inherits: false;
initial-value: 0%;
}

@mixin sheet-animation() {
&.sheet-in {
@include animation(sheet-in);
}
&.sheet-hide {
@include animation(sheet-hide);
}
}

.sheet-container {
height: 100vh;
width: 100vw;
position: fixed;
left: 0;
top: 0;
z-index: 2;
z-index: 1;
box-sizing: border-box;
background-color: $background-shadow-color;
&.showAnimation {
@include animation(showShadow);
}
&.hideAnimation {
@include animation(hideShadow);
&.mask {
backdrop-filter: blur(var(--blur));
background-color: rgb($black-color, var(--opacity-background));
}
.sheetContent {
@include sheet-animation();
.sheet {
top: 0;
height: 100vh;
background-color: var(--white-color);
background-color: $white-color;
position: absolute;
z-index: 3;
z-index: 2;
box-sizing: border-box;
opacity: 1;
right: 0;
padding: $padding-left-right-distance;
opacity: 1;
&.showAnimation {
@include animation(showSlideSheet);
}
&.hideAnimation {
@include animation(hideSlideSheet);
transform: translateX(var(--slide));
opacity: var(--opacity-sheet);
@include sheet-animation();
display: flex;
flex-direction: column;
&.left {
left: 0;
transform: translateX(calc(-1 * var(--slide)));
}
.sheetMainContent {
padding: 10px 0;
overflow-y: scroll;
display: flex;
position: relative;
height: calc(100vh - 32px - 60px);
top: 30px;
flex-grow: 1;
margin-top: 10px;
}
.sheetFooter {
height: 50px;
position: absolute;
bottom: 20px;
width: -webkit-fill-available;
padding-right: $padding-left-right-distance;
text-align: end;
background-color: var(--white-color);
background-color: $white-color;
z-index: 1;
}
.sheet-header {
height: 32px;
background-color: var(--white-color);
position: absolute;
display: flex;
width: -webkit-fill-available;
padding-right: 20px;
flex-direction: column;
background-color: $white-color;
width: 100%;
.sheet-header-content {
display: flex;
width: 100%;
align-items: center;
justify-content: space-between;
flex-direction: row;
span {
font-size: 16px;
font-weight: 700;
font-weight: bolder;
white-space: nowrap;
}
.svg-container {
Expand Down Expand Up @@ -109,39 +134,32 @@ $padding-left-right-distance: 20px;
}
}
}

@keyframes showShadow {
from {
background-color: rgb(var(--black-color-rgb), 0);
}
to {
background-color: $background-shadow-color;
}
}

@keyframes hideShadow {
from {
background-color: $background-shadow-color;
@keyframes sheet-in {
0% {
--blur: 0px;
--opacity-background: 0%;
--slide: 100%;
--opacity-sheet: 0%;
}
to {
background-color: rgb(var(--black-color-rgb), 0);
100% {
--blur: 4px;
--opacity-background: 40%;
--slide: 0%;
--opacity-sheet: 100%;
}
}

@keyframes showSlideSheet {
from {
right: -30%;
}
to {
right: 0;
}
}

@keyframes hideSlideSheet {
from {
right: 0;
@keyframes sheet-hide {
0% {
--blur: 4px;
--opacity-background: 40%;
--slide: 0%;
--opacity-sheet: 100%;
}
to {
right: -30%;
100% {
--blur: 0px;
--opacity-background: 0%;
--slide: 100%;
--opacity-sheet: 0%;
}
}
147 changes: 91 additions & 56 deletions packages/ui-react/lib/Sheet/Sheet.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import classnames from 'classnames';
import React, { useEffect, useState } from 'react';
import React, { useEffect, useState, type CSSProperties } from 'react';
import styles from './Sheet.module.scss';
// import SheetTrigger from './SheetTrigger';
import { SheetHeader } from './SheetHeader';
import { SheetFooter } from './SheetFooter';
import { useWrapperVisibleStore } from './useWrapperVisibleStore';
import { createPortal } from 'react-dom';

export interface SheetProps extends React.HtmlHTMLAttributes<HTMLDivElement> {
/**
Expand All @@ -31,70 +31,105 @@ export interface SheetProps extends React.HtmlHTMLAttributes<HTMLDivElement> {
* width, the width of the sheet
*/
width?: number;
/**
* classname , the classname of the sidesheet
*/
className?: string;
/**
* mask, Whether to display the mask
*/
mask?: boolean;
/**
* Whether or not to allow closing the dialog by clicking on the mask
*/
maskClosable?: boolean;
/**
* the style of the mask
*/
maskStyle?: CSSProperties;
/**
* placement : left|right
*/
placement?: 'left' | 'right';
}

export const Sheet = React.forwardRef<HTMLDivElement, SheetProps>(
({ visible, onCancel, sheetTitle, sheetFooter, mainContent, width = 500, ...rest }, ref) => {
const [innerVisible, setInnerVisible] = useState<boolean>(false);
const [isShowAnimation, setIsShowAnimation] = useState<boolean>(false);
const [isHideAnimation, setIsHideAnimation] = useState<boolean>(false);
(
{
visible,
onCancel,
sheetTitle,
sheetFooter,
mainContent,
width = 500,
className,
maskClosable = true,
mask = true,
maskStyle,
placement = 'right',
...rest
},
ref,
) => {
const [sheetVisible, setSheetVisible] = useState<boolean>(false);
const [sheetIn, setSheetIn] = useState<boolean>(false);
const [sheetHide, setSheetHide] = useState<boolean>(false);
const [open, close] = useWrapperVisibleStore((state) => [state.open, state.close]);

const stopPropagation = (e: React.MouseEvent<HTMLDivElement>) => {
e.stopPropagation();
};

useEffect(() => {
if (visible) {
setInnerVisible(true);
setIsShowAnimation(true);
open();
document.body.style.overflow = 'hidden';
setTimeout(() => {
setIsShowAnimation(false);
}, 400);
}
if (!visible) {
setIsHideAnimation(true);
close();
setTimeout(() => {
setIsHideAnimation(false);
setInnerVisible(false);
document.body.style.overflow = '';
}, 400);
}
}, [visible, open, close]);
visible ? openSheet() : closeSheet();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [visible]);

const sheetClass = classnames(
`${styles['base']}
${styles[isShowAnimation ? 'showAnimation' : '']}
${styles[isHideAnimation ? 'hideAnimation' : '']}`,
);
const closeSheet = () => {
setSheetIn(false);
setSheetHide(true);
close();
setTimeout(() => {
setSheetHide(false);
setSheetVisible(false);
document.body.style.overflow = '';
}, 400);
};

const openSheet = () => {
setSheetVisible(true);
setSheetIn(true);
open();
document.body.style.overflow = 'hidden';
};

return (
<>
{innerVisible && (
<div
className={sheetClass}
onMouseDown={onCancel}
ref={ref}
{...rest}
>
<div
style={{ width: `${width}px` }}
className={`${styles['sheetContent']}
${styles[isShowAnimation ? 'showAnimation' : '']}
${styles[isHideAnimation ? 'hideAnimation' : '']}`}
onMouseDown={stopPropagation}
>
<SheetHeader
onCancel={onCancel}
content={sheetTitle}
></SheetHeader>
<div className={styles['sheetMainContent']}>{mainContent}</div>
<SheetFooter>{sheetFooter}</SheetFooter>
</div>
</div>
{createPortal(
<div>
{sheetVisible && (
<div
className={`${styles['sheet-container']} ${styles[sheetIn ? 'sheet-in' : '']}
${styles[sheetHide ? 'sheet-hide' : '']} ${styles[mask ? 'mask' : 'no-mask']}`}
style={maskStyle}
onMouseDown={() => maskClosable && onCancel && onCancel()}
ref={ref}
{...rest}
>
<div
style={{ width: `${width}px` }}
className={`${styles['sheet']}
${styles[sheetIn ? 'sheet-in' : '']}
${styles[sheetHide ? 'sheet-hide' : '']} ${className} ${styles[placement === 'left' ? 'left' : '']}`}
onMouseDown={(e) => e.stopPropagation()}
>
<SheetHeader
onCancel={onCancel}
content={sheetTitle}
></SheetHeader>
<div className={styles['sheetMainContent']}>{mainContent}</div>
<SheetFooter onCancel={onCancel}>{sheetFooter}</SheetFooter>
</div>
</div>
)}
</div>,
document.body,
)}
</>
);
Expand Down
Loading

0 comments on commit d124864

Please sign in to comment.