@uniai-fe/uds-primitives 0.5.6 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -4
- package/dist/styles.css +237 -16
- package/package.json +1 -1
- package/src/components/alternate/{markup/index.tsx → Alternate.tsx} +7 -4
- package/src/components/alternate/index.tsx +2 -1
- package/src/components/alternate/layout/Button.tsx +29 -0
- package/src/components/alternate/layout/Container.tsx +24 -0
- package/src/components/alternate/layout/Contents.tsx +23 -0
- package/src/components/alternate/layout/Figure.tsx +24 -0
- package/src/components/alternate/layout/Layout.tsx +27 -0
- package/src/components/alternate/layout/TextButton.tsx +50 -0
- package/src/components/alternate/layout/Title.tsx +25 -0
- package/src/components/alternate/layout/index.tsx +1 -0
- package/src/components/alternate/styles/index.scss +3 -1
- package/src/components/alternate/styles/layout.scss +63 -0
- package/src/components/alternate/styles/{alternate.scss → unit.scss} +16 -16
- package/src/components/alternate/styles/variables.scss +30 -0
- package/src/components/alternate/types/index.ts +2 -77
- package/src/components/alternate/types/layout.ts +126 -0
- package/src/components/alternate/types/unit.ts +77 -0
- package/src/components/alternate/{markup → unit}/empty/Data.tsx +1 -1
- package/src/components/alternate/{markup → unit}/loading/Default.tsx +1 -1
- package/src/components/toast/img/error.svg +6 -0
- package/src/components/toast/img/success.svg +5 -0
- package/src/components/toast/img/warning.svg +5 -0
- package/src/components/toast/index.scss +1 -0
- package/src/components/toast/index.tsx +11 -0
- package/src/components/toast/markup/Host.tsx +74 -0
- package/src/components/toast/markup/Icon.tsx +15 -0
- package/src/components/toast/markup/Item.tsx +100 -0
- package/src/components/toast/markup/Text.tsx +21 -0
- package/src/components/toast/markup/index.tsx +16 -0
- package/src/components/toast/styles/index.scss +2 -0
- package/src/components/toast/styles/toast.scss +113 -0
- package/src/components/toast/styles/variables.scss +24 -0
- package/src/components/toast/types/index.ts +1 -0
- package/src/components/toast/types/internal.ts +71 -0
- package/src/components/toast/types/props.ts +128 -0
- package/src/index.scss +1 -0
- package/src/index.tsx +1 -0
- /package/src/components/alternate/{markup/Label.tsx → unit/Text.tsx} +0 -0
- /package/src/components/alternate/{markup → unit}/loading/Icon.tsx +0 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import clsx from "clsx";
|
|
2
|
+
import { createElement, forwardRef, useEffect, useState } from "react";
|
|
3
|
+
|
|
4
|
+
import type { ToastItemProps } from "../types";
|
|
5
|
+
import type { ToastItemStyle } from "../types/internal";
|
|
6
|
+
import { ToastIcon } from "./Icon";
|
|
7
|
+
import { ToastText } from "./Text";
|
|
8
|
+
|
|
9
|
+
const TOAST_TRANSITION_MS = 600;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Toast Item; 개별 Toast 메시지 렌더러
|
|
13
|
+
* @component
|
|
14
|
+
* @param {ToastItemProps} props
|
|
15
|
+
* @param {string} props.toastKey 트리거 지점을 드러내는 semantic key
|
|
16
|
+
* @param {number} props.duration 자동 닫힘까지의 시간(ms)
|
|
17
|
+
* @param {"standard" | "success" | "warning" | "error"} props.state Toast 피드백 성격
|
|
18
|
+
* @param {React.ReactNode} props.message 한 줄 메시지 콘텐츠
|
|
19
|
+
* @param {React.ReactNode} [props.description] 선택 보조 콘텐츠
|
|
20
|
+
* @param {(toastKey: string) => void} props.onClose 닫힘 요청 핸들러
|
|
21
|
+
* @example
|
|
22
|
+
* <Toast.Item toastKey="save-success" duration={3000} state="success" message="저장되었습니다." onClose={onClose} />
|
|
23
|
+
*/
|
|
24
|
+
const ToastItem = forwardRef<HTMLElementTagNameMap["section"], ToastItemProps>(
|
|
25
|
+
(
|
|
26
|
+
{
|
|
27
|
+
toastKey,
|
|
28
|
+
duration,
|
|
29
|
+
state,
|
|
30
|
+
message,
|
|
31
|
+
description,
|
|
32
|
+
onClose,
|
|
33
|
+
className,
|
|
34
|
+
role,
|
|
35
|
+
style,
|
|
36
|
+
...restProps
|
|
37
|
+
},
|
|
38
|
+
ref,
|
|
39
|
+
) => {
|
|
40
|
+
const [isVisible, setIsVisible] = useState(false);
|
|
41
|
+
const toastStyle: ToastItemStyle = {
|
|
42
|
+
...style,
|
|
43
|
+
"--toast-transition-duration": `${TOAST_TRANSITION_MS}ms`,
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
// 변경: mount 직후 open phase를 분리해 enter transition이 실제 렌더 프레임에서 실행되게 한다.
|
|
48
|
+
const enterFrameId = window.requestAnimationFrame(() => {
|
|
49
|
+
setIsVisible(true);
|
|
50
|
+
});
|
|
51
|
+
let exitTimerId: number | undefined;
|
|
52
|
+
|
|
53
|
+
// 변경: duration 만료 후 즉시 제거하지 않고 closed phase를 거쳐 exit transition을 보장한다.
|
|
54
|
+
const closeTimerId = window.setTimeout(() => {
|
|
55
|
+
setIsVisible(false);
|
|
56
|
+
exitTimerId = window.setTimeout(() => {
|
|
57
|
+
onClose(toastKey);
|
|
58
|
+
}, TOAST_TRANSITION_MS);
|
|
59
|
+
}, duration);
|
|
60
|
+
|
|
61
|
+
return () => {
|
|
62
|
+
window.cancelAnimationFrame(enterFrameId);
|
|
63
|
+
window.clearTimeout(closeTimerId);
|
|
64
|
+
if (typeof exitTimerId === "number") {
|
|
65
|
+
window.clearTimeout(exitTimerId);
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
}, [duration, onClose, toastKey]);
|
|
69
|
+
|
|
70
|
+
return (
|
|
71
|
+
<section
|
|
72
|
+
{...restProps}
|
|
73
|
+
ref={ref}
|
|
74
|
+
className={clsx("toast", className)}
|
|
75
|
+
data-phase={isVisible ? "open" : "closed"}
|
|
76
|
+
data-state={state}
|
|
77
|
+
data-toast-key={toastKey}
|
|
78
|
+
role={role ?? "status"}
|
|
79
|
+
aria-live="polite"
|
|
80
|
+
style={toastStyle}
|
|
81
|
+
>
|
|
82
|
+
{state === "standard" ? null : (
|
|
83
|
+
<figure className="toast-icon" aria-hidden="true">
|
|
84
|
+
{createElement(ToastIcon[state])}
|
|
85
|
+
</figure>
|
|
86
|
+
)}
|
|
87
|
+
<div className="toast-content">
|
|
88
|
+
<ToastText>{message}</ToastText>
|
|
89
|
+
{description ? (
|
|
90
|
+
<ToastText className="toast-description">{description}</ToastText>
|
|
91
|
+
) : null}
|
|
92
|
+
</div>
|
|
93
|
+
</section>
|
|
94
|
+
);
|
|
95
|
+
},
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
ToastItem.displayName = "Toast.Item";
|
|
99
|
+
|
|
100
|
+
export { ToastItem };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import clsx from "clsx";
|
|
2
|
+
import { Slot } from "../../slot";
|
|
3
|
+
import type { ToastTextProps } from "../types/internal";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Toast Text; Toast 텍스트 className 계약을 고정하는 전용 마크업
|
|
7
|
+
* @component
|
|
8
|
+
* @param {object} props
|
|
9
|
+
* @param {React.ReactNode} [props.children] 문자열/숫자는 p 태그로 감싸고, ReactNode는 그대로 렌더링한다.
|
|
10
|
+
* @param {string} [props.className] 텍스트 className
|
|
11
|
+
* @example
|
|
12
|
+
* <ToastText>저장되었습니다.</ToastText>
|
|
13
|
+
*/
|
|
14
|
+
export function ToastText({ children, className }: ToastTextProps) {
|
|
15
|
+
// 변경: Toast 메시지 텍스트는 Slot.Text로 위임해 string | number 래핑 규칙을 유지한다.
|
|
16
|
+
return (
|
|
17
|
+
<Slot.Text as="p" className={clsx("toast-text", className)}>
|
|
18
|
+
{children}
|
|
19
|
+
</Slot.Text>
|
|
20
|
+
);
|
|
21
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { ToastHost } from "./Host";
|
|
2
|
+
import { ToastItem } from "./Item";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Toast; semantic feedback toast namespace
|
|
6
|
+
* @desc
|
|
7
|
+
* - `Toast.Host`: item data를 x/y/margin별 stack으로 렌더링한다.
|
|
8
|
+
* - `Toast.Item`: 개별 toast content와 timer close를 담당한다.
|
|
9
|
+
*/
|
|
10
|
+
export const Toast = {
|
|
11
|
+
Host: ToastHost,
|
|
12
|
+
Item: ToastItem,
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export { ToastHost, ToastItem };
|
|
16
|
+
export * from "./Icon";
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
.toast-stack {
|
|
2
|
+
--toast-stack-translate-x: 0;
|
|
3
|
+
--toast-stack-translate-y: 0;
|
|
4
|
+
position: fixed;
|
|
5
|
+
z-index: var(--toast-stack-z-index);
|
|
6
|
+
display: flex;
|
|
7
|
+
flex-direction: column;
|
|
8
|
+
gap: var(--toast-stack-gap);
|
|
9
|
+
pointer-events: none;
|
|
10
|
+
transform: translate(
|
|
11
|
+
var(--toast-stack-translate-x),
|
|
12
|
+
var(--toast-stack-translate-y)
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.toast-stack:where([data-x="left"]) {
|
|
17
|
+
left: var(--toast-stack-margin);
|
|
18
|
+
--toast-transition-x: calc(var(--toast-transition-distance) * -1);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.toast-stack:where([data-x="center"]) {
|
|
22
|
+
left: 50%;
|
|
23
|
+
--toast-stack-translate-x: -50%;
|
|
24
|
+
--toast-transition-distance: -80%;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.toast-stack:where([data-x="right"]) {
|
|
28
|
+
right: var(--toast-stack-margin);
|
|
29
|
+
--toast-transition-x: var(--toast-transition-distance);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.toast-stack:where([data-y="top"]) {
|
|
33
|
+
top: var(--toast-stack-margin);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.toast-stack:where([data-y="center"]) {
|
|
37
|
+
top: 50%;
|
|
38
|
+
--toast-stack-translate-y: -50%;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.toast-stack:where([data-y="bottom"]) {
|
|
42
|
+
bottom: var(--toast-stack-margin);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.toast-stack:where([data-x="center"][data-y="top"]) {
|
|
46
|
+
--toast-transition-y: calc(var(--toast-transition-distance) * -1);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.toast-stack:where([data-x="center"][data-y="bottom"]) {
|
|
50
|
+
--toast-transition-y: var(--toast-transition-distance);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.toast {
|
|
54
|
+
display: flex;
|
|
55
|
+
align-items: center;
|
|
56
|
+
width: min(var(--toast-width), calc(100vw - (var(--toast-stack-margin) * 2)));
|
|
57
|
+
box-sizing: border-box;
|
|
58
|
+
gap: var(--toast-gap);
|
|
59
|
+
overflow: hidden;
|
|
60
|
+
padding: var(--toast-padding-block) var(--toast-padding-inline);
|
|
61
|
+
border-radius: var(--toast-radius);
|
|
62
|
+
background-color: var(--toast-background-color);
|
|
63
|
+
opacity: 0;
|
|
64
|
+
pointer-events: auto;
|
|
65
|
+
transform: translate(var(--toast-transition-x), var(--toast-transition-y));
|
|
66
|
+
transition:
|
|
67
|
+
opacity var(--toast-transition-duration) var(--toast-transition-easing),
|
|
68
|
+
transform var(--toast-transition-duration) var(--toast-transition-easing);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.toast:where([data-phase="open"]) {
|
|
72
|
+
opacity: 1;
|
|
73
|
+
transform: translateY(0);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.toast-icon {
|
|
77
|
+
display: flex;
|
|
78
|
+
align-items: center;
|
|
79
|
+
justify-content: center;
|
|
80
|
+
flex-shrink: 0;
|
|
81
|
+
width: var(--toast-icon-size);
|
|
82
|
+
height: var(--toast-icon-size);
|
|
83
|
+
margin: 0;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.toast-icon svg {
|
|
87
|
+
display: block;
|
|
88
|
+
width: 100%;
|
|
89
|
+
height: 100%;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.toast-content {
|
|
93
|
+
display: flex;
|
|
94
|
+
flex: 1;
|
|
95
|
+
min-width: 0;
|
|
96
|
+
flex-direction: column;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.toast-text {
|
|
100
|
+
overflow: hidden;
|
|
101
|
+
margin: 0;
|
|
102
|
+
color: var(--toast-foreground-color);
|
|
103
|
+
font-size: var(--toast-message-font-size);
|
|
104
|
+
line-height: var(--toast-message-line-height);
|
|
105
|
+
letter-spacing: var(--toast-message-letter-spacing);
|
|
106
|
+
font-weight: var(--toast-message-font-weight);
|
|
107
|
+
text-overflow: ellipsis;
|
|
108
|
+
white-space: nowrap;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.toast-description {
|
|
112
|
+
opacity: 0.82;
|
|
113
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
--toast-stack-margin: var(--spacing-padding-7);
|
|
3
|
+
--toast-stack-gap: var(--spacing-gap-3);
|
|
4
|
+
--toast-stack-z-index: 10000;
|
|
5
|
+
|
|
6
|
+
--toast-width: 361px;
|
|
7
|
+
--toast-background-color: var(--color-surface-heavy);
|
|
8
|
+
--toast-foreground-color: var(--color-common-100);
|
|
9
|
+
--toast-radius: var(--theme-radius-large-1);
|
|
10
|
+
--toast-padding-block: var(--spacing-padding-5);
|
|
11
|
+
--toast-padding-inline: var(--spacing-padding-7);
|
|
12
|
+
--toast-gap: var(--spacing-gap-5);
|
|
13
|
+
--toast-icon-size: 24px;
|
|
14
|
+
--toast-transition-duration: 0.6s;
|
|
15
|
+
--toast-transition-easing: cubic-bezier(0.16, 1, 0.3, 1);
|
|
16
|
+
--toast-transition-distance: -24%;
|
|
17
|
+
--toast-transition-x: 0;
|
|
18
|
+
--toast-transition-y: 0;
|
|
19
|
+
|
|
20
|
+
--toast-message-font-size: var(--font-body-xsmall-size);
|
|
21
|
+
--toast-message-line-height: var(--font-body-xsmall-line-height);
|
|
22
|
+
--toast-message-letter-spacing: var(--font-body-xsmall-letter-spacing);
|
|
23
|
+
--toast-message-font-weight: var(--font-body-xsmall-weight);
|
|
24
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type * from "./props";
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { CSSProperties, ReactNode } from "react";
|
|
2
|
+
import type { ToastHorizontal, ToastItemData, ToastVertical } from "./props";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Toast text props; Toast 메시지 텍스트 렌더링 props
|
|
6
|
+
* @property {ReactNode} [children] 문자열/숫자는 p 태그로 감싸고, ReactNode는 그대로 렌더링한다.
|
|
7
|
+
* @property {string} [className] 텍스트 className
|
|
8
|
+
*/
|
|
9
|
+
export interface ToastTextProps {
|
|
10
|
+
/**
|
|
11
|
+
* 문자열/숫자는 p 태그로 감싸고, ReactNode는 그대로 렌더링한다.
|
|
12
|
+
*/
|
|
13
|
+
children?: ReactNode;
|
|
14
|
+
/**
|
|
15
|
+
* 텍스트 className
|
|
16
|
+
*/
|
|
17
|
+
className?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Toast stack group; Host 내부 placement bucket
|
|
22
|
+
* @property {string} stackKey x/y/margin 조합으로 만든 stack key
|
|
23
|
+
* @property {"left" | "center" | "right"} x Toast stack 가로 위치
|
|
24
|
+
* @property {"top" | "center" | "bottom"} y Toast stack 세로 위치
|
|
25
|
+
* @property {number | string} margin page frame 기준 위치 간격
|
|
26
|
+
* @property {ToastItemData[]} items 같은 위치에 stack될 Toast 목록
|
|
27
|
+
*/
|
|
28
|
+
export interface ToastStackGroup {
|
|
29
|
+
/**
|
|
30
|
+
* x/y/margin 조합으로 만든 stack key
|
|
31
|
+
*/
|
|
32
|
+
stackKey: string;
|
|
33
|
+
/**
|
|
34
|
+
* Toast stack 가로 위치
|
|
35
|
+
*/
|
|
36
|
+
x: ToastHorizontal;
|
|
37
|
+
/**
|
|
38
|
+
* Toast stack 세로 위치
|
|
39
|
+
*/
|
|
40
|
+
y: ToastVertical;
|
|
41
|
+
/**
|
|
42
|
+
* page frame 기준 위치 간격
|
|
43
|
+
*/
|
|
44
|
+
margin: number | string;
|
|
45
|
+
/**
|
|
46
|
+
* 같은 위치에 stack될 Toast 목록
|
|
47
|
+
*/
|
|
48
|
+
items: ToastItemData[];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Toast stack style; 런타임 margin CSS 변수 주입 타입
|
|
53
|
+
* @property {string} --toast-stack-margin page frame 기준 위치 간격 CSS 값
|
|
54
|
+
*/
|
|
55
|
+
export interface ToastStackStyle extends CSSProperties {
|
|
56
|
+
/**
|
|
57
|
+
* page frame 기준 위치 간격 CSS 값
|
|
58
|
+
*/
|
|
59
|
+
["--toast-stack-margin"]: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Toast item style; transition duration CSS 변수 주입 타입
|
|
64
|
+
* @property {string} --toast-transition-duration Toast enter/exit transition 시간 CSS 값
|
|
65
|
+
*/
|
|
66
|
+
export interface ToastItemStyle extends CSSProperties {
|
|
67
|
+
/**
|
|
68
|
+
* Toast enter/exit transition 시간 CSS 값
|
|
69
|
+
*/
|
|
70
|
+
["--toast-transition-duration"]: string;
|
|
71
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import type { ComponentPropsWithoutRef, ReactNode } from "react";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Toast state; Toast 피드백 성격 축
|
|
5
|
+
* @typedef {"standard" | "success" | "warning" | "error"} ToastState
|
|
6
|
+
*/
|
|
7
|
+
export type ToastState = "standard" | "success" | "warning" | "error";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Toast horizontal position; Toast stack 가로 위치 축
|
|
11
|
+
* @typedef {"left" | "center" | "right"} ToastHorizontal
|
|
12
|
+
*/
|
|
13
|
+
export type ToastHorizontal = "left" | "center" | "right";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Toast vertical position; Toast stack 세로 위치 축
|
|
17
|
+
* @typedef {"top" | "center" | "bottom"} ToastVertical
|
|
18
|
+
*/
|
|
19
|
+
export type ToastVertical = "top" | "center" | "bottom";
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Toast item data; 트리거 로직이 생성하는 Toast 렌더링 데이터
|
|
23
|
+
* @property {string} toastKey 트리거 지점을 드러내는 semantic key
|
|
24
|
+
* @property {"left" | "center" | "right"} x Toast stack 가로 위치
|
|
25
|
+
* @property {"top" | "center" | "bottom"} y Toast stack 세로 위치
|
|
26
|
+
* @property {number | string} margin page frame 기준 위치 간격
|
|
27
|
+
* @property {number} duration 자동 닫힘까지의 시간(ms)
|
|
28
|
+
* @property {"standard" | "success" | "warning" | "error"} state Toast 피드백 성격
|
|
29
|
+
* @property {ReactNode} message 한 줄 메시지 콘텐츠
|
|
30
|
+
* @property {ReactNode} [description] 선택 보조 콘텐츠
|
|
31
|
+
*/
|
|
32
|
+
export interface ToastItemData {
|
|
33
|
+
/**
|
|
34
|
+
* 트리거 지점을 드러내는 semantic key
|
|
35
|
+
*/
|
|
36
|
+
toastKey: string;
|
|
37
|
+
/**
|
|
38
|
+
* Toast stack 가로 위치
|
|
39
|
+
*/
|
|
40
|
+
x: ToastHorizontal;
|
|
41
|
+
/**
|
|
42
|
+
* Toast stack 세로 위치
|
|
43
|
+
*/
|
|
44
|
+
y: ToastVertical;
|
|
45
|
+
/**
|
|
46
|
+
* page frame 기준 위치 간격
|
|
47
|
+
*/
|
|
48
|
+
margin: number | string;
|
|
49
|
+
/**
|
|
50
|
+
* 자동 닫힘까지의 시간(ms)
|
|
51
|
+
*/
|
|
52
|
+
duration: number;
|
|
53
|
+
/**
|
|
54
|
+
* Toast 피드백 성격
|
|
55
|
+
*/
|
|
56
|
+
state: ToastState;
|
|
57
|
+
/**
|
|
58
|
+
* 한 줄 메시지 콘텐츠
|
|
59
|
+
*/
|
|
60
|
+
message: ReactNode;
|
|
61
|
+
/**
|
|
62
|
+
* 선택 보조 콘텐츠
|
|
63
|
+
*/
|
|
64
|
+
description?: ReactNode;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
type NativeToastItemProps = Omit<
|
|
68
|
+
ComponentPropsWithoutRef<"section">,
|
|
69
|
+
"children"
|
|
70
|
+
>;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Toast item props; 개별 Toast 렌더링 props
|
|
74
|
+
* @property {string} toastKey 트리거 지점을 드러내는 semantic key
|
|
75
|
+
* @property {number} duration 자동 닫힘까지의 시간(ms)
|
|
76
|
+
* @property {"standard" | "success" | "warning" | "error"} state Toast 피드백 성격
|
|
77
|
+
* @property {ReactNode} message 한 줄 메시지 콘텐츠
|
|
78
|
+
* @property {ReactNode} [description] 선택 보조 콘텐츠
|
|
79
|
+
* @property {(toastKey: string) => void} onClose 닫힘 요청 핸들러
|
|
80
|
+
* @property {string} [className] Toast item className
|
|
81
|
+
* @see React.ComponentPropsWithoutRef<"section">
|
|
82
|
+
*/
|
|
83
|
+
export interface ToastItemProps extends NativeToastItemProps {
|
|
84
|
+
/**
|
|
85
|
+
* 트리거 지점을 드러내는 semantic key
|
|
86
|
+
*/
|
|
87
|
+
toastKey: string;
|
|
88
|
+
/**
|
|
89
|
+
* 자동 닫힘까지의 시간(ms)
|
|
90
|
+
*/
|
|
91
|
+
duration: number;
|
|
92
|
+
/**
|
|
93
|
+
* Toast 피드백 성격
|
|
94
|
+
*/
|
|
95
|
+
state: ToastState;
|
|
96
|
+
/**
|
|
97
|
+
* 한 줄 메시지 콘텐츠
|
|
98
|
+
*/
|
|
99
|
+
message: ReactNode;
|
|
100
|
+
/**
|
|
101
|
+
* 선택 보조 콘텐츠
|
|
102
|
+
*/
|
|
103
|
+
description?: ReactNode;
|
|
104
|
+
/**
|
|
105
|
+
* 닫힘 요청 핸들러
|
|
106
|
+
*/
|
|
107
|
+
onClose: (toastKey: string) => void;
|
|
108
|
+
/**
|
|
109
|
+
* Toast item className
|
|
110
|
+
*/
|
|
111
|
+
className?: string;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Toast host props; placement별 Toast stack 렌더링 props
|
|
116
|
+
* @property {ToastItemData[]} items Toast item 데이터 목록
|
|
117
|
+
* @property {(toastKey: string) => void} onClose 닫힘 요청 핸들러
|
|
118
|
+
*/
|
|
119
|
+
export interface ToastHostProps {
|
|
120
|
+
/**
|
|
121
|
+
* Toast item 데이터 목록
|
|
122
|
+
*/
|
|
123
|
+
items: ToastItemData[];
|
|
124
|
+
/**
|
|
125
|
+
* 닫힘 요청 핸들러
|
|
126
|
+
*/
|
|
127
|
+
onClose: (toastKey: string) => void;
|
|
128
|
+
}
|
package/src/index.scss
CHANGED
package/src/index.tsx
CHANGED
|
@@ -28,5 +28,6 @@ export * from "./components/spinner";
|
|
|
28
28
|
export * from "./components/switch";
|
|
29
29
|
export * from "./components/tab";
|
|
30
30
|
export * from "./components/table";
|
|
31
|
+
export * from "./components/toast";
|
|
31
32
|
export * from "./components/tooltip";
|
|
32
33
|
export type * from "./types";
|
|
File without changes
|
|
File without changes
|