@ncds/ui-admin 1.8.26-alpha.4 → 1.8.26-alpha.5
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/dist/cjs/assets/scripts/notification/FloatingNotification.js +23 -7
- package/dist/cjs/assets/scripts/notification/FullWidthNotification.js +14 -3
- package/dist/cjs/assets/scripts/notification/MessageNotification.js +3 -0
- package/dist/cjs/assets/scripts/notification/Notification.js +8 -2
- package/dist/cjs/assets/scripts/notification/messageTemplate.js +21 -5
- package/dist/cjs/constant/notification.js +8 -2
- package/dist/cjs/src/components/overlays/notification/FloatingNotification.js +10 -28
- package/dist/cjs/src/components/overlays/notification/FullWidthNotification.js +9 -24
- package/dist/cjs/src/components/overlays/notification/MessageNotification.js +12 -0
- package/dist/cjs/src/components/overlays/notification/MessageNotificationParts.js +5 -2
- package/dist/cjs/src/components/overlays/notification/Notification.js +1 -0
- package/dist/cjs/src/components/overlays/notification/__tests__/CalloutNotification.test.js +8 -2
- package/dist/cjs/src/components/overlays/notification/__tests__/Notification.test.js +176 -0
- package/dist/cjs/src/components/overlays/notification/useAutoClose.js +39 -0
- package/dist/cjs/src/utils/notification/__tests__/resolveAutoClose.test.js +44 -0
- package/dist/cjs/src/utils/notification/index.js +12 -0
- package/dist/cjs/src/utils/notification/resolveAutoClose.js +22 -0
- package/dist/esm/assets/scripts/notification/FloatingNotification.js +23 -7
- package/dist/esm/assets/scripts/notification/FullWidthNotification.js +14 -3
- package/dist/esm/assets/scripts/notification/MessageNotification.js +3 -0
- package/dist/esm/assets/scripts/notification/Notification.js +8 -2
- package/dist/esm/assets/scripts/notification/messageTemplate.js +21 -5
- package/dist/esm/constant/notification.js +7 -1
- package/dist/esm/src/components/overlays/notification/FloatingNotification.js +11 -29
- package/dist/esm/src/components/overlays/notification/FullWidthNotification.js +10 -25
- package/dist/esm/src/components/overlays/notification/MessageNotification.js +12 -0
- package/dist/esm/src/components/overlays/notification/MessageNotificationParts.js +5 -2
- package/dist/esm/src/components/overlays/notification/Notification.js +1 -0
- package/dist/esm/src/components/overlays/notification/__tests__/CalloutNotification.test.js +9 -3
- package/dist/esm/src/components/overlays/notification/__tests__/Notification.test.js +177 -1
- package/dist/esm/src/components/overlays/notification/useAutoClose.js +32 -0
- package/dist/esm/src/utils/notification/__tests__/resolveAutoClose.test.js +42 -0
- package/dist/esm/src/utils/notification/index.js +1 -0
- package/dist/esm/src/utils/notification/resolveAutoClose.js +15 -0
- package/dist/temp/assets/scripts/notification/FloatingNotification.js +10 -6
- package/dist/temp/assets/scripts/notification/FullWidthNotification.js +8 -5
- package/dist/temp/assets/scripts/notification/MessageNotification.js +3 -1
- package/dist/temp/assets/scripts/notification/Notification.js +7 -1
- package/dist/temp/assets/scripts/notification/const/types.d.ts +7 -0
- package/dist/temp/assets/scripts/notification/messageTemplate.d.ts +1 -0
- package/dist/temp/assets/scripts/notification/messageTemplate.js +19 -9
- package/dist/temp/constant/notification.d.ts +6 -0
- package/dist/temp/constant/notification.js +6 -0
- package/dist/temp/src/components/overlays/notification/FloatingNotification.d.ts +8 -0
- package/dist/temp/src/components/overlays/notification/FloatingNotification.js +6 -29
- package/dist/temp/src/components/overlays/notification/FullWidthNotification.d.ts +7 -0
- package/dist/temp/src/components/overlays/notification/FullWidthNotification.js +6 -25
- package/dist/temp/src/components/overlays/notification/MessageNotification.d.ts +12 -0
- package/dist/temp/src/components/overlays/notification/MessageNotification.js +8 -2
- package/dist/temp/src/components/overlays/notification/MessageNotificationParts.d.ts +2 -1
- package/dist/temp/src/components/overlays/notification/MessageNotificationParts.js +5 -3
- package/dist/temp/src/components/overlays/notification/Notification.d.ts +14 -1
- package/dist/temp/src/components/overlays/notification/Notification.js +1 -1
- package/dist/temp/src/components/overlays/notification/__tests__/CalloutNotification.test.js +8 -1
- package/dist/temp/src/components/overlays/notification/__tests__/Notification.test.js +128 -1
- package/dist/temp/src/components/overlays/notification/useAutoClose.d.ts +15 -0
- package/dist/temp/src/components/overlays/notification/useAutoClose.js +25 -0
- package/dist/temp/src/utils/notification/__tests__/resolveAutoClose.test.d.ts +1 -0
- package/dist/temp/src/utils/notification/__tests__/resolveAutoClose.test.js +22 -0
- package/dist/temp/src/utils/notification/index.d.ts +1 -0
- package/dist/temp/src/utils/notification/index.js +1 -0
- package/dist/temp/src/utils/notification/resolveAutoClose.d.ts +14 -0
- package/dist/temp/src/utils/notification/resolveAutoClose.js +12 -0
- package/dist/types/assets/scripts/notification/const/types.d.ts +7 -0
- package/dist/types/assets/scripts/notification/messageTemplate.d.ts +1 -0
- package/dist/types/constant/notification.d.ts +6 -0
- package/dist/types/src/components/overlays/notification/FloatingNotification.d.ts +8 -0
- package/dist/types/src/components/overlays/notification/FullWidthNotification.d.ts +7 -0
- package/dist/types/src/components/overlays/notification/MessageNotification.d.ts +12 -0
- package/dist/types/src/components/overlays/notification/MessageNotificationParts.d.ts +2 -1
- package/dist/types/src/components/overlays/notification/Notification.d.ts +14 -1
- package/dist/types/src/components/overlays/notification/useAutoClose.d.ts +15 -0
- package/dist/types/src/utils/notification/__tests__/resolveAutoClose.test.d.ts +1 -0
- package/dist/types/src/utils/notification/index.d.ts +1 -0
- package/dist/types/src/utils/notification/resolveAutoClose.d.ts +14 -0
- package/package.json +1 -1
|
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.FloatingNotification = void 0;
|
|
7
7
|
var _breakpoint = require("../../../src/constant/breakpoint");
|
|
8
|
+
var _notification = require("../../../src/utils/notification");
|
|
8
9
|
var _featuredIcon = require("../featuredIcon");
|
|
9
10
|
var _ButtonCloseX = require("../shared/ButtonCloseX");
|
|
10
11
|
var _sanitize = require("../utils/sanitize");
|
|
@@ -16,9 +17,13 @@ class FloatingNotification {
|
|
|
16
17
|
color: 'neutral',
|
|
17
18
|
className: '',
|
|
18
19
|
actions: [],
|
|
19
|
-
|
|
20
|
+
hideCloseButton: false,
|
|
20
21
|
supportingText: undefined,
|
|
21
|
-
...options
|
|
22
|
+
...options,
|
|
23
|
+
autoClose: (0, _notification.resolveAutoClose)({
|
|
24
|
+
autoClose: options.autoClose,
|
|
25
|
+
hideCloseButton: options.hideCloseButton
|
|
26
|
+
})
|
|
22
27
|
};
|
|
23
28
|
this.element = this.createElement();
|
|
24
29
|
this.bindEvents();
|
|
@@ -32,7 +37,8 @@ class FloatingNotification {
|
|
|
32
37
|
color,
|
|
33
38
|
className,
|
|
34
39
|
actions,
|
|
35
|
-
onClose
|
|
40
|
+
onClose,
|
|
41
|
+
hideCloseButton
|
|
36
42
|
} = this.options;
|
|
37
43
|
// 플로팅 알림에서 info 색상 사용 시 neutral로 대체
|
|
38
44
|
let actualColor = color;
|
|
@@ -61,6 +67,7 @@ class FloatingNotification {
|
|
|
61
67
|
supportingText,
|
|
62
68
|
actions,
|
|
63
69
|
onClose,
|
|
70
|
+
hideCloseButton,
|
|
64
71
|
isMobile: mobile
|
|
65
72
|
}));
|
|
66
73
|
// FeaturedIcon을 container에 추가
|
|
@@ -78,6 +85,7 @@ class FloatingNotification {
|
|
|
78
85
|
supportingText,
|
|
79
86
|
actions,
|
|
80
87
|
onClose,
|
|
88
|
+
hideCloseButton,
|
|
81
89
|
isMobile
|
|
82
90
|
} = params;
|
|
83
91
|
return `
|
|
@@ -92,12 +100,20 @@ class FloatingNotification {
|
|
|
92
100
|
</div>
|
|
93
101
|
</div>
|
|
94
102
|
</div>
|
|
95
|
-
${this.renderCloseButton(
|
|
103
|
+
${this.renderCloseButton({
|
|
104
|
+
onClose,
|
|
105
|
+
isMobile,
|
|
106
|
+
hideCloseButton
|
|
107
|
+
})}
|
|
96
108
|
`;
|
|
97
109
|
}
|
|
98
|
-
renderCloseButton(
|
|
99
|
-
|
|
100
|
-
|
|
110
|
+
renderCloseButton(params) {
|
|
111
|
+
const {
|
|
112
|
+
onClose,
|
|
113
|
+
isMobile = false,
|
|
114
|
+
hideCloseButton = false
|
|
115
|
+
} = params;
|
|
116
|
+
if (!onClose || hideCloseButton) return '';
|
|
101
117
|
const size = _const.getSizes.closeButton(isMobile);
|
|
102
118
|
return (0, _ButtonCloseX.ButtonCloseX)(size, 'light', _const.CLASS_NAMES.FLOATING.CLOSE_BUTTON, '알림 닫기', onClose);
|
|
103
119
|
}
|
|
@@ -15,6 +15,7 @@ class FullWidthNotification {
|
|
|
15
15
|
className: '',
|
|
16
16
|
actions: [],
|
|
17
17
|
autoClose: 0,
|
|
18
|
+
hideCloseButton: false,
|
|
18
19
|
supportingText: undefined,
|
|
19
20
|
...options
|
|
20
21
|
};
|
|
@@ -30,6 +31,7 @@ class FullWidthNotification {
|
|
|
30
31
|
className,
|
|
31
32
|
actions,
|
|
32
33
|
onClose,
|
|
34
|
+
hideCloseButton,
|
|
33
35
|
supportTextLink,
|
|
34
36
|
supportTextLinkTarget,
|
|
35
37
|
onHidePermanently,
|
|
@@ -43,6 +45,7 @@ class FullWidthNotification {
|
|
|
43
45
|
supportingText,
|
|
44
46
|
actions,
|
|
45
47
|
onClose,
|
|
48
|
+
hideCloseButton,
|
|
46
49
|
supportTextLink,
|
|
47
50
|
onHidePermanently,
|
|
48
51
|
hidePermanentlyLabel
|
|
@@ -57,6 +60,7 @@ class FullWidthNotification {
|
|
|
57
60
|
supportingText,
|
|
58
61
|
actions,
|
|
59
62
|
onClose,
|
|
63
|
+
hideCloseButton,
|
|
60
64
|
supportTextLink,
|
|
61
65
|
onHidePermanently,
|
|
62
66
|
hidePermanentlyLabel
|
|
@@ -74,7 +78,10 @@ class FullWidthNotification {
|
|
|
74
78
|
<div class="${_const.CLASS_NAMES.FULL_WIDTH.ACTIONS_CONTAINER}">
|
|
75
79
|
${actions && actions.length > 0 ? (0, _utils.renderActions)(actions, _const.CLASS_NAMES.FULL_WIDTH.ACTIONS) : ''}
|
|
76
80
|
${this.renderHidePermanentlyButton(onHidePermanently, hidePermanentlyLabel)}
|
|
77
|
-
${this.renderCloseButton(
|
|
81
|
+
${this.renderCloseButton({
|
|
82
|
+
onClose,
|
|
83
|
+
hideCloseButton
|
|
84
|
+
})}
|
|
78
85
|
</div>
|
|
79
86
|
</div>
|
|
80
87
|
</div>
|
|
@@ -95,8 +102,12 @@ class FullWidthNotification {
|
|
|
95
102
|
</button>
|
|
96
103
|
`;
|
|
97
104
|
}
|
|
98
|
-
renderCloseButton(
|
|
99
|
-
|
|
105
|
+
renderCloseButton(params) {
|
|
106
|
+
const {
|
|
107
|
+
onClose,
|
|
108
|
+
hideCloseButton = false
|
|
109
|
+
} = params;
|
|
110
|
+
if (!onClose || hideCloseButton) return '';
|
|
100
111
|
return `
|
|
101
112
|
<button type="button" class="${_const.CLASS_NAMES.FULL_WIDTH.CLOSE_BUTTON}" aria-label="알림 닫기">
|
|
102
113
|
${_const.SVG_ICONS['x-close'](_const.FULL_WIDTH_SIZES.CLOSE_BUTTON)}
|
|
@@ -16,6 +16,7 @@ class MessageNotification {
|
|
|
16
16
|
className: '',
|
|
17
17
|
actions: [],
|
|
18
18
|
autoClose: 0,
|
|
19
|
+
hideCloseButton: false,
|
|
19
20
|
supportingText: undefined,
|
|
20
21
|
...options
|
|
21
22
|
};
|
|
@@ -31,6 +32,7 @@ class MessageNotification {
|
|
|
31
32
|
className,
|
|
32
33
|
actions,
|
|
33
34
|
onClose,
|
|
35
|
+
hideCloseButton,
|
|
34
36
|
onHidePermanently,
|
|
35
37
|
hidePermanentlyLabel,
|
|
36
38
|
variant,
|
|
@@ -50,6 +52,7 @@ class MessageNotification {
|
|
|
50
52
|
color: actualColor,
|
|
51
53
|
actions,
|
|
52
54
|
onClose,
|
|
55
|
+
hideCloseButton,
|
|
53
56
|
onHidePermanently,
|
|
54
57
|
hidePermanentlyLabel
|
|
55
58
|
}));
|
|
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.NcuaNotification = void 0;
|
|
7
|
+
var _notification = require("../../../src/utils/notification");
|
|
7
8
|
var _FloatingNotification = require("./FloatingNotification");
|
|
8
9
|
var _FullWidthNotification = require("./FullWidthNotification");
|
|
9
10
|
var _MessageNotification = require("./MessageNotification");
|
|
@@ -79,8 +80,13 @@ class NcuaNotification {
|
|
|
79
80
|
supportingText,
|
|
80
81
|
color,
|
|
81
82
|
type: 'floating',
|
|
82
|
-
|
|
83
|
-
|
|
83
|
+
...options,
|
|
84
|
+
// 명시 autoClose > 색상별 기본값 > (floating 이고 hideCloseButton 이면 3초). neutral 은 기본 0 이라 세 번째 분기가 필요.
|
|
85
|
+
autoClose: (0, _notification.resolveAutoClose)({
|
|
86
|
+
autoClose: options?.autoClose,
|
|
87
|
+
hideCloseButton: (options?.type ?? 'floating') === 'floating' && options?.hideCloseButton,
|
|
88
|
+
fallback: autoCloseMap[color]
|
|
89
|
+
})
|
|
84
90
|
});
|
|
85
91
|
}
|
|
86
92
|
// 클래스를 생성하지 않고도 기본 floating 알림 생성을 하기 위한 함수들
|
|
@@ -25,6 +25,7 @@ function buildMessageTemplate(params) {
|
|
|
25
25
|
color,
|
|
26
26
|
actions,
|
|
27
27
|
onClose,
|
|
28
|
+
hideCloseButton,
|
|
28
29
|
onHidePermanently,
|
|
29
30
|
hidePermanentlyLabel
|
|
30
31
|
} = params;
|
|
@@ -40,6 +41,7 @@ function buildMessageTemplate(params) {
|
|
|
40
41
|
${renderActionsContainer({
|
|
41
42
|
actions,
|
|
42
43
|
onClose,
|
|
44
|
+
hideCloseButton,
|
|
43
45
|
onHidePermanently,
|
|
44
46
|
hidePermanentlyLabel,
|
|
45
47
|
color
|
|
@@ -57,6 +59,7 @@ function renderActionsContainer(params) {
|
|
|
57
59
|
const {
|
|
58
60
|
actions,
|
|
59
61
|
onClose,
|
|
62
|
+
hideCloseButton,
|
|
60
63
|
onHidePermanently,
|
|
61
64
|
hidePermanentlyLabel,
|
|
62
65
|
color
|
|
@@ -64,6 +67,7 @@ function renderActionsContainer(params) {
|
|
|
64
67
|
const actionsHtml = (0, _utils.renderActions)(actions ?? [], _const.CLASS_NAMES.MESSAGE.ACTIONS, ACTION_BUTTON_SIZE);
|
|
65
68
|
const footerHtml = renderFooterContainer({
|
|
66
69
|
onClose,
|
|
70
|
+
hideCloseButton,
|
|
67
71
|
onHidePermanently,
|
|
68
72
|
hidePermanentlyLabel,
|
|
69
73
|
color
|
|
@@ -75,15 +79,23 @@ function renderActionsContainer(params) {
|
|
|
75
79
|
function renderFooterContainer(params) {
|
|
76
80
|
const {
|
|
77
81
|
onClose,
|
|
82
|
+
hideCloseButton,
|
|
78
83
|
onHidePermanently,
|
|
79
84
|
hidePermanentlyLabel,
|
|
80
85
|
color
|
|
81
86
|
} = params;
|
|
82
|
-
|
|
87
|
+
// footer 컨테이너와 닫기 버튼이 같은 판정을 보게 해 빈 footer 가 남지 않게 한다.
|
|
88
|
+
// cf. React `MessageNotificationParts.tsx` 의 showCloseButton — 두 구현이 같은 판정을 유지해야 한다.
|
|
89
|
+
const showCloseButton = Boolean(onClose) && !hideCloseButton;
|
|
90
|
+
if (!onHidePermanently && !showCloseButton) return '';
|
|
83
91
|
return `
|
|
84
92
|
<div class="${_const.CLASS_NAMES.MESSAGE.FOOTER_CONTAINER}">
|
|
85
93
|
${renderHidePermanentlyButton(onHidePermanently, hidePermanentlyLabel)}
|
|
86
|
-
${renderCloseButton(
|
|
94
|
+
${renderCloseButton({
|
|
95
|
+
onClose,
|
|
96
|
+
hideCloseButton,
|
|
97
|
+
color
|
|
98
|
+
})}
|
|
87
99
|
</div>
|
|
88
100
|
`;
|
|
89
101
|
}
|
|
@@ -106,9 +118,13 @@ function renderHidePermanentlyButton(onHidePermanently, hidePermanentlyLabel) {
|
|
|
106
118
|
* 닫기(X) 버튼. 아이콘 색은 React `<XClose color>`와 같이 svg 의 `color` 속성으로 주고
|
|
107
119
|
* path 는 `stroke="currentColor"`로 상속받는다 — 두 구현이 같은 마크업을 낸다.
|
|
108
120
|
*/
|
|
109
|
-
function renderCloseButton(
|
|
110
|
-
|
|
111
|
-
|
|
121
|
+
function renderCloseButton(params) {
|
|
122
|
+
const {
|
|
123
|
+
onClose,
|
|
124
|
+
hideCloseButton = false,
|
|
125
|
+
color = 'neutral'
|
|
126
|
+
} = params;
|
|
127
|
+
if (!onClose || hideCloseButton) return '';
|
|
112
128
|
const iconColor = _notification.MESSAGE_CLOSE_ICON_COLOR[color];
|
|
113
129
|
return `
|
|
114
130
|
<button type="button" class="${_const.CLASS_NAMES.MESSAGE.CLOSE_BUTTON}" aria-label="알림 닫기">
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.MESSAGE_CLOSE_ICON_COLOR = exports.HIDE_PERMANENTLY_LABEL = void 0;
|
|
6
|
+
exports.MESSAGE_CLOSE_ICON_COLOR = exports.HIDE_PERMANENTLY_LABEL = exports.HIDE_CLOSE_BUTTON_AUTO_CLOSE_MS = void 0;
|
|
7
7
|
var _color = require("./color");
|
|
8
8
|
/**
|
|
9
9
|
* 다시보지 않기 버튼의 타입별 기본 문구.
|
|
@@ -32,4 +32,10 @@ const MESSAGE_CLOSE_ICON_COLOR = exports.MESSAGE_CLOSE_ICON_COLOR = {
|
|
|
32
32
|
warning: _color.COLOR.orange500,
|
|
33
33
|
success: _color.COLOR.green600,
|
|
34
34
|
info: _color.COLOR.violet600
|
|
35
|
-
};
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* floating(토스트)에서 `hideCloseButton`인데 `autoClose`를 지정하지 않았을 때 적용되는 자동 닫힘 시간(ms).
|
|
38
|
+
* 닫기 버튼이 없는 토스트가 영구히 남지 않게 한다 — DES-SPEC-027 §5.3 Toast Alert 3초.
|
|
39
|
+
* full-width · message 는 부모가 언마운트로 닫으므로 적용하지 않는다.
|
|
40
|
+
*/
|
|
41
|
+
const HIDE_CLOSE_BUTTON_AUTO_CLOSE_MS = exports.HIDE_CLOSE_BUTTON_AUTO_CLOSE_MS = 3000;
|
|
@@ -15,6 +15,7 @@ var _ButtonCloseX = require("../../action/button/ButtonCloseX");
|
|
|
15
15
|
var _FeaturedIcon = require("../../image-and-icons/featured-icon/FeaturedIcon");
|
|
16
16
|
var _host = require("./host");
|
|
17
17
|
var _NotificationActionButtons = require("./NotificationActionButtons");
|
|
18
|
+
var _useAutoClose = require("./useAutoClose");
|
|
18
19
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
19
20
|
// 호스트 싱글톤은 vanilla/React 양쪽이 동일한 함수를 공유한다 — host.ts 가 가까운 진입점 역할을
|
|
20
21
|
// 하므로 React 컴포넌트는 deep relative path 로 vanilla internals 를 직접 import 하지 않는다.
|
|
@@ -73,13 +74,19 @@ const FloatingNotification = exports.FloatingNotification = /*#__PURE__*/(0, _re
|
|
|
73
74
|
supportingText,
|
|
74
75
|
color = 'neutral',
|
|
75
76
|
onClose,
|
|
77
|
+
hideCloseButton = false,
|
|
76
78
|
className,
|
|
77
79
|
actions,
|
|
78
|
-
autoClose
|
|
80
|
+
autoClose,
|
|
79
81
|
portal = false,
|
|
80
82
|
...rest
|
|
81
83
|
} = _ref;
|
|
82
|
-
|
|
84
|
+
// floating 은 닫기 버튼이 없는데 autoClose 도 없으면 영구히 남으므로 기본 3초를 준다.
|
|
85
|
+
const shouldRemove = (0, _useAutoClose.useAutoClose)({
|
|
86
|
+
autoClose,
|
|
87
|
+
hideCloseButton,
|
|
88
|
+
onClose
|
|
89
|
+
});
|
|
83
90
|
const featuredIconProps = {
|
|
84
91
|
icon: iconMap[color] || _uiAdminIcon.Pin02,
|
|
85
92
|
size: 'sm',
|
|
@@ -89,31 +96,6 @@ const FloatingNotification = exports.FloatingNotification = /*#__PURE__*/(0, _re
|
|
|
89
96
|
const isMobile = (0, _useMediaQuery.useMediaQuery)(_breakpoint.MEDIA_QUERY.mobile, {
|
|
90
97
|
onMatched: onClose
|
|
91
98
|
});
|
|
92
|
-
// onClose 는 매 렌더 새 함수 ref 일 수 있으므로 ref 로 latest 만 보관.
|
|
93
|
-
// → autoClose 타이머 effect 의 deps 에서 onClose 를 빼서 타이머 재시작 회피.
|
|
94
|
-
// render 본문에서 직접 할당 — useEffect 로 미루면 같은 commit 안에서 fire 되는 타이머가 stale onClose 를 볼 위험.
|
|
95
|
-
const onCloseRef = (0, _react.useRef)(onClose);
|
|
96
|
-
onCloseRef.current = onClose;
|
|
97
|
-
// autoClose 타이머 관리
|
|
98
|
-
const timerRef = (0, _react.useRef)(null);
|
|
99
|
-
// onClose 는 onCloseRef 로 latest 만 추적하므로 deps 에서 제외 (의도된 패턴).
|
|
100
|
-
(0, _react.useEffect)(() => {
|
|
101
|
-
// autoClose 가 0 보다 크면 타이머 설정.
|
|
102
|
-
if (autoClose > 0) {
|
|
103
|
-
timerRef.current = setTimeout(() => {
|
|
104
|
-
onCloseRef.current?.();
|
|
105
|
-
// DOM 에서 바로 제거
|
|
106
|
-
setShouldRemove(true);
|
|
107
|
-
}, autoClose);
|
|
108
|
-
}
|
|
109
|
-
// cleanup: 컴포넌트 언마운트 또는 autoClose 변경 시 타이머 정리
|
|
110
|
-
return () => {
|
|
111
|
-
if (timerRef.current) {
|
|
112
|
-
clearTimeout(timerRef.current);
|
|
113
|
-
timerRef.current = null;
|
|
114
|
-
}
|
|
115
|
-
};
|
|
116
|
-
}, [autoClose]);
|
|
117
99
|
// portal=true 일 때만 호스트가 필요하다.
|
|
118
100
|
const host = useMountFloatingNotificationHost(portal);
|
|
119
101
|
// a11y — 카드 root 의 role 과 제목/본문 ID. 색상에 따라 alert(error/warning) / status(나머지) 로 분기.
|
|
@@ -163,7 +145,7 @@ const FloatingNotification = exports.FloatingNotification = /*#__PURE__*/(0, _re
|
|
|
163
145
|
})]
|
|
164
146
|
})]
|
|
165
147
|
})
|
|
166
|
-
}), onClose && (0, _jsxRuntime.jsx)(_ButtonCloseX.ButtonCloseX, {
|
|
148
|
+
}), onClose && !hideCloseButton && (0, _jsxRuntime.jsx)(_ButtonCloseX.ButtonCloseX, {
|
|
167
149
|
theme: "light",
|
|
168
150
|
className: "ncua-floating-notification__close-button",
|
|
169
151
|
size: isMobile ? 'sm' : 'xs',
|
|
@@ -13,6 +13,7 @@ var _notification = require("../../../../constant/notification");
|
|
|
13
13
|
var _url = require("../../../utils/url");
|
|
14
14
|
var _linkTarget = require("./linkTarget");
|
|
15
15
|
var _NotificationActionButtons = require("./NotificationActionButtons");
|
|
16
|
+
var _useAutoClose = require("./useAutoClose");
|
|
16
17
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
17
18
|
const iconMap = {
|
|
18
19
|
neutral: _uiAdminIcon.MessageChatSquare,
|
|
@@ -34,43 +35,27 @@ const FullWidthNotification = exports.FullWidthNotification = /*#__PURE__*/(0, _
|
|
|
34
35
|
supportingText,
|
|
35
36
|
color = 'neutral',
|
|
36
37
|
onClose,
|
|
38
|
+
hideCloseButton = false,
|
|
37
39
|
className,
|
|
38
40
|
actions,
|
|
39
|
-
autoClose
|
|
41
|
+
autoClose,
|
|
40
42
|
supportTextLink,
|
|
41
43
|
supportTextLinkTarget,
|
|
42
44
|
onHidePermanently,
|
|
43
45
|
hidePermanentlyLabel = _notification.HIDE_PERMANENTLY_LABEL.fullWidth,
|
|
44
46
|
...rest
|
|
45
47
|
} = _ref;
|
|
46
|
-
|
|
48
|
+
// full-width 는 부모가 언마운트로 닫으므로 hideCloseButton 기본 autoClose 를 적용하지 않는다.
|
|
49
|
+
const shouldRemove = (0, _useAutoClose.useAutoClose)({
|
|
50
|
+
autoClose,
|
|
51
|
+
onClose
|
|
52
|
+
});
|
|
47
53
|
// unsafe URL(javascript: 등)이면 링크 없이 텍스트만 렌더한다 — Vanilla `renderSupportingText` 와 같은 정책.
|
|
48
54
|
const safeSupportTextLink = supportTextLink && (0, _url.isSafeUrl)(supportTextLink) ? supportTextLink : undefined;
|
|
49
55
|
const closeIconSize = {
|
|
50
56
|
width: 20,
|
|
51
57
|
height: 20
|
|
52
58
|
};
|
|
53
|
-
// autoClose 타이머 관리
|
|
54
|
-
const timerRef = (0, _react.useRef)(null);
|
|
55
|
-
(0, _react.useEffect)(() => {
|
|
56
|
-
// autoClose가 0보다 크면 무조건 타이머 설정
|
|
57
|
-
if (autoClose > 0) {
|
|
58
|
-
timerRef.current = setTimeout(() => {
|
|
59
|
-
if (onClose) {
|
|
60
|
-
onClose();
|
|
61
|
-
}
|
|
62
|
-
// DOM에서 바로 제거
|
|
63
|
-
setShouldRemove(true);
|
|
64
|
-
}, autoClose);
|
|
65
|
-
}
|
|
66
|
-
// cleanup 함수: 컴포넌트 언마운트 시 타이머 정리
|
|
67
|
-
return () => {
|
|
68
|
-
if (timerRef.current) {
|
|
69
|
-
clearTimeout(timerRef.current);
|
|
70
|
-
timerRef.current = null;
|
|
71
|
-
}
|
|
72
|
-
};
|
|
73
|
-
}, [autoClose, onClose]);
|
|
74
59
|
// DOM에서 완전히 제거
|
|
75
60
|
if (shouldRemove) {
|
|
76
61
|
return null;
|
|
@@ -124,7 +109,7 @@ const FullWidthNotification = exports.FullWidthNotification = /*#__PURE__*/(0, _
|
|
|
124
109
|
className: (0, _classnames.default)('ncua-notification__action-button', 'ncua-notification__action-button--text', 'ncua-full-width-notification__link'),
|
|
125
110
|
onClick: onHidePermanently,
|
|
126
111
|
children: hidePermanentlyLabel
|
|
127
|
-
}), onClose && (0, _jsxRuntime.jsx)("button", {
|
|
112
|
+
}), onClose && !hideCloseButton && (0, _jsxRuntime.jsx)("button", {
|
|
128
113
|
type: "button",
|
|
129
114
|
className: "ncua-full-width-notification__close-button",
|
|
130
115
|
onClick: onClose,
|
|
@@ -10,6 +10,7 @@ var _classnames = _interopRequireDefault(require("classnames"));
|
|
|
10
10
|
var _react = require("react");
|
|
11
11
|
var _notification = require("../../../../constant/notification");
|
|
12
12
|
var _MessageNotificationParts = require("./MessageNotificationParts");
|
|
13
|
+
var _useAutoClose = require("./useAutoClose");
|
|
13
14
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
14
15
|
const iconMap = {
|
|
15
16
|
neutral: _uiAdminIcon.Pin02,
|
|
@@ -26,6 +27,8 @@ const MessageNotification = exports.MessageNotification = /*#__PURE__*/(0, _reac
|
|
|
26
27
|
icon: Icon,
|
|
27
28
|
color = 'neutral',
|
|
28
29
|
onClose,
|
|
30
|
+
hideCloseButton = false,
|
|
31
|
+
autoClose,
|
|
29
32
|
className,
|
|
30
33
|
actions,
|
|
31
34
|
onHidePermanently,
|
|
@@ -40,6 +43,14 @@ const MessageNotification = exports.MessageNotification = /*#__PURE__*/(0, _reac
|
|
|
40
43
|
const validColor = !isBlock && color === 'info' ? 'neutral' : color;
|
|
41
44
|
// FeaturedIcon 에는 info 색이 없다. block+info 의 violet 톤은 message SCSS 가 덮어쓴다.
|
|
42
45
|
const featuredIconColor = validColor === 'info' ? 'neutral' : validColor;
|
|
46
|
+
// message 는 부모가 언마운트로 닫으므로 hideCloseButton 기본 autoClose 를 적용하지 않는다.
|
|
47
|
+
const shouldRemove = (0, _useAutoClose.useAutoClose)({
|
|
48
|
+
autoClose,
|
|
49
|
+
onClose
|
|
50
|
+
});
|
|
51
|
+
if (shouldRemove) {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
43
54
|
return (0, _jsxRuntime.jsx)("div", {
|
|
44
55
|
ref: ref,
|
|
45
56
|
className: (0, _classnames.default)('ncua-message-notification', `ncua-message-notification--${validColor}`, {
|
|
@@ -62,6 +73,7 @@ const MessageNotification = exports.MessageNotification = /*#__PURE__*/(0, _reac
|
|
|
62
73
|
}), (0, _jsxRuntime.jsx)(_MessageNotificationParts.MessageNotificationActions, {
|
|
63
74
|
actions: actions,
|
|
64
75
|
onClose: onClose,
|
|
76
|
+
hideCloseButton: hideCloseButton,
|
|
65
77
|
onHidePermanently: onHidePermanently,
|
|
66
78
|
hidePermanentlyLabel: hidePermanentlyLabel,
|
|
67
79
|
closeIconColor: _notification.MESSAGE_CLOSE_ICON_COLOR[validColor]
|
|
@@ -61,12 +61,15 @@ const MessageNotificationActions = _ref2 => {
|
|
|
61
61
|
let {
|
|
62
62
|
actions,
|
|
63
63
|
onClose,
|
|
64
|
+
hideCloseButton = false,
|
|
64
65
|
onHidePermanently,
|
|
65
66
|
hidePermanentlyLabel = _notification.HIDE_PERMANENTLY_LABEL.message,
|
|
66
67
|
closeIconColor
|
|
67
68
|
} = _ref2;
|
|
68
69
|
const hasActions = Boolean(actions?.length);
|
|
69
|
-
|
|
70
|
+
// footer 컨테이너와 닫기 버튼이 같은 판정을 보게 해 빈 footer 가 남지 않게 한다.
|
|
71
|
+
const showCloseButton = Boolean(onClose) && !hideCloseButton;
|
|
72
|
+
const hasFooter = Boolean(onHidePermanently) || showCloseButton;
|
|
70
73
|
if (!hasActions && !hasFooter) return null;
|
|
71
74
|
return (0, _jsxRuntime.jsxs)("div", {
|
|
72
75
|
className: "ncua-message-notification__actions-container",
|
|
@@ -82,7 +85,7 @@ const MessageNotificationActions = _ref2 => {
|
|
|
82
85
|
className: "ncua-notification__action-button ncua-message-notification__hide-link",
|
|
83
86
|
onClick: onHidePermanently,
|
|
84
87
|
children: hidePermanentlyLabel
|
|
85
|
-
}),
|
|
88
|
+
}), showCloseButton && (0, _jsxRuntime.jsx)("button", {
|
|
86
89
|
type: "button",
|
|
87
90
|
className: "ncua-message-notification__close-button",
|
|
88
91
|
onClick: onClose,
|
|
@@ -57,6 +57,7 @@ const Notification = exports.Notification = /*#__PURE__*/(0, _react.forwardRef)(
|
|
|
57
57
|
actions: _actions,
|
|
58
58
|
autoClose: _autoClose,
|
|
59
59
|
onClose: _onClose,
|
|
60
|
+
hideCloseButton: _hideCloseButton,
|
|
60
61
|
onHidePermanently: _onHidePermanently,
|
|
61
62
|
hidePermanentlyLabel: _hidePermanentlyLabel,
|
|
62
63
|
portal: _portal,
|
|
@@ -46,6 +46,7 @@ const renderNotification = function () {
|
|
|
46
46
|
container?.remove();
|
|
47
47
|
root = null;
|
|
48
48
|
container = null;
|
|
49
|
+
_vitest.vi.restoreAllMocks();
|
|
49
50
|
});
|
|
50
51
|
(0, _vitest.describe)('CalloutNotification — width prop', () => {
|
|
51
52
|
(0, _vitest.it)('width 미지정 시 너비 클래스를 붙이지 않는다 (부모 너비를 채우는 기본 스타일 유지)', () => {
|
|
@@ -94,6 +95,7 @@ const renderNotification = function () {
|
|
|
94
95
|
});
|
|
95
96
|
// Notification 의 callout 분기가 제외하는 prop 전체. 여기 누락된 prop 은 DOM 속성으로 출력된다.
|
|
96
97
|
(0, _vitest.it)('callout 이 지원하지 않는 prop 은 DOM 속성으로 새지 않는다', () => {
|
|
98
|
+
const consoleError = _vitest.vi.spyOn(console, 'error').mockImplementation(() => undefined);
|
|
97
99
|
const element = renderNotification({
|
|
98
100
|
icon: () => null,
|
|
99
101
|
supportingText: '보조 문구',
|
|
@@ -106,12 +108,16 @@ const renderNotification = function () {
|
|
|
106
108
|
portal: true,
|
|
107
109
|
onClose: () => undefined,
|
|
108
110
|
onHidePermanently: () => undefined,
|
|
109
|
-
hidePermanentlyLabel: '다시 보지 않기'
|
|
111
|
+
hidePermanentlyLabel: '다시 보지 않기',
|
|
112
|
+
hideCloseButton: true
|
|
110
113
|
});
|
|
111
|
-
for (const attr of ['icon', 'supportingtext', 'supporttextlink', 'actions', 'autoclose', 'portal', 'onclose', 'onhidepermanently', 'hidepermanentlylabel']) {
|
|
114
|
+
for (const attr of ['icon', 'supportingtext', 'supporttextlink', 'actions', 'autoclose', 'portal', 'onclose', 'onhidepermanently', 'hidepermanentlylabel', 'hideclosebutton']) {
|
|
112
115
|
(0, _vitest.expect)(element.hasAttribute(attr), attr).toBe(false);
|
|
113
116
|
}
|
|
114
117
|
(0, _vitest.expect)(element.textContent).toBe('안내 문구');
|
|
118
|
+
// 불리언 true 는 React 가 미지 속성으로 출력하지 않아 hasAttribute 로는 누수를 못 잡는다 — 경고 로그로 검출한다.
|
|
119
|
+
const leaked = consoleError.mock.calls.some(call => call.some(arg => String(arg).includes('hideCloseButton')));
|
|
120
|
+
(0, _vitest.expect)(leaked).toBe(false);
|
|
115
121
|
});
|
|
116
122
|
(0, _vitest.it)('ref 를 callout 루트 엘리먼트로 전달한다', () => {
|
|
117
123
|
let captured = null;
|