Skip to content

Commit

Permalink
feat(ui-kit): 토스트에 Align 기능 추가 (#36)
Browse files Browse the repository at this point in the history
  • Loading branch information
evan-moon authored Jan 26, 2021
1 parent 7677d5a commit 976ce6f
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 35 deletions.
17 changes: 14 additions & 3 deletions ui-kit/src/components/Toast/ToastBody.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,25 @@ import React from 'react';
import classnames from 'classnames';
import Text from 'components/Text';

type ToastTextAlign = 'left' | 'center' | 'right';

interface Props {
message: string;
textAlign: ToastTextAlign;
}

const ToastBody = ({ message }: Props) => {
const ToastBody = ({ message, textAlign = 'left' }: Props) => {
return (
<div className={classnames('lubycon-toast--inbox', 'lubycon-shadow--3')}>
<Text typography="p2">{message}</Text>
<div
className={classnames(
'lubycon-toast__body',
'lubycon-shadow--3',
`lubycon-toast__body--align-${textAlign}`
)}
>
<Text typography="p2" className="lubycon-toast__text">
{message}
</Text>
</div>
);
};
Expand Down
36 changes: 30 additions & 6 deletions ui-kit/src/components/Toast/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,37 @@ import React, { HTMLAttributes, useEffect, useState } from 'react';
import { animated, useTransition } from 'react-spring';
import classnames from 'classnames';
import ToastBody from './ToastBody';
import { useMemo } from 'react';

export type ToastAlign = 'left' | 'center' | 'right';

const getTranslateAnimation = (align: ToastAlign) => {
switch (align) {
case 'left':
return {
from: 'translateX(-100%)',
to: 'translateX(0)',
};
case 'center':
return {
from: 'translateY(100%)',
to: 'translateY(0)',
};
case 'right':
return {
from: 'translateX(100%)',
to: 'translateX(0)',
};
}
};

export interface ToastProps extends Omit<HTMLAttributes<HTMLDivElement>, 'children'> {
show: boolean;
message: string;
autoHideDuration?: number;
onShow?: () => void;
onHide?: () => void;
align?: ToastAlign;
}
const Toast = ({
show,
Expand All @@ -18,27 +42,29 @@ const Toast = ({
onHide,
className,
style,
align = 'left',
...rest
}: ToastProps) => {
const [isOpen, setOpen] = useState(show);
const translateAnimation = useMemo(() => getTranslateAnimation(align), [align]);

const transition = useTransition(isOpen, null, {
from: {
opacity: 0,
transform: 'translateX(-100%)',
transform: translateAnimation.from,
height: 60,
},
enter: [
{ height: 60 },
{
opacity: 1,
transform: 'translateX(0)',
transform: translateAnimation.to,
},
],
leave: [
{
opacity: 0,
transform: 'translateX(-100%)',
transform: translateAnimation.from,
},
{ height: 0 },
],
Expand Down Expand Up @@ -74,9 +100,7 @@ const Toast = ({
}}
{...rest}
>
<div>
<ToastBody message={message} />
</div>
<ToastBody message={message} textAlign={align} />
</animated.div>
) : null;
})}
Expand Down
50 changes: 31 additions & 19 deletions ui-kit/src/contexts/Toast.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import React, { ReactNode, createContext, useState, useCallback, useContext } from 'react';
import classnames from 'classnames';
import Toast, { ToastProps } from 'components/Toast';
import Toast, { ToastAlign, ToastProps } from 'components/Toast';
import { generateID } from 'src/utils';
import { Portal } from './Portal';

interface ToastOptions extends Omit<ToastProps, 'show'> {
duration?: number;
align?: ToastAlign;
}
const aligns: ToastAlign[] = ['left', 'center', 'right'];

interface ToastGlobalState {
openToast: (option: ToastOptions) => void;
closeToast: (toastId: string) => void;
Expand All @@ -24,9 +26,8 @@ export function ToastProvider({ children, maxStack = 3 }: ToastProviderProps) {
const [openedToastsQueue, setOpenedToastsQueue] = useState<ToastOptions[]>([]);

const openToast = useCallback(
(option: ToastOptions) => {
const id = option.id ?? generateID('lubycon-toast');
const toast = { id, ...option };
({ id = generateID('lubycon-toast'), align = 'left', ...option }: ToastOptions) => {
const toast = { id, align, ...option };
const [, ...rest] = openedToastsQueue;

if (openedToastsQueue.length >= maxStack) {
Expand Down Expand Up @@ -54,20 +55,31 @@ export function ToastProvider({ children, maxStack = 3 }: ToastProviderProps) {
>
{children}
<Portal>
<div className={classnames('lubycon-toast--context-container')}>
{openedToastsQueue.map(({ id, onHide, duration = 3000, ...toastProps }) => (
<Toast
key={id}
show={true}
autoHideDuration={duration}
onHide={() => {
closeToast(id ?? '');
onHide?.();
}}
{...toastProps}
/>
))}
</div>
{aligns.map((align) => (
<div
key={align}
className={classnames(
'lubycon-toast__context-container',
`lubycon-toast__context-container--align-${align}`
)}
>
{openedToastsQueue
.filter((toast) => toast.align === align)
.map(({ id, align, onHide, duration = 3000, ...toastProps }) => (
<Toast
key={id}
show={true}
align={align}
autoHideDuration={duration}
onHide={() => {
closeToast(id ?? '');
onHide?.();
}}
{...toastProps}
/>
))}
</div>
))}
</Portal>
</ToastContext.Provider>
);
Expand Down
41 changes: 34 additions & 7 deletions ui-kit/src/sass/components/_Toast.scss
Original file line number Diff line number Diff line change
@@ -1,32 +1,59 @@
.lubycon-toast {
overflow: visible;

.lubycon-toast--inbox {
.lubycon-toast__body {
display: inline-block;
padding: 8px 16px;
min-width: 336px;
border-radius: 4px;
background-color: white;
margin: 12px 0;
&--align-left {
text-align: left;
}
&--align-center {
text-align: center;
min-width: auto;
}
&--align-right {
text-align: right;
}
}

.lubycon-text {
.lubycon-toast__text {
white-space: pre;
}

&:first-of-type {
.lubycon-toast--inbox {
.lubycon-toast__body {
margin-bottom: 0;
}
}
}

.lubycon-toast--context-container {
display: flex;
%context-container {
position: fixed;
display: flex;
flex-direction: column-reverse;
top: auto;
right: auto;
bottom: 40px;
left: 40px;
}

.lubycon-toast__context-container {
&--align-left {
@extend %context-container;
left: 40px;
right: auto;
}
&--align-center {
@extend %context-container;
left: 50%;
transform: translateX(-50%);
right: auto;
}
&--align-right {
@extend %context-container;
left: auto;
right: 40px;
}
}
37 changes: 37 additions & 0 deletions ui-kit/src/stories/Toast.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,40 @@ export const ToastHooks = () => {
</div>
);
};

export const Align = () => {
const { openToast } = useToast();
return (
<div>
<Button
onClick={() =>
openToast({
message: `데이터 전송이 완료되었습니다`,
})
}
>
Left
</Button>
<Button
onClick={() =>
openToast({
message: `데이터 전송이 완료되었습니다`,
align: 'center',
})
}
>
Center
</Button>
<Button
onClick={() =>
openToast({
message: `데이터 전송이 완료되었습니다`,
align: 'right',
})
}
>
Right
</Button>
</div>
);
};

0 comments on commit 976ce6f

Please sign in to comment.