@uniai-fe/uds-templates 0.2.1 → 0.2.4
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 +1 -1
- package/dist/styles.css +3 -3
- package/package.json +1 -1
- package/src/auth/login/types/api.ts +7 -0
- package/src/cctv/components/video/Template.tsx +6 -3
- package/src/modal/core/components/Container.tsx +18 -1
- package/src/modal/core/components/Root.tsx +17 -7
- package/src/modal/styles/base.scss +1 -1
- package/src/modal/styles/container.scss +4 -1
- package/src/modal/templates/Dialog.tsx +4 -0
- package/src/modal/templates/components/DialogBody.tsx +0 -1
- package/src/modal/types/state.ts +19 -0
- package/src/modal/types/templates.ts +21 -0
- package/src/page-frame/desktop/styles/variables.scss +1 -1
package/README.md
CHANGED
|
@@ -123,7 +123,7 @@ export default function LoginPage() {
|
|
|
123
123
|
> 위 예시는 개념을 설명하기 위한 형태이며,
|
|
124
124
|
> 실제 props 구조/이름은 `CONTEXT-AUTH.md`에서 확정·관리합니다.
|
|
125
125
|
|
|
126
|
-
> modules 레포 내부(Storybook 등)에서는 개발 편의를 위해 `@uniai-fe/uds-templates/
|
|
126
|
+
> modules 레포 내부(Storybook 등)에서는 개발 편의를 위해 `@uniai-fe/uds-templates/styles` 엔트리를 import하지만, 외부 서비스/패키지는 `@uniai-fe/uds-templates/css` 엔트리만 사용해야 한다.
|
|
127
127
|
|
|
128
128
|
### 최근 업데이트
|
|
129
129
|
|
package/dist/styles.css
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
--uds-page-nav-logo-height: var(--uds-page-header-height, 7.2rem);
|
|
14
14
|
--uds-page-nav-list-padding-horizontal: 0rem;
|
|
15
15
|
--uds-page-nav-list-padding-vertical: var(--spacing-padding-9, 2.4rem);
|
|
16
|
-
--uds-page-nav-item-height: var(--theme-size-
|
|
16
|
+
--uds-page-nav-item-height: var(--theme-size-medium-2, 4.8rem);
|
|
17
17
|
--uds-page-nav-item-gap: var(--spacing-gap-6, 1.6rem);
|
|
18
18
|
--uds-page-nav-item-color-default: var(--color-label-standard);
|
|
19
19
|
--uds-page-nav-item-color-active: var(--color-primary-default);
|
|
@@ -456,7 +456,7 @@
|
|
|
456
456
|
.uds-modal-root {
|
|
457
457
|
position: fixed;
|
|
458
458
|
inset: 0;
|
|
459
|
-
z-index: calc(
|
|
459
|
+
z-index: calc(1000 + var(--modal-stack-index, 0));
|
|
460
460
|
display: flex;
|
|
461
461
|
align-items: center;
|
|
462
462
|
justify-content: center;
|
|
@@ -702,7 +702,7 @@
|
|
|
702
702
|
}
|
|
703
703
|
|
|
704
704
|
.uds-modal-dialog-body-content {
|
|
705
|
-
padding: var(--spacing-padding-7, 20px) var(--spacing-padding-6, 16px);
|
|
705
|
+
padding: var(--modal-dialog-body-padding, var(--spacing-padding-7, 20px) var(--spacing-padding-6, 16px));
|
|
706
706
|
text-align: center;
|
|
707
707
|
word-break: keep-all;
|
|
708
708
|
color: var(--modal-dialog-body-color);
|
package/package.json
CHANGED
|
@@ -76,6 +76,13 @@ export interface API_Res_LoginUserInfo {
|
|
|
76
76
|
* 사용자 주소
|
|
77
77
|
*/
|
|
78
78
|
address: string;
|
|
79
|
+
/**
|
|
80
|
+
* 계정 권한/직책 코드
|
|
81
|
+
* - OWNER: 농장주
|
|
82
|
+
* - EMPLOYEE: 농장직원
|
|
83
|
+
* - REGIONAL_MANAGER: 지역소장
|
|
84
|
+
*/
|
|
85
|
+
user_access_role: string;
|
|
79
86
|
/**
|
|
80
87
|
* 가입일 (UTC)
|
|
81
88
|
* - yyyy-MM-ddTHH:mm:ss
|
|
@@ -19,7 +19,7 @@ import type { CctvVideoTemplateProps } from "../../types/props";
|
|
|
19
19
|
* @property {boolean} [isLive]
|
|
20
20
|
* @property {React.Ref<HTMLVideoElement>} ref
|
|
21
21
|
*/
|
|
22
|
-
const CCTVVideoTemplate = forwardRef(
|
|
22
|
+
const CCTVVideoTemplate = forwardRef<HTMLVideoElement, CctvVideoTemplateProps>(
|
|
23
23
|
(
|
|
24
24
|
{
|
|
25
25
|
className,
|
|
@@ -28,8 +28,8 @@ const CCTVVideoTemplate = forwardRef(
|
|
|
28
28
|
isError,
|
|
29
29
|
isLive,
|
|
30
30
|
overlayMessage,
|
|
31
|
-
}
|
|
32
|
-
ref
|
|
31
|
+
},
|
|
32
|
+
ref,
|
|
33
33
|
) => {
|
|
34
34
|
return (
|
|
35
35
|
<CCTVVideoContainer className={className}>
|
|
@@ -46,4 +46,7 @@ const CCTVVideoTemplate = forwardRef(
|
|
|
46
46
|
},
|
|
47
47
|
);
|
|
48
48
|
|
|
49
|
+
// forwardRef Tooltip 유지를 위해 displayName 지정.
|
|
50
|
+
CCTVVideoTemplate.displayName = "CCTVVideoTemplate";
|
|
51
|
+
|
|
49
52
|
export default CCTVVideoTemplate;
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
+
import type { CSSProperties } from "react";
|
|
4
|
+
|
|
5
|
+
import { stylePaddingSize } from "@uniai-fe/util-functions";
|
|
6
|
+
|
|
3
7
|
import type { ModalFooterButton, ModalSections } from "../../types";
|
|
4
8
|
import { ModalFooterButtons } from "./FooterButtons";
|
|
5
9
|
|
|
@@ -12,6 +16,8 @@ import { ModalFooterButtons } from "./FooterButtons";
|
|
|
12
16
|
* @param {React.ReactNode} props.body 본문 슬롯
|
|
13
17
|
* @param {React.ReactNode} [props.footer] footer 슬롯
|
|
14
18
|
* @param {ModalFooterButton[]} [props.footerButtons] footer 버튼 스펙 배열
|
|
19
|
+
* @param {number | string} [props.width] 커스텀 width
|
|
20
|
+
* @param {StyleSpacingType} [props.padding] 커스텀 padding
|
|
15
21
|
*/
|
|
16
22
|
export function ModalContainer({
|
|
17
23
|
stackKey,
|
|
@@ -19,14 +25,25 @@ export function ModalContainer({
|
|
|
19
25
|
body,
|
|
20
26
|
footer,
|
|
21
27
|
footerButtons,
|
|
28
|
+
padding,
|
|
22
29
|
}: ModalSections & {
|
|
23
30
|
stackKey: string;
|
|
24
31
|
footerButtons?: ModalFooterButton[];
|
|
25
32
|
}) {
|
|
33
|
+
// modalProps에서 받은 padding을 직접 스타일에 주입해 템플릿 제어를 허용한다.
|
|
34
|
+
const bodyStyle =
|
|
35
|
+
typeof padding !== "undefined"
|
|
36
|
+
? ({
|
|
37
|
+
"--modal-dialog-body-padding": stylePaddingSize("rem", padding),
|
|
38
|
+
} as CSSProperties)
|
|
39
|
+
: undefined;
|
|
40
|
+
|
|
26
41
|
return (
|
|
27
42
|
<div className="uds-modal-container">
|
|
28
43
|
{header ? <div className="uds-modal-header">{header}</div> : null}
|
|
29
|
-
<div className="uds-modal-body"
|
|
44
|
+
<div className="uds-modal-body" style={bodyStyle}>
|
|
45
|
+
{body}
|
|
46
|
+
</div>
|
|
30
47
|
{footer ? <div className="uds-modal-footer">{footer}</div> : null}
|
|
31
48
|
{!footer && footerButtons && footerButtons.length ? (
|
|
32
49
|
<div className="uds-modal-footer">
|
|
@@ -9,6 +9,10 @@ import { ModalContainer } from "./Container";
|
|
|
9
9
|
|
|
10
10
|
import type { ModalRootProps } from "../../types";
|
|
11
11
|
|
|
12
|
+
type ModalSurfaceStyle = CSSProperties & {
|
|
13
|
+
"--modal-panel-width"?: string | number;
|
|
14
|
+
};
|
|
15
|
+
|
|
12
16
|
/**
|
|
13
17
|
* 모달 Root; overlay 클릭 닫기와 상태 전환을 담당한다.
|
|
14
18
|
* @component
|
|
@@ -59,6 +63,17 @@ export function ModalRoot({
|
|
|
59
63
|
[index],
|
|
60
64
|
);
|
|
61
65
|
|
|
66
|
+
const surfaceStyle = useMemo<ModalSurfaceStyle>(() => {
|
|
67
|
+
const style: ModalSurfaceStyle = {};
|
|
68
|
+
if (typeof modalProps.width !== "undefined") {
|
|
69
|
+
style["--modal-panel-width"] =
|
|
70
|
+
typeof modalProps.width === "number"
|
|
71
|
+
? `${modalProps.width}px`
|
|
72
|
+
: modalProps.width;
|
|
73
|
+
}
|
|
74
|
+
return style;
|
|
75
|
+
}, [modalProps.width]);
|
|
76
|
+
|
|
62
77
|
return (
|
|
63
78
|
<div
|
|
64
79
|
className={clsx("uds-modal-root", className)}
|
|
@@ -73,14 +88,9 @@ export function ModalRoot({
|
|
|
73
88
|
role="dialog"
|
|
74
89
|
aria-modal="true"
|
|
75
90
|
onClick={stopPropagation}
|
|
91
|
+
style={surfaceStyle}
|
|
76
92
|
>
|
|
77
|
-
<ModalContainer
|
|
78
|
-
stackKey={stackKey}
|
|
79
|
-
header={modalProps.header}
|
|
80
|
-
body={modalProps.body}
|
|
81
|
-
footer={modalProps.footer}
|
|
82
|
-
footerButtons={modalProps.footerButtons}
|
|
83
|
-
/>
|
|
93
|
+
<ModalContainer stackKey={stackKey} {...modalProps} />
|
|
84
94
|
</div>
|
|
85
95
|
</div>
|
|
86
96
|
);
|
|
@@ -219,7 +219,10 @@
|
|
|
219
219
|
}
|
|
220
220
|
|
|
221
221
|
.uds-modal-dialog-body-content {
|
|
222
|
-
padding: var(
|
|
222
|
+
padding: var(
|
|
223
|
+
--modal-dialog-body-padding,
|
|
224
|
+
var(--spacing-padding-7, 20px) var(--spacing-padding-6, 16px)
|
|
225
|
+
);
|
|
223
226
|
text-align: center;
|
|
224
227
|
word-break: keep-all;
|
|
225
228
|
color: var(--modal-dialog-body-color);
|
|
@@ -45,6 +45,8 @@ export function createDialogModal({
|
|
|
45
45
|
cancel,
|
|
46
46
|
footer,
|
|
47
47
|
showDelay,
|
|
48
|
+
width,
|
|
49
|
+
padding,
|
|
48
50
|
}: DialogTemplateOptions): ModalState {
|
|
49
51
|
// confirm이 없을 때 기본 confirm 버튼을 생성한다.
|
|
50
52
|
const primary: ModalTemplateButtonSpec = confirm ?? {
|
|
@@ -118,6 +120,8 @@ export function createDialogModal({
|
|
|
118
120
|
footer,
|
|
119
121
|
// footerButtons가 비어 있으면 undefined로 넘겨 footer 렌더를 생략한다.
|
|
120
122
|
footerButtons: footerButtons.length ? footerButtons : undefined,
|
|
123
|
+
width,
|
|
124
|
+
padding,
|
|
121
125
|
},
|
|
122
126
|
};
|
|
123
127
|
}
|
package/src/modal/types/state.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
2
|
|
|
3
3
|
import type { ModalFooterButton } from "./footer";
|
|
4
|
+
import type { StyleSpacingType } from "@uniai-fe/util-functions";
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Modal 노출 상태 표현값.
|
|
@@ -13,6 +14,8 @@ export type ModalShowState = "init" | boolean;
|
|
|
13
14
|
* @property {ReactNode} [header] 헤더 콘텐츠
|
|
14
15
|
* @property {ReactNode} body 본문 콘텐츠
|
|
15
16
|
* @property {ReactNode} [footer] footer 콘텐츠
|
|
17
|
+
* @property {number | string} [width] 커스텀 width
|
|
18
|
+
* @property {StyleSpacingType} [padding] 커스텀 padding
|
|
16
19
|
*/
|
|
17
20
|
export type ModalSections = {
|
|
18
21
|
/**
|
|
@@ -27,6 +30,20 @@ export type ModalSections = {
|
|
|
27
30
|
* footer 콘텐츠
|
|
28
31
|
*/
|
|
29
32
|
footer?: ReactNode;
|
|
33
|
+
/**
|
|
34
|
+
* 커스텀 width
|
|
35
|
+
*/
|
|
36
|
+
width?: number | string;
|
|
37
|
+
/**
|
|
38
|
+
* 커스텀 padding
|
|
39
|
+
* @desc
|
|
40
|
+
* - number | string: 단일 값
|
|
41
|
+
* - [상하좌우]: 일괄적용 처리
|
|
42
|
+
* - [상하, 좌우]
|
|
43
|
+
* - [상, 좌우, 하]
|
|
44
|
+
* - [상, 우, 하, 좌]
|
|
45
|
+
*/
|
|
46
|
+
padding?: StyleSpacingType;
|
|
30
47
|
};
|
|
31
48
|
|
|
32
49
|
/**
|
|
@@ -34,6 +51,8 @@ export type ModalSections = {
|
|
|
34
51
|
* @property {ReactNode} [header] 헤더 콘텐츠 (@see ModalSections)
|
|
35
52
|
* @property {ReactNode} body 본문 콘텐츠 (@see ModalSections)
|
|
36
53
|
* @property {ReactNode} [footer] footer 콘텐츠 (@see ModalSections)
|
|
54
|
+
* @property {number | string} [width] 커스텀 width
|
|
55
|
+
* @property {StyleSpacingType} [padding] 커스텀 padding
|
|
37
56
|
* @property {ModalShowState} show 노출 상태
|
|
38
57
|
* @property {number} [showDelay] close 후 제거 지연(ms)
|
|
39
58
|
* @property {ModalFooterButton[]} [footerButtons] footer 버튼 스펙
|
|
@@ -5,6 +5,7 @@ import type {
|
|
|
5
5
|
ModalFooterButtonWidth,
|
|
6
6
|
} from "./footer";
|
|
7
7
|
import type { ModalState } from "./state";
|
|
8
|
+
import type { StyleSpacingType } from "@uniai-fe/util-functions";
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Dialog header 레이아웃.
|
|
@@ -52,6 +53,8 @@ export type ModalTemplateButtonSpec = {
|
|
|
52
53
|
* 템플릿 공통 옵션.
|
|
53
54
|
* @property {string} stackKey 모달 스택 키
|
|
54
55
|
* @property {number} [showDelay] close 후 제거 지연(ms)
|
|
56
|
+
* @property {number | string} [width] 커스텀 width
|
|
57
|
+
* @property {StyleSpacingType} [padding] 커스텀 padding
|
|
55
58
|
*/
|
|
56
59
|
type ModalTemplateBase = {
|
|
57
60
|
/**
|
|
@@ -62,6 +65,20 @@ type ModalTemplateBase = {
|
|
|
62
65
|
* close 후 제거 지연(ms)
|
|
63
66
|
*/
|
|
64
67
|
showDelay?: number;
|
|
68
|
+
/**
|
|
69
|
+
* 커스텀 width
|
|
70
|
+
*/
|
|
71
|
+
width?: number | string;
|
|
72
|
+
/**
|
|
73
|
+
* 커스텀 padding
|
|
74
|
+
* @desc
|
|
75
|
+
* - number | string: 단일 값
|
|
76
|
+
* - [상하좌우]: 일괄적용 처리
|
|
77
|
+
* - [상하, 좌우]
|
|
78
|
+
* - [상, 좌우, 하]
|
|
79
|
+
* - [상, 우, 하, 좌]
|
|
80
|
+
*/
|
|
81
|
+
padding?: StyleSpacingType;
|
|
65
82
|
};
|
|
66
83
|
|
|
67
84
|
/**
|
|
@@ -72,6 +89,8 @@ type ModalTemplateBase = {
|
|
|
72
89
|
* @property {ModalTemplateButtonSpec} [confirm] 확인 버튼 스펙
|
|
73
90
|
* @property {ModalTemplateButtonSpec} [cancel] 취소 버튼 스펙
|
|
74
91
|
* @property {ReactNode} [footer] 커스텀 footer
|
|
92
|
+
* @property {number | string} [width] 커스텀 width
|
|
93
|
+
* @property {StyleSpacingType} [padding] 커스텀 padding
|
|
75
94
|
*/
|
|
76
95
|
export type AlertTemplateOptions = ModalTemplateBase & {
|
|
77
96
|
/**
|
|
@@ -108,6 +127,8 @@ export type AlertTemplateOptions = ModalTemplateBase & {
|
|
|
108
127
|
* @property {ModalTemplateButtonSpec} [confirm] 확인 버튼 스펙
|
|
109
128
|
* @property {ModalTemplateButtonSpec} [cancel] 취소 버튼 스펙
|
|
110
129
|
* @property {ReactNode} [footer] 커스텀 footer
|
|
130
|
+
* @property {number | string} [width] 커스텀 width
|
|
131
|
+
* @property {StyleSpacingType} [padding] 커스텀 padding
|
|
111
132
|
*/
|
|
112
133
|
export type DialogTemplateOptions = ModalTemplateBase & {
|
|
113
134
|
/**
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
--uds-page-nav-list-padding-horizontal: 0rem;
|
|
18
18
|
--uds-page-nav-list-padding-vertical: var(--spacing-padding-9, 2.4rem);
|
|
19
|
-
--uds-page-nav-item-height: var(--theme-size-
|
|
19
|
+
--uds-page-nav-item-height: var(--theme-size-medium-2, 4.8rem);
|
|
20
20
|
--uds-page-nav-item-gap: var(--spacing-gap-6, 1.6rem);
|
|
21
21
|
--uds-page-nav-item-color-default: var(--color-label-standard);
|
|
22
22
|
--uds-page-nav-item-color-active: var(--color-primary-default);
|