@uniai-fe/uds-templates 0.3.6 → 0.3.8
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/package.json
CHANGED
|
@@ -52,7 +52,11 @@ export function ModalContainer({
|
|
|
52
52
|
|
|
53
53
|
return (
|
|
54
54
|
<ContextProvider>
|
|
55
|
-
<div
|
|
55
|
+
<div
|
|
56
|
+
className={clsx("uds-modal-container", className)}
|
|
57
|
+
// 변경 설명: Dialog 기본 submit 동작에서 현재 스택의 form을 조회하기 위한 식별자다.
|
|
58
|
+
data-modal-stack-key={stackKey}
|
|
59
|
+
>
|
|
56
60
|
{header ? <ModalHeaderContainer>{header}</ModalHeaderContainer> : null}
|
|
57
61
|
<ModalBody style={bodyStyle}>{body}</ModalBody>
|
|
58
62
|
{footer ? <div className="uds-modal-footer">{footer}</div> : null}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import clsx from "clsx";
|
|
4
|
+
import { useModal } from "../../hooks/useModal";
|
|
5
|
+
import { ModalHeaderCloseButton } from "../core/header/CloseButton";
|
|
4
6
|
|
|
5
7
|
import type { DialogHeaderProps } from "../../types";
|
|
6
8
|
|
|
@@ -13,6 +15,8 @@ import type { DialogHeaderProps } from "../../types";
|
|
|
13
15
|
* @param {"center" | "split"} [props.layout] 헤더 레이아웃
|
|
14
16
|
* @param {React.ReactNode} [props.leadingContent] 타이틀 왼쪽 콘텐츠
|
|
15
17
|
* @param {React.ReactNode} [props.trailingContent] 우측 액션 콘텐츠
|
|
18
|
+
* @param {string} [props.stackKey] 모달 스택 키(기본 닫기 버튼 동작 연결용)
|
|
19
|
+
* @param {boolean} [props.activeCloseButton] 우측 기본 닫기 버튼 활성화 여부
|
|
16
20
|
* @param {string} [props.className] 헤더 className
|
|
17
21
|
* @example
|
|
18
22
|
* <DialogHeader title="제목" description="설명" />
|
|
@@ -23,10 +27,22 @@ export function DialogHeader({
|
|
|
23
27
|
layout = "center",
|
|
24
28
|
leadingContent,
|
|
25
29
|
trailingContent,
|
|
30
|
+
stackKey,
|
|
31
|
+
activeCloseButton = false,
|
|
26
32
|
className,
|
|
27
33
|
}: DialogHeaderProps) {
|
|
34
|
+
const { closeModal } = useModal();
|
|
28
35
|
const hasRight = Boolean(trailingContent);
|
|
29
36
|
const hasDescription = Boolean(description);
|
|
37
|
+
const shouldRenderDefaultCloseButton =
|
|
38
|
+
activeCloseButton && !hasRight && Boolean(stackKey);
|
|
39
|
+
const resolvedTrailingContent = shouldRenderDefaultCloseButton ? (
|
|
40
|
+
<ModalHeaderCloseButton
|
|
41
|
+
onClick={() => closeModal({ stackKey: String(stackKey) })}
|
|
42
|
+
/>
|
|
43
|
+
) : (
|
|
44
|
+
trailingContent
|
|
45
|
+
);
|
|
30
46
|
// 변경: title/description은 string | number일 때만 래핑한다.
|
|
31
47
|
const shouldWrapTitleAsText = ["string", "number"].includes(typeof title);
|
|
32
48
|
const shouldWrapDescriptionAsText = ["string", "number"].includes(
|
|
@@ -56,9 +72,9 @@ export function DialogHeader({
|
|
|
56
72
|
{shouldWrapTitleAsText ? <h3>{title}</h3> : title}
|
|
57
73
|
</div>
|
|
58
74
|
</div>
|
|
59
|
-
{
|
|
75
|
+
{resolvedTrailingContent ? (
|
|
60
76
|
<div className="uds-modal-dialog-header-trailing">
|
|
61
|
-
{
|
|
77
|
+
{resolvedTrailingContent}
|
|
62
78
|
</div>
|
|
63
79
|
) : null}
|
|
64
80
|
</div>
|
|
@@ -10,6 +10,30 @@ import {
|
|
|
10
10
|
import type { DialogTemplateOptions, ModalState } from "../../types";
|
|
11
11
|
import type { FieldValues } from "react-hook-form";
|
|
12
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Dialog 기본 submit 핸들러 생성기
|
|
15
|
+
* - formContextOptions가 활성화되고 confirm.onClick이 비어 있을 때에만 사용한다.
|
|
16
|
+
*/
|
|
17
|
+
function createDialogFormSubmitHandler(stackKey: string): () => void {
|
|
18
|
+
return () => {
|
|
19
|
+
const modalContainers = document.querySelectorAll<HTMLElement>(
|
|
20
|
+
"[data-modal-stack-key]",
|
|
21
|
+
);
|
|
22
|
+
const targetContainer = Array.from(modalContainers).find(
|
|
23
|
+
container => container.dataset.modalStackKey === stackKey,
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
if (!targetContainer) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const formElement = targetContainer.querySelector("form");
|
|
31
|
+
if (formElement instanceof HTMLFormElement) {
|
|
32
|
+
formElement.requestSubmit();
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
13
37
|
/**
|
|
14
38
|
* Modal Dialog Template; Dialog 모달 상태 생성기
|
|
15
39
|
* @component
|
|
@@ -20,6 +44,7 @@ import type { FieldValues } from "react-hook-form";
|
|
|
20
44
|
* @param {"center" | "split"} [options.headerLayout] 헤더 레이아웃
|
|
21
45
|
* @param {React.ReactNode} [options.headerLeadingContent] 타이틀 왼쪽 콘텐츠
|
|
22
46
|
* @param {React.ReactNode} [options.headerTrailingContent] 우측 액션 콘텐츠
|
|
47
|
+
* @param {boolean} [options.activeCloseButton] 우측 기본 닫기 버튼 표시 여부
|
|
23
48
|
* @param {string} [options.headerClassName] 헤더 className
|
|
24
49
|
* @param {React.ReactNode} [options.customHeader] 완전 커스텀 header
|
|
25
50
|
* @param {React.ReactNode} options.content 본문 콘텐츠
|
|
@@ -42,6 +67,7 @@ export function createDialogModal<FormContext extends FieldValues>({
|
|
|
42
67
|
headerLayout,
|
|
43
68
|
headerLeadingContent,
|
|
44
69
|
headerTrailingContent,
|
|
70
|
+
activeCloseButton,
|
|
45
71
|
headerClassName,
|
|
46
72
|
customHeader,
|
|
47
73
|
content,
|
|
@@ -55,6 +81,16 @@ export function createDialogModal<FormContext extends FieldValues>({
|
|
|
55
81
|
formContextOptions,
|
|
56
82
|
}: DialogTemplateOptions<FormContext>): ModalState<FormContext> {
|
|
57
83
|
const primary = resolveDialogPrimaryButton(confirm);
|
|
84
|
+
const hasFormContext = typeof formContextOptions !== "undefined";
|
|
85
|
+
const resolvedPrimary =
|
|
86
|
+
hasFormContext && typeof primary.onClick === "undefined"
|
|
87
|
+
? {
|
|
88
|
+
...primary,
|
|
89
|
+
// 변경 설명: Form.Provider가 있는 Dialog는 confirm 기본동작을 submit으로 연결하고 자동 close는 비활성화한다.
|
|
90
|
+
closeOnClick: primary.closeOnClick ?? false,
|
|
91
|
+
onClick: createDialogFormSubmitHandler(stackKey),
|
|
92
|
+
}
|
|
93
|
+
: primary;
|
|
58
94
|
|
|
59
95
|
const headerNode =
|
|
60
96
|
customHeader ??
|
|
@@ -65,13 +101,19 @@ export function createDialogModal<FormContext extends FieldValues>({
|
|
|
65
101
|
layout={headerLayout}
|
|
66
102
|
leadingContent={headerLeadingContent}
|
|
67
103
|
trailingContent={headerTrailingContent}
|
|
104
|
+
stackKey={stackKey}
|
|
105
|
+
activeCloseButton={activeCloseButton}
|
|
68
106
|
className={headerClassName}
|
|
69
107
|
/>
|
|
70
108
|
) : null);
|
|
71
109
|
|
|
72
110
|
const footerButtons = footer
|
|
73
111
|
? undefined
|
|
74
|
-
: createDialogFooterButtons({
|
|
112
|
+
: createDialogFooterButtons({
|
|
113
|
+
stackKey,
|
|
114
|
+
primary: resolvedPrimary,
|
|
115
|
+
cancel,
|
|
116
|
+
});
|
|
75
117
|
|
|
76
118
|
return {
|
|
77
119
|
stackKey,
|
|
@@ -256,6 +256,8 @@ export type AlertContentsProps = {
|
|
|
256
256
|
* @property {ModalDialogHeaderLayout} [layout] 레이아웃 정보
|
|
257
257
|
* @property {ReactNode} [leadingContent] 타이틀 왼쪽 콘텐츠
|
|
258
258
|
* @property {ReactNode} [trailingContent] 우측 액션 콘텐츠
|
|
259
|
+
* @property {string} [stackKey] 모달 스택 키(기본 닫기 버튼 동작 연결용)
|
|
260
|
+
* @property {boolean} [activeCloseButton] 우측 기본 닫기 버튼 활성화 여부
|
|
259
261
|
* @property {string} [className] 추가 className
|
|
260
262
|
*/
|
|
261
263
|
export interface DialogHeaderProps {
|
|
@@ -279,6 +281,14 @@ export interface DialogHeaderProps {
|
|
|
279
281
|
* 우측 액션 콘텐츠
|
|
280
282
|
*/
|
|
281
283
|
trailingContent?: ReactNode;
|
|
284
|
+
/**
|
|
285
|
+
* 모달 스택 키(기본 닫기 버튼 동작 연결용)
|
|
286
|
+
*/
|
|
287
|
+
stackKey?: string;
|
|
288
|
+
/**
|
|
289
|
+
* 우측 기본 닫기 버튼 활성화 여부
|
|
290
|
+
*/
|
|
291
|
+
activeCloseButton?: boolean;
|
|
282
292
|
/**
|
|
283
293
|
* 추가 className
|
|
284
294
|
*/
|
|
@@ -135,6 +135,7 @@ export type AlertTemplateOptions<
|
|
|
135
135
|
* @property {ModalDialogHeaderLayout} [headerLayout] 헤더 레이아웃
|
|
136
136
|
* @property {ReactNode} [headerLeadingContent] 타이틀 왼쪽 콘텐츠
|
|
137
137
|
* @property {ReactNode} [headerTrailingContent] 우측 액션 콘텐츠
|
|
138
|
+
* @property {boolean} [activeCloseButton] 우측 기본 닫기 버튼 표시 여부
|
|
138
139
|
* @property {string} [headerClassName] header 추가 className
|
|
139
140
|
* @property {ReactNode} [customHeader] 완전 커스텀 header
|
|
140
141
|
* @property {ReactNode} content 본문 콘텐츠
|
|
@@ -169,6 +170,10 @@ export type DialogTemplateOptions<
|
|
|
169
170
|
* 우측 액션 콘텐츠
|
|
170
171
|
*/
|
|
171
172
|
headerTrailingContent?: ReactNode;
|
|
173
|
+
/**
|
|
174
|
+
* 우측 기본 닫기 버튼 표시 여부
|
|
175
|
+
*/
|
|
176
|
+
activeCloseButton?: boolean;
|
|
172
177
|
/**
|
|
173
178
|
* header 추가 className
|
|
174
179
|
*/
|