@uniai-fe/uds-templates 0.3.4 → 0.3.6
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 +2 -2
- package/src/modal/components/alert/Template.tsx +7 -2
- package/src/modal/components/core/Container.tsx +25 -14
- package/src/modal/components/dialog/Template.tsx +7 -2
- package/src/modal/hooks/useModal.ts +16 -5
- package/src/modal/types/components.ts +10 -4
- package/src/modal/types/hooks.ts +11 -6
- package/src/modal/types/state.ts +28 -8
- package/src/modal/types/templates.ts +28 -4
- package/src/page-frame/desktop/components/header/util/setting/Button.tsx +7 -11
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uniai-fe/uds-templates",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.6",
|
|
4
4
|
"description": "UNIAI Design System; UI Templates Package",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"publishConfig": {
|
|
13
13
|
"access": "public"
|
|
14
14
|
},
|
|
15
|
-
"packageManager": "pnpm@10.30.
|
|
15
|
+
"packageManager": "pnpm@10.30.3",
|
|
16
16
|
"engines": {
|
|
17
17
|
"node": ">=24",
|
|
18
18
|
"pnpm": ">=10"
|
|
@@ -8,6 +8,7 @@ import type {
|
|
|
8
8
|
ModalState,
|
|
9
9
|
ModalTemplateButtonSpec,
|
|
10
10
|
} from "../../types";
|
|
11
|
+
import type { FieldValues } from "react-hook-form";
|
|
11
12
|
|
|
12
13
|
const DEFAULT_CONFIRM_LABEL = "확인";
|
|
13
14
|
|
|
@@ -23,11 +24,12 @@ const DEFAULT_CONFIRM_LABEL = "확인";
|
|
|
23
24
|
* @param {number} [options.showDelay] close 후 제거 지연(ms)
|
|
24
25
|
* @param {number | string} [options.width] 모달 width
|
|
25
26
|
* @param {StyleSpacingType} [options.padding] 모달 body padding
|
|
27
|
+
* @param {UseFormProps<FormContext>} [options.formContextOptions] modal 내부 Form.Provider 옵션
|
|
26
28
|
* @returns {ModalState}
|
|
27
29
|
* @example
|
|
28
30
|
* Modal.Alert({ stackKey: "sample", message: "완료되었습니다." })
|
|
29
31
|
*/
|
|
30
|
-
export function createAlertModal({
|
|
32
|
+
export function createAlertModal<FormContext extends FieldValues>({
|
|
31
33
|
stackKey,
|
|
32
34
|
message,
|
|
33
35
|
confirm,
|
|
@@ -36,7 +38,8 @@ export function createAlertModal({
|
|
|
36
38
|
showDelay,
|
|
37
39
|
width,
|
|
38
40
|
padding,
|
|
39
|
-
|
|
41
|
+
formContextOptions,
|
|
42
|
+
}: AlertTemplateOptions<FormContext>): ModalState<FormContext> {
|
|
40
43
|
const primary: ModalTemplateButtonSpec = confirm ?? {
|
|
41
44
|
label: DEFAULT_CONFIRM_LABEL,
|
|
42
45
|
};
|
|
@@ -48,6 +51,8 @@ export function createAlertModal({
|
|
|
48
51
|
showDelay,
|
|
49
52
|
width,
|
|
50
53
|
padding,
|
|
54
|
+
// 변경 설명: 템플릿 생성 시점의 FormContext 제네릭을 modalProps로 전달한다.
|
|
55
|
+
formContextOptions,
|
|
51
56
|
body: <AlertContents message={message} />,
|
|
52
57
|
footer,
|
|
53
58
|
// 변경: footer가 없을 때만 템플릿 버튼 스펙을 조합한다.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import type
|
|
3
|
+
import { type CSSProperties } from "react";
|
|
4
4
|
|
|
5
5
|
import clsx from "clsx";
|
|
6
6
|
import { stylePaddingSize } from "@uniai-fe/util-functions";
|
|
@@ -9,6 +9,7 @@ import type { ModalContainerProps } from "../../types";
|
|
|
9
9
|
import { ModalBody } from "./Body";
|
|
10
10
|
import { ModalHeaderContainer } from "./header/Container";
|
|
11
11
|
import { ModalFooterButtonWrapper } from "./footer/ButtonWrapper";
|
|
12
|
+
import { Form } from "@uniai-fe/uds-primitives";
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* Modal Container; header/body/footer 슬롯 조합 컨테이너
|
|
@@ -32,6 +33,7 @@ export function ModalContainer({
|
|
|
32
33
|
footerButtons,
|
|
33
34
|
padding,
|
|
34
35
|
className,
|
|
36
|
+
formContextOptions,
|
|
35
37
|
}: ModalContainerProps) {
|
|
36
38
|
// 변경: modalProps의 padding을 CSS 변수로 주입해 템플릿 단위 body spacing 제어를 유지한다.
|
|
37
39
|
const bodyStyle =
|
|
@@ -41,19 +43,28 @@ export function ModalContainer({
|
|
|
41
43
|
} as CSSProperties)
|
|
42
44
|
: undefined;
|
|
43
45
|
|
|
46
|
+
const ContextProvider = ({ children }: { children: React.ReactNode }) =>
|
|
47
|
+
typeof formContextOptions !== "undefined" ? (
|
|
48
|
+
<Form.Provider options={formContextOptions}>{children}</Form.Provider>
|
|
49
|
+
) : (
|
|
50
|
+
children
|
|
51
|
+
);
|
|
52
|
+
|
|
44
53
|
return (
|
|
45
|
-
<
|
|
46
|
-
{
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
<
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
54
|
+
<ContextProvider>
|
|
55
|
+
<div className={clsx("uds-modal-container", className)}>
|
|
56
|
+
{header ? <ModalHeaderContainer>{header}</ModalHeaderContainer> : null}
|
|
57
|
+
<ModalBody style={bodyStyle}>{body}</ModalBody>
|
|
58
|
+
{footer ? <div className="uds-modal-footer">{footer}</div> : null}
|
|
59
|
+
{!footer && footerButtons && footerButtons.length ? (
|
|
60
|
+
<div className="uds-modal-footer">
|
|
61
|
+
<ModalFooterButtonWrapper
|
|
62
|
+
stackKey={stackKey}
|
|
63
|
+
buttons={footerButtons}
|
|
64
|
+
/>
|
|
65
|
+
</div>
|
|
66
|
+
) : null}
|
|
67
|
+
</div>
|
|
68
|
+
</ContextProvider>
|
|
58
69
|
);
|
|
59
70
|
}
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
} from "../../utils/create-dialog-footer-buttons";
|
|
9
9
|
|
|
10
10
|
import type { DialogTemplateOptions, ModalState } from "../../types";
|
|
11
|
+
import type { FieldValues } from "react-hook-form";
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* Modal Dialog Template; Dialog 모달 상태 생성기
|
|
@@ -29,11 +30,12 @@ import type { DialogTemplateOptions, ModalState } from "../../types";
|
|
|
29
30
|
* @param {number} [options.showDelay] close 후 제거 지연(ms)
|
|
30
31
|
* @param {number | string} [options.width] 모달 width
|
|
31
32
|
* @param {StyleSpacingType} [options.padding] 모달 body padding
|
|
33
|
+
* @param {UseFormProps<FormContext>} [options.formContextOptions] modal 내부 Form.Provider 옵션
|
|
32
34
|
* @returns {ModalState}
|
|
33
35
|
* @example
|
|
34
36
|
* Modal.Dialog({ stackKey: "sample", title: "제목", content: "본문" })
|
|
35
37
|
*/
|
|
36
|
-
export function createDialogModal({
|
|
38
|
+
export function createDialogModal<FormContext extends FieldValues>({
|
|
37
39
|
stackKey,
|
|
38
40
|
title,
|
|
39
41
|
description,
|
|
@@ -50,7 +52,8 @@ export function createDialogModal({
|
|
|
50
52
|
showDelay,
|
|
51
53
|
width,
|
|
52
54
|
padding,
|
|
53
|
-
|
|
55
|
+
formContextOptions,
|
|
56
|
+
}: DialogTemplateOptions<FormContext>): ModalState<FormContext> {
|
|
54
57
|
const primary = resolveDialogPrimaryButton(confirm);
|
|
55
58
|
|
|
56
59
|
const headerNode =
|
|
@@ -77,6 +80,8 @@ export function createDialogModal({
|
|
|
77
80
|
showDelay,
|
|
78
81
|
width,
|
|
79
82
|
padding,
|
|
83
|
+
// 변경 설명: 템플릿 생성 시점의 FormContext 제네릭을 modalProps로 전달한다.
|
|
84
|
+
formContextOptions,
|
|
80
85
|
header: headerNode ?? undefined,
|
|
81
86
|
body: <DialogContents content={content} className={bodyClassName} />,
|
|
82
87
|
footer,
|
|
@@ -7,11 +7,13 @@ import { useAtom } from "jotai";
|
|
|
7
7
|
import type {
|
|
8
8
|
CloseFlagState,
|
|
9
9
|
ModalCloseRequest,
|
|
10
|
+
ModalProps,
|
|
10
11
|
ModalState,
|
|
11
12
|
ModalStatePatch,
|
|
12
13
|
UseModalReturn,
|
|
13
14
|
} from "../types";
|
|
14
15
|
import { modalStackAtom } from "../jotai/atoms";
|
|
16
|
+
import type { FieldValues } from "react-hook-form";
|
|
15
17
|
|
|
16
18
|
const DEFAULT_CLOSE_DELAY = 400;
|
|
17
19
|
|
|
@@ -30,7 +32,7 @@ export function useModal(): UseModalReturn {
|
|
|
30
32
|
const [closeFlag, setCloseFlag] = useState<CloseFlagState | null>(null);
|
|
31
33
|
|
|
32
34
|
const newModal = useCallback(
|
|
33
|
-
(newStack: ModalState) => {
|
|
35
|
+
<FormContext extends FieldValues>(newStack: ModalState<FormContext>) => {
|
|
34
36
|
updateModalStack((stacks: ModalState[]) => {
|
|
35
37
|
const exists = stacks.some(
|
|
36
38
|
stack => stack.stackKey === newStack.stackKey,
|
|
@@ -45,7 +47,10 @@ export function useModal(): UseModalReturn {
|
|
|
45
47
|
...stacks,
|
|
46
48
|
{
|
|
47
49
|
...newStack,
|
|
48
|
-
modalProps: {
|
|
50
|
+
modalProps: {
|
|
51
|
+
...(newStack.modalProps as ModalProps),
|
|
52
|
+
show: "init",
|
|
53
|
+
},
|
|
49
54
|
},
|
|
50
55
|
];
|
|
51
56
|
});
|
|
@@ -54,14 +59,20 @@ export function useModal(): UseModalReturn {
|
|
|
54
59
|
);
|
|
55
60
|
|
|
56
61
|
const updateModal = useCallback(
|
|
57
|
-
|
|
62
|
+
<FormContext extends FieldValues>(
|
|
63
|
+
nextStack: ModalStatePatch<FormContext>,
|
|
64
|
+
) => {
|
|
58
65
|
updateModalStack((stacks: ModalState[]) =>
|
|
59
66
|
stacks.map(stack => {
|
|
60
67
|
if (stack.stackKey !== nextStack.stackKey) {
|
|
61
68
|
return stack;
|
|
62
69
|
}
|
|
63
|
-
|
|
64
|
-
|
|
70
|
+
// 변경 설명: 스택 저장 타입은 공통 ModalProps로 유지하고, 제네릭 옵션은 생성 경계에서만 보장한다.
|
|
71
|
+
const mergedProps: ModalProps = nextStack.modalProps
|
|
72
|
+
? {
|
|
73
|
+
...stack.modalProps,
|
|
74
|
+
...(nextStack.modalProps as Partial<ModalProps>),
|
|
75
|
+
}
|
|
65
76
|
: stack.modalProps;
|
|
66
77
|
return {
|
|
67
78
|
...stack,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { CSSProperties, ReactNode } from "react";
|
|
2
|
+
import type { FieldValues } from "react-hook-form";
|
|
2
3
|
import type {
|
|
3
4
|
ModalFooterButtonAppearance,
|
|
4
5
|
ModalFooterButtonDefaultOptions,
|
|
@@ -12,11 +13,13 @@ import type { ModalFooterButton } from "./footer";
|
|
|
12
13
|
/**
|
|
13
14
|
* ModalRoot 컴포넌트 props.
|
|
14
15
|
* @property {string} stackKey 모달 스택 식별자
|
|
15
|
-
* @property {ModalProps} modalProps 모달 렌더링에 필요한 상태
|
|
16
|
+
* @property {ModalProps<FormContext>} modalProps 모달 렌더링에 필요한 상태
|
|
16
17
|
* @property {number} index Provider에서 전달한 스택 index
|
|
17
18
|
* @property {string} [className] 사용자 정의 className
|
|
18
19
|
*/
|
|
19
|
-
export type ModalRootProps
|
|
20
|
+
export type ModalRootProps<
|
|
21
|
+
FormContext extends FieldValues = Record<string, unknown>,
|
|
22
|
+
> = ModalState<FormContext> & {
|
|
20
23
|
/**
|
|
21
24
|
* 모달 스택 식별자
|
|
22
25
|
*/
|
|
@@ -24,7 +27,7 @@ export type ModalRootProps = ModalState & {
|
|
|
24
27
|
/**
|
|
25
28
|
* 모달 렌더링에 필요한 상태
|
|
26
29
|
*/
|
|
27
|
-
modalProps: ModalProps
|
|
30
|
+
modalProps: ModalProps<FormContext>;
|
|
28
31
|
/**
|
|
29
32
|
* Provider에서 전달한 스택 index
|
|
30
33
|
*/
|
|
@@ -43,8 +46,11 @@ export type ModalRootProps = ModalState & {
|
|
|
43
46
|
* @property {ReactNode} [footer] footer 콘텐츠
|
|
44
47
|
* @property {ModalFooterButton[]} [footerButtons] footer 버튼 목록
|
|
45
48
|
* @property {string} [className] 컨테이너 className
|
|
49
|
+
* @property {UseFormProps<FormContext>} [formContextOptions] form context 옵션
|
|
46
50
|
*/
|
|
47
|
-
export type ModalContainerProps
|
|
51
|
+
export type ModalContainerProps<
|
|
52
|
+
FormContext extends FieldValues = Record<string, unknown>,
|
|
53
|
+
> = ModalSections<FormContext> & {
|
|
48
54
|
/**
|
|
49
55
|
* 모달 스택 식별자
|
|
50
56
|
*/
|
package/src/modal/types/hooks.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import type { ModalCloseRequest } from "./options";
|
|
2
2
|
import type { ModalState, ModalStatePatch } from "./state";
|
|
3
|
+
import type { FieldValues } from "react-hook-form";
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* close flag 상태; 모달 스택 제거 예약을 표현한다.
|
|
6
7
|
* @property {string} stackKey 닫을 모달 스택 키
|
|
7
8
|
* @property {number} showDelay 제거까지 대기할 지연(ms)
|
|
8
|
-
* @property {
|
|
9
|
+
* @property {() => void} [callback] 완료 후 실행 콜백
|
|
9
10
|
*/
|
|
10
11
|
export type CloseFlagState = {
|
|
11
12
|
/**
|
|
@@ -19,14 +20,14 @@ export type CloseFlagState = {
|
|
|
19
20
|
/**
|
|
20
21
|
* 완료 후 실행 콜백
|
|
21
22
|
*/
|
|
22
|
-
callback?:
|
|
23
|
+
callback?: () => void;
|
|
23
24
|
};
|
|
24
25
|
|
|
25
26
|
/**
|
|
26
27
|
* useModal 훅 반환값.
|
|
27
28
|
* @property {ModalState[]} modalStacks 현재 모달 스택 목록
|
|
28
|
-
* @property {(newStack: ModalState) => void} newModal 신규 모달 추가 함수
|
|
29
|
-
* @property {(nextStack: ModalStatePatch) => void} updateModal 스택 상태 갱신 함수
|
|
29
|
+
* @property {<FormContext extends FieldValues>(newStack: ModalState<FormContext>) => void} newModal 신규 모달 추가 함수
|
|
30
|
+
* @property {<FormContext extends FieldValues>(nextStack: ModalStatePatch<FormContext>) => void} updateModal 스택 상태 갱신 함수
|
|
30
31
|
* @property {(request: ModalCloseRequest) => void} closeModal close 제어 함수
|
|
31
32
|
*/
|
|
32
33
|
export type UseModalReturn = {
|
|
@@ -37,11 +38,15 @@ export type UseModalReturn = {
|
|
|
37
38
|
/**
|
|
38
39
|
* 신규 모달 추가 함수
|
|
39
40
|
*/
|
|
40
|
-
newModal:
|
|
41
|
+
newModal: <FormContext extends FieldValues>(
|
|
42
|
+
newStack: ModalState<FormContext>,
|
|
43
|
+
) => void;
|
|
41
44
|
/**
|
|
42
45
|
* 스택 상태 갱신 함수
|
|
43
46
|
*/
|
|
44
|
-
updateModal:
|
|
47
|
+
updateModal: <FormContext extends FieldValues>(
|
|
48
|
+
nextStack: ModalStatePatch<FormContext>,
|
|
49
|
+
) => void;
|
|
45
50
|
/**
|
|
46
51
|
* close 제어 함수
|
|
47
52
|
*/
|
package/src/modal/types/state.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { ReactNode } from "react";
|
|
|
2
2
|
|
|
3
3
|
import type { ModalFooterButton } from "./footer";
|
|
4
4
|
import type { StyleSpacingType } from "@uniai-fe/util-functions";
|
|
5
|
+
import type { FieldValues, UseFormProps } from "react-hook-form";
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Modal 노출 상태 표현값.
|
|
@@ -16,8 +17,11 @@ export type ModalShowState = "init" | boolean;
|
|
|
16
17
|
* @property {ReactNode} [footer] footer 콘텐츠
|
|
17
18
|
* @property {number | string} [width] 커스텀 width
|
|
18
19
|
* @property {StyleSpacingType} [padding] 커스텀 padding
|
|
20
|
+
* @property {UseFormProps<FormContext>} [formContextOptions] form context 옵션
|
|
19
21
|
*/
|
|
20
|
-
export type ModalSections
|
|
22
|
+
export type ModalSections<
|
|
23
|
+
FormContext extends FieldValues = Record<string, unknown>,
|
|
24
|
+
> = {
|
|
21
25
|
/**
|
|
22
26
|
* 헤더 콘텐츠
|
|
23
27
|
*/
|
|
@@ -44,6 +48,15 @@ export type ModalSections = {
|
|
|
44
48
|
* - [상, 우, 하, 좌]
|
|
45
49
|
*/
|
|
46
50
|
padding?: StyleSpacingType;
|
|
51
|
+
/**
|
|
52
|
+
* form context 옵션
|
|
53
|
+
* - 옵션이 활성화되면, Form.Provider 사용으로 간주하여 활성화시킴
|
|
54
|
+
* ```
|
|
55
|
+
* // 다음과 같이 전달
|
|
56
|
+
* <Form.Provider options={formContextOptions}>
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
formContextOptions?: UseFormProps<FormContext>;
|
|
47
60
|
};
|
|
48
61
|
|
|
49
62
|
/**
|
|
@@ -56,8 +69,11 @@ export type ModalSections = {
|
|
|
56
69
|
* @property {ModalShowState} show 노출 상태
|
|
57
70
|
* @property {number} [showDelay] close 후 제거 지연(ms)
|
|
58
71
|
* @property {ModalFooterButton[]} [footerButtons] footer 버튼 스펙
|
|
72
|
+
* @property {UseFormProps<FormContext>} [formContextOptions] form context 옵션
|
|
59
73
|
*/
|
|
60
|
-
export type ModalProps
|
|
74
|
+
export type ModalProps<
|
|
75
|
+
FormContext extends FieldValues = Record<string, unknown>,
|
|
76
|
+
> = ModalSections<FormContext> & {
|
|
61
77
|
/**
|
|
62
78
|
* 노출 상태
|
|
63
79
|
*/
|
|
@@ -75,10 +91,12 @@ export type ModalProps = ModalSections & {
|
|
|
75
91
|
/**
|
|
76
92
|
* Modal 스택에 저장되는 상태.
|
|
77
93
|
* @property {string} stackKey 모달 스택 키
|
|
78
|
-
* @property {ModalProps} modalProps 컨테이너 props
|
|
94
|
+
* @property {ModalProps<FormContext>} modalProps 컨테이너 props
|
|
79
95
|
* @property {string} [className] 추가 className
|
|
80
96
|
*/
|
|
81
|
-
export type ModalState
|
|
97
|
+
export type ModalState<
|
|
98
|
+
FormContext extends FieldValues = Record<string, unknown>,
|
|
99
|
+
> = {
|
|
82
100
|
/**
|
|
83
101
|
* 모달 스택 키
|
|
84
102
|
*/
|
|
@@ -86,7 +104,7 @@ export type ModalState = {
|
|
|
86
104
|
/**
|
|
87
105
|
* 컨테이너 props
|
|
88
106
|
*/
|
|
89
|
-
modalProps: ModalProps
|
|
107
|
+
modalProps: ModalProps<FormContext>;
|
|
90
108
|
/**
|
|
91
109
|
* 추가 className
|
|
92
110
|
*/
|
|
@@ -96,10 +114,12 @@ export type ModalState = {
|
|
|
96
114
|
/**
|
|
97
115
|
* Modal 상태 패치 데이터.
|
|
98
116
|
* @property {string} stackKey 수정할 모달 스택 키
|
|
99
|
-
* @property {Partial<ModalProps
|
|
117
|
+
* @property {Partial<ModalProps<FormContext>>} [modalProps] 덮어쓸 props
|
|
100
118
|
* @property {string} [className] 추가 className
|
|
101
119
|
*/
|
|
102
|
-
export type ModalStatePatch
|
|
120
|
+
export type ModalStatePatch<
|
|
121
|
+
FormContext extends FieldValues = Record<string, unknown>,
|
|
122
|
+
> = {
|
|
103
123
|
/**
|
|
104
124
|
* 수정할 모달 스택 키
|
|
105
125
|
*/
|
|
@@ -107,7 +127,7 @@ export type ModalStatePatch = {
|
|
|
107
127
|
/**
|
|
108
128
|
* 덮어쓸 props
|
|
109
129
|
*/
|
|
110
|
-
modalProps?: Partial<ModalProps
|
|
130
|
+
modalProps?: Partial<ModalProps<FormContext>>;
|
|
111
131
|
/**
|
|
112
132
|
* 추가 className
|
|
113
133
|
*/
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
|
+
import type { FieldValues, UseFormProps } from "react-hook-form";
|
|
2
3
|
|
|
3
4
|
import type {
|
|
4
5
|
ModalFooterButtonPosition,
|
|
@@ -56,7 +57,9 @@ export type ModalTemplateButtonSpec = {
|
|
|
56
57
|
* @property {number | string} [width] 커스텀 width
|
|
57
58
|
* @property {StyleSpacingType} [padding] 커스텀 padding
|
|
58
59
|
*/
|
|
59
|
-
type ModalTemplateBase
|
|
60
|
+
type ModalTemplateBase<
|
|
61
|
+
FormContext extends FieldValues = Record<string, unknown>,
|
|
62
|
+
> = {
|
|
60
63
|
/**
|
|
61
64
|
* 모달 스택 키
|
|
62
65
|
*/
|
|
@@ -79,6 +82,11 @@ type ModalTemplateBase = {
|
|
|
79
82
|
* - [상, 우, 하, 좌]
|
|
80
83
|
*/
|
|
81
84
|
padding?: StyleSpacingType;
|
|
85
|
+
/**
|
|
86
|
+
* modal 내부 Form.Provider 옵션
|
|
87
|
+
* - 타입 안정성은 Modal.Alert/Dialog 생성 시점 제네릭으로 보장한다.
|
|
88
|
+
*/
|
|
89
|
+
formContextOptions?: UseFormProps<FormContext>;
|
|
82
90
|
};
|
|
83
91
|
|
|
84
92
|
/**
|
|
@@ -91,8 +99,11 @@ type ModalTemplateBase = {
|
|
|
91
99
|
* @property {ReactNode} [footer] 커스텀 footer
|
|
92
100
|
* @property {number | string} [width] 커스텀 width
|
|
93
101
|
* @property {StyleSpacingType} [padding] 커스텀 padding
|
|
102
|
+
* @property {UseFormProps<FormContext>} [formContextOptions] modal 내부 Form.Provider 옵션
|
|
94
103
|
*/
|
|
95
|
-
export type AlertTemplateOptions
|
|
104
|
+
export type AlertTemplateOptions<
|
|
105
|
+
FormContext extends FieldValues = Record<string, unknown>,
|
|
106
|
+
> = ModalTemplateBase<FormContext> & {
|
|
96
107
|
/**
|
|
97
108
|
* 본문 메시지
|
|
98
109
|
*/
|
|
@@ -109,6 +120,10 @@ export type AlertTemplateOptions = ModalTemplateBase & {
|
|
|
109
120
|
* 커스텀 footer
|
|
110
121
|
*/
|
|
111
122
|
footer?: ReactNode;
|
|
123
|
+
/**
|
|
124
|
+
* modal 내부 Form.Provider 옵션
|
|
125
|
+
*/
|
|
126
|
+
formContextOptions?: UseFormProps<FormContext>;
|
|
112
127
|
};
|
|
113
128
|
|
|
114
129
|
/**
|
|
@@ -129,8 +144,11 @@ export type AlertTemplateOptions = ModalTemplateBase & {
|
|
|
129
144
|
* @property {ReactNode} [footer] 커스텀 footer
|
|
130
145
|
* @property {number | string} [width] 커스텀 width
|
|
131
146
|
* @property {StyleSpacingType} [padding] 커스텀 padding
|
|
147
|
+
* @property {UseFormProps<FormContext>} [formContextOptions] modal 내부 Form.Provider 옵션
|
|
132
148
|
*/
|
|
133
|
-
export type DialogTemplateOptions
|
|
149
|
+
export type DialogTemplateOptions<
|
|
150
|
+
FormContext extends FieldValues = Record<string, unknown>,
|
|
151
|
+
> = ModalTemplateBase<FormContext> & {
|
|
134
152
|
/**
|
|
135
153
|
* 헤더 타이틀
|
|
136
154
|
*/
|
|
@@ -179,10 +197,16 @@ export type DialogTemplateOptions = ModalTemplateBase & {
|
|
|
179
197
|
* 커스텀 footer
|
|
180
198
|
*/
|
|
181
199
|
footer?: ReactNode;
|
|
200
|
+
/**
|
|
201
|
+
* modal 내부 Form.Provider 옵션
|
|
202
|
+
*/
|
|
203
|
+
formContextOptions?: UseFormProps<FormContext>;
|
|
182
204
|
};
|
|
183
205
|
|
|
184
206
|
/**
|
|
185
207
|
* Modal 템플릿 결과 타입.
|
|
186
208
|
* @typedef {ModalState} ModalTemplateResult
|
|
187
209
|
*/
|
|
188
|
-
export type ModalTemplateResult
|
|
210
|
+
export type ModalTemplateResult<
|
|
211
|
+
FormContext extends FieldValues = Record<string, unknown>,
|
|
212
|
+
> = ModalState<FormContext>;
|
|
@@ -42,6 +42,10 @@ export default function PageHeaderSettingButton({
|
|
|
42
42
|
);
|
|
43
43
|
const pathname = usePathname();
|
|
44
44
|
const resolvedPath = pathname ?? "";
|
|
45
|
+
const closestRoute = useMemo(
|
|
46
|
+
() => getClosestRoute(menuItems, resolvedPath),
|
|
47
|
+
[menuItems, resolvedPath],
|
|
48
|
+
);
|
|
45
49
|
|
|
46
50
|
const dropdownItems: DropdownTemplateItem[] = useMemo(
|
|
47
51
|
() =>
|
|
@@ -49,19 +53,12 @@ export default function PageHeaderSettingButton({
|
|
|
49
53
|
id: item.routeKey,
|
|
50
54
|
label: item.name,
|
|
51
55
|
left: item.icon,
|
|
56
|
+
// 변경: Dropdown.Template 선택 계약은 items[].selected를 source로 사용한다.
|
|
57
|
+
selected: String(closestRoute?.routeKey) === String(item.routeKey),
|
|
52
58
|
})),
|
|
53
|
-
[menuItems],
|
|
59
|
+
[closestRoute?.routeKey, menuItems],
|
|
54
60
|
);
|
|
55
61
|
|
|
56
|
-
/**
|
|
57
|
-
* 현재 경로와 가장 근접한 설정 경로를 계산한다.
|
|
58
|
-
* - 메뉴 수가 많아져도 useMemo로 계산을 한 번만 수행한다.
|
|
59
|
-
*/
|
|
60
|
-
const selectedIds = useMemo(() => {
|
|
61
|
-
const closestRoute = getClosestRoute(menuItems, resolvedPath);
|
|
62
|
-
return closestRoute ? [String(closestRoute.routeKey)] : [];
|
|
63
|
-
}, [menuItems, resolvedPath]);
|
|
64
|
-
|
|
65
62
|
/**
|
|
66
63
|
* dropdown 항목을 선택했을 때 routeKey에 대응하는 onSelect를 실행한다.
|
|
67
64
|
* @param {DropdownTemplateChangePayload} payload 선택 결과 payload
|
|
@@ -98,7 +95,6 @@ export default function PageHeaderSettingButton({
|
|
|
98
95
|
items={dropdownItems}
|
|
99
96
|
width={170}
|
|
100
97
|
size="small"
|
|
101
|
-
selectedIds={selectedIds}
|
|
102
98
|
// Dropdown.Template 신규 계약(onChange payload)을 우선 사용한다.
|
|
103
99
|
onChange={handleSelect}
|
|
104
100
|
containerProps={{
|