@ncds/ui-admin 1.8.21-alpha.5 → 1.8.21-alpha.7
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/FullWidthNotification.js +17 -6
- package/dist/cjs/assets/scripts/notification/MessageNotification.js +4 -2
- package/dist/cjs/assets/scripts/notification/messageTemplate.js +37 -8
- package/dist/cjs/constant/notification.js +21 -0
- package/dist/cjs/src/components/forms-and-input/input-base/InputBase.js +20 -14
- package/dist/cjs/src/components/index.js +11 -0
- package/dist/cjs/src/components/overlays/notification/FullWidthNotification.js +3 -1
- package/dist/cjs/src/components/overlays/notification/MessageNotification.js +2 -0
- package/dist/cjs/src/components/overlays/notification/MessageNotificationParts.js +3 -1
- package/dist/cjs/src/components/overlays/notification/__tests__/hidePermanentlyLabel.test.js +209 -0
- package/dist/cjs/src/components/overlays/postcode-search-modal/PostcodeSearchModal.js +283 -0
- package/dist/cjs/src/components/overlays/postcode-search-modal/__tests__/PostcodeSearchModal.test.js +566 -0
- package/dist/cjs/src/components/overlays/postcode-search-modal/index.js +16 -0
- package/dist/cjs/src/generated/scoped-css.js +1 -1
- package/dist/esm/assets/scripts/notification/FullWidthNotification.js +17 -6
- package/dist/esm/assets/scripts/notification/MessageNotification.js +4 -2
- package/dist/esm/assets/scripts/notification/messageTemplate.js +37 -8
- package/dist/esm/constant/notification.js +15 -0
- package/dist/esm/src/components/forms-and-input/input-base/InputBase.js +20 -14
- package/dist/esm/src/components/index.js +1 -0
- package/dist/esm/src/components/overlays/notification/FullWidthNotification.js +3 -1
- package/dist/esm/src/components/overlays/notification/MessageNotification.js +2 -0
- package/dist/esm/src/components/overlays/notification/MessageNotificationParts.js +3 -1
- package/dist/esm/src/components/overlays/notification/__tests__/hidePermanentlyLabel.test.js +206 -0
- package/dist/esm/src/components/overlays/postcode-search-modal/PostcodeSearchModal.js +276 -0
- package/dist/esm/src/components/overlays/postcode-search-modal/__tests__/PostcodeSearchModal.test.js +563 -0
- package/dist/esm/src/components/overlays/postcode-search-modal/index.js +1 -0
- package/dist/esm/src/generated/scoped-css.js +1 -1
- package/dist/temp/assets/scripts/notification/FullWidthNotification.d.ts +6 -0
- package/dist/temp/assets/scripts/notification/FullWidthNotification.js +14 -5
- package/dist/temp/assets/scripts/notification/MessageNotification.js +2 -1
- package/dist/temp/assets/scripts/notification/const/types.d.ts +10 -0
- package/dist/temp/assets/scripts/notification/messageTemplate.d.ts +1 -0
- package/dist/temp/assets/scripts/notification/messageTemplate.js +18 -8
- package/dist/temp/constant/notification.d.ts +15 -0
- package/dist/temp/constant/notification.js +15 -0
- package/dist/temp/src/components/forms-and-input/input-base/InputBase.js +18 -10
- package/dist/temp/src/components/index.d.ts +1 -0
- package/dist/temp/src/components/index.js +1 -0
- package/dist/temp/src/components/overlays/notification/FullWidthNotification.d.ts +6 -0
- package/dist/temp/src/components/overlays/notification/FullWidthNotification.js +3 -2
- package/dist/temp/src/components/overlays/notification/MessageNotification.d.ts +6 -0
- package/dist/temp/src/components/overlays/notification/MessageNotification.js +2 -2
- package/dist/temp/src/components/overlays/notification/MessageNotificationParts.d.ts +2 -1
- package/dist/temp/src/components/overlays/notification/MessageNotificationParts.js +3 -2
- package/dist/temp/src/components/overlays/notification/Notification.d.ts +8 -0
- package/dist/temp/src/components/overlays/notification/__tests__/hidePermanentlyLabel.test.d.ts +1 -0
- package/dist/temp/src/components/overlays/notification/__tests__/hidePermanentlyLabel.test.js +160 -0
- package/dist/temp/src/components/overlays/postcode-search-modal/PostcodeSearchModal.d.ts +49 -0
- package/dist/temp/src/components/overlays/postcode-search-modal/PostcodeSearchModal.js +118 -0
- package/dist/temp/src/components/overlays/postcode-search-modal/__tests__/PostcodeSearchModal.test.d.ts +1 -0
- package/dist/temp/src/components/overlays/postcode-search-modal/__tests__/PostcodeSearchModal.test.js +456 -0
- package/dist/temp/src/components/overlays/postcode-search-modal/index.d.ts +1 -0
- package/dist/temp/src/components/overlays/postcode-search-modal/index.js +1 -0
- package/dist/temp/src/generated/scoped-css.js +1 -1
- package/dist/types/assets/scripts/notification/FullWidthNotification.d.ts +6 -0
- package/dist/types/assets/scripts/notification/const/types.d.ts +10 -0
- package/dist/types/assets/scripts/notification/messageTemplate.d.ts +1 -0
- package/dist/types/constant/notification.d.ts +15 -0
- package/dist/types/src/components/index.d.ts +1 -0
- package/dist/types/src/components/overlays/notification/FullWidthNotification.d.ts +6 -0
- package/dist/types/src/components/overlays/notification/MessageNotification.d.ts +6 -0
- package/dist/types/src/components/overlays/notification/MessageNotificationParts.d.ts +2 -1
- package/dist/types/src/components/overlays/notification/Notification.d.ts +8 -0
- package/dist/types/src/components/overlays/notification/__tests__/hidePermanentlyLabel.test.d.ts +1 -0
- package/dist/types/src/components/overlays/postcode-search-modal/PostcodeSearchModal.d.ts +49 -0
- package/dist/types/src/components/overlays/postcode-search-modal/__tests__/PostcodeSearchModal.test.d.ts +1 -0
- package/dist/types/src/components/overlays/postcode-search-modal/index.d.ts +1 -0
- package/dist/ui-admin/assets/styles/style.css +188 -13
- package/dist/ui-admin/assets/styles/style.scoped.css +188 -13
- package/package.json +1 -1
|
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.FullWidthNotification = void 0;
|
|
7
|
+
var _notification = require("../../../constant/notification");
|
|
7
8
|
var _sanitize = require("../utils/sanitize");
|
|
8
9
|
var _const = require("./const");
|
|
9
10
|
var _utils = require("./utils");
|
|
@@ -30,7 +31,8 @@ class FullWidthNotification {
|
|
|
30
31
|
actions,
|
|
31
32
|
onClose,
|
|
32
33
|
supportTextLink,
|
|
33
|
-
onHidePermanently
|
|
34
|
+
onHidePermanently,
|
|
35
|
+
hidePermanentlyLabel
|
|
34
36
|
} = this.options;
|
|
35
37
|
const wrapper = (0, _utils.createWrapperElement)(_const.CLASS_NAMES.FULL_WIDTH.BASE, color, className);
|
|
36
38
|
const iconHtml = _const.FULL_WIDTH_ICON_MAP[color](_const.FULL_WIDTH_SIZES.ICON);
|
|
@@ -41,7 +43,8 @@ class FullWidthNotification {
|
|
|
41
43
|
actions,
|
|
42
44
|
onClose,
|
|
43
45
|
supportTextLink,
|
|
44
|
-
onHidePermanently
|
|
46
|
+
onHidePermanently,
|
|
47
|
+
hidePermanentlyLabel
|
|
45
48
|
}));
|
|
46
49
|
return wrapper;
|
|
47
50
|
}
|
|
@@ -53,7 +56,8 @@ class FullWidthNotification {
|
|
|
53
56
|
actions,
|
|
54
57
|
onClose,
|
|
55
58
|
supportTextLink,
|
|
56
|
-
onHidePermanently
|
|
59
|
+
onHidePermanently,
|
|
60
|
+
hidePermanentlyLabel
|
|
57
61
|
} = params;
|
|
58
62
|
return `
|
|
59
63
|
<div class="${_const.CLASS_NAMES.FULL_WIDTH.CONTAINER}">
|
|
@@ -67,18 +71,25 @@ class FullWidthNotification {
|
|
|
67
71
|
</div>
|
|
68
72
|
<div class="${_const.CLASS_NAMES.FULL_WIDTH.ACTIONS_CONTAINER}">
|
|
69
73
|
${actions && actions.length > 0 ? (0, _utils.renderActions)(actions, _const.CLASS_NAMES.FULL_WIDTH.ACTIONS) : ''}
|
|
70
|
-
${this.renderHidePermanentlyButton(onHidePermanently)}
|
|
74
|
+
${this.renderHidePermanentlyButton(onHidePermanently, hidePermanentlyLabel)}
|
|
71
75
|
${this.renderCloseButton(onClose)}
|
|
72
76
|
</div>
|
|
73
77
|
</div>
|
|
74
78
|
</div>
|
|
75
79
|
`;
|
|
76
80
|
}
|
|
77
|
-
|
|
81
|
+
/**
|
|
82
|
+
* 다시보지 않기 버튼.
|
|
83
|
+
*
|
|
84
|
+
* `label`은 이 함수의 반환값이 `wrapper.innerHTML`에 들어가기 전에 `sanitizeHtml`로
|
|
85
|
+
* 처리되므로 별도 이스케이프하지 않는다 — `renderSupportingText`와 같은 정책이다.
|
|
86
|
+
*/
|
|
87
|
+
renderHidePermanentlyButton(onHidePermanently, hidePermanentlyLabel) {
|
|
78
88
|
if (!onHidePermanently) return '';
|
|
89
|
+
const label = hidePermanentlyLabel ?? _notification.HIDE_PERMANENTLY_LABEL.fullWidth;
|
|
79
90
|
return `
|
|
80
91
|
<button type="button" class="ncua-notification__action-button ncua-notification__action-button--text ncua-full-width-notification__link" data-hide-permanently="true">
|
|
81
|
-
|
|
92
|
+
${label}
|
|
82
93
|
</button>
|
|
83
94
|
`;
|
|
84
95
|
}
|
|
@@ -31,7 +31,8 @@ class MessageNotification {
|
|
|
31
31
|
className,
|
|
32
32
|
actions,
|
|
33
33
|
onClose,
|
|
34
|
-
onHidePermanently
|
|
34
|
+
onHidePermanently,
|
|
35
|
+
hidePermanentlyLabel
|
|
35
36
|
} = this.options;
|
|
36
37
|
// message 타입은 neutral, error, warning, success 4가지 색상만 지원
|
|
37
38
|
let actualColor = color;
|
|
@@ -60,7 +61,8 @@ class MessageNotification {
|
|
|
60
61
|
supportingText,
|
|
61
62
|
actions,
|
|
62
63
|
onClose,
|
|
63
|
-
onHidePermanently
|
|
64
|
+
onHidePermanently,
|
|
65
|
+
hidePermanentlyLabel
|
|
64
66
|
}));
|
|
65
67
|
// FeaturedIcon을 content-wrapper에 추가
|
|
66
68
|
if (featuredIconElement) {
|
|
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.buildMessageTemplate = buildMessageTemplate;
|
|
7
|
+
var _notification = require("../../../constant/notification");
|
|
7
8
|
var _const = require("./const");
|
|
8
9
|
var _utils = require("./utils");
|
|
9
10
|
/**
|
|
@@ -22,7 +23,8 @@ function buildMessageTemplate(params) {
|
|
|
22
23
|
supportingText,
|
|
23
24
|
actions,
|
|
24
25
|
onClose,
|
|
25
|
-
onHidePermanently
|
|
26
|
+
onHidePermanently,
|
|
27
|
+
hidePermanentlyLabel
|
|
26
28
|
} = params;
|
|
27
29
|
return `
|
|
28
30
|
<div class="${_const.CLASS_NAMES.MESSAGE.CONTAINER}">
|
|
@@ -33,7 +35,12 @@ function buildMessageTemplate(params) {
|
|
|
33
35
|
${(0, _utils.renderSupportingText)(supportingText, _const.CLASS_NAMES.MESSAGE.SUPPORTING_TEXT)}
|
|
34
36
|
</div>
|
|
35
37
|
</div>
|
|
36
|
-
${renderActionsContainer(
|
|
38
|
+
${renderActionsContainer({
|
|
39
|
+
actions,
|
|
40
|
+
onClose,
|
|
41
|
+
onHidePermanently,
|
|
42
|
+
hidePermanentlyLabel
|
|
43
|
+
})}
|
|
37
44
|
</div>
|
|
38
45
|
</div>
|
|
39
46
|
`;
|
|
@@ -43,27 +50,49 @@ function buildMessageTemplate(params) {
|
|
|
43
50
|
* 이 컨테이너의 gap(12px)이 두 그룹 사이 간격을 만든다.
|
|
44
51
|
* 표시할 요소가 하나도 없으면 빈 컨테이너를 남기지 않는다.
|
|
45
52
|
*/
|
|
46
|
-
function renderActionsContainer(
|
|
53
|
+
function renderActionsContainer(params) {
|
|
54
|
+
const {
|
|
55
|
+
actions,
|
|
56
|
+
onClose,
|
|
57
|
+
onHidePermanently,
|
|
58
|
+
hidePermanentlyLabel
|
|
59
|
+
} = params;
|
|
47
60
|
const actionsHtml = (0, _utils.renderActions)(actions ?? [], _const.CLASS_NAMES.MESSAGE.ACTIONS, ACTION_BUTTON_SIZE);
|
|
48
|
-
const footerHtml = renderFooterContainer(
|
|
61
|
+
const footerHtml = renderFooterContainer({
|
|
62
|
+
onClose,
|
|
63
|
+
onHidePermanently,
|
|
64
|
+
hidePermanentlyLabel
|
|
65
|
+
});
|
|
49
66
|
if (!actionsHtml && !footerHtml) return '';
|
|
50
67
|
return `<div class="${_const.CLASS_NAMES.MESSAGE.ACTIONS_CONTAINER}">${actionsHtml}${footerHtml}</div>`;
|
|
51
68
|
}
|
|
52
69
|
/** 다시 보지 않기 + 닫기 그룹. 전용 래퍼를 쓰는 이유는 `CLASS_NAMES.MESSAGE.FOOTER_CONTAINER` 참조. */
|
|
53
|
-
function renderFooterContainer(
|
|
70
|
+
function renderFooterContainer(params) {
|
|
71
|
+
const {
|
|
72
|
+
onClose,
|
|
73
|
+
onHidePermanently,
|
|
74
|
+
hidePermanentlyLabel
|
|
75
|
+
} = params;
|
|
54
76
|
if (!onHidePermanently && !onClose) return '';
|
|
55
77
|
return `
|
|
56
78
|
<div class="${_const.CLASS_NAMES.MESSAGE.FOOTER_CONTAINER}">
|
|
57
|
-
${renderHidePermanentlyButton(onHidePermanently)}
|
|
79
|
+
${renderHidePermanentlyButton(onHidePermanently, hidePermanentlyLabel)}
|
|
58
80
|
${renderCloseButton(onClose)}
|
|
59
81
|
</div>
|
|
60
82
|
`;
|
|
61
83
|
}
|
|
62
|
-
|
|
84
|
+
/**
|
|
85
|
+
* 다시 보지 않기 버튼.
|
|
86
|
+
*
|
|
87
|
+
* `label`은 이 함수의 반환값이 `wrapper.innerHTML`에 들어가기 전에 `sanitizeHtml`로
|
|
88
|
+
* 처리되므로 별도 이스케이프하지 않는다 — `renderSupportingText`와 같은 정책이다.
|
|
89
|
+
*/
|
|
90
|
+
function renderHidePermanentlyButton(onHidePermanently, hidePermanentlyLabel) {
|
|
63
91
|
if (!onHidePermanently) return '';
|
|
92
|
+
const label = hidePermanentlyLabel ?? _notification.HIDE_PERMANENTLY_LABEL.message;
|
|
64
93
|
return `
|
|
65
94
|
<button type="button" class="${_const.CLASS_NAMES.COMMON.ACTION_BUTTON} ${_const.CLASS_NAMES.MESSAGE.HIDE_LINK}" data-hide-permanently="true">
|
|
66
|
-
|
|
95
|
+
${label}
|
|
67
96
|
</button>
|
|
68
97
|
`;
|
|
69
98
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.HIDE_PERMANENTLY_LABEL = void 0;
|
|
7
|
+
/**
|
|
8
|
+
* 다시보지 않기 버튼의 타입별 기본 문구.
|
|
9
|
+
*
|
|
10
|
+
* `hidePermanentlyLabel`을 지정하지 않았을 때 쓰인다.
|
|
11
|
+
* React(`src/components/overlays/notification/`)와 Vanilla(`assets/scripts/notification/`)
|
|
12
|
+
* 두 구현이 이 상수를 함께 참조한다 — 문구가 하드코딩으로 흩어져 서로 어긋나던 문제(#460)를
|
|
13
|
+
* 막기 위한 단일 출처다.
|
|
14
|
+
*
|
|
15
|
+
* `message`와 `fullWidth`의 띄어쓰기가 다른 것은 오타가 아니라 현행 유지다.
|
|
16
|
+
* 표기 통일은 별도 결정 사항이며, 결정되면 이 파일 한 곳만 고치면 된다.
|
|
17
|
+
*/
|
|
18
|
+
const HIDE_PERMANENTLY_LABEL = exports.HIDE_PERMANENTLY_LABEL = {
|
|
19
|
+
message: '다시 보지 않기',
|
|
20
|
+
fullWidth: '다시보지 않기'
|
|
21
|
+
};
|
|
@@ -39,26 +39,27 @@ const InputBase = exports.InputBase = /*#__PURE__*/(0, _react.forwardRef)((_ref,
|
|
|
39
39
|
...props
|
|
40
40
|
} = _ref;
|
|
41
41
|
const inputRef = (0, _react.useRef)(null);
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
// controlled 인풋은 props.value 로 길이를 알 수 있으므로 상태를 두지 않는다.
|
|
43
|
+
// 입력마다 setState 를 하면 조합 중(한글 IME)에 리렌더가 끼어들어 조합이 끊긴다.
|
|
44
|
+
const isControlled = props.value !== undefined;
|
|
45
|
+
const [uncontrolledLength, setUncontrolledLength] = (0, _react.useState)(0);
|
|
46
|
+
const valueLength = isControlled ? String(props.value ?? '').length : uncontrolledLength;
|
|
47
|
+
const hasValue = valueLength > 0;
|
|
48
|
+
const textCount = valueLength;
|
|
49
|
+
// uncontrolled 인풋만 DOM 값을 읽어 따라간다 — props.value 가 없어 길이를 알 방법이 이것뿐이다.
|
|
46
50
|
(0, _react.useEffect)(() => {
|
|
51
|
+
if (isControlled) return;
|
|
47
52
|
const input = inputRef.current;
|
|
48
53
|
if (!input) return;
|
|
49
54
|
const syncFromInput = () => {
|
|
50
|
-
|
|
51
|
-
length
|
|
52
|
-
} = input.value;
|
|
53
|
-
setHasValue(length > 0);
|
|
54
|
-
setTextCount(length);
|
|
55
|
+
setUncontrolledLength(input.value.length);
|
|
55
56
|
};
|
|
56
57
|
syncFromInput();
|
|
57
58
|
input.addEventListener('input', syncFromInput);
|
|
58
59
|
return () => {
|
|
59
60
|
input.removeEventListener('input', syncFromInput);
|
|
60
61
|
};
|
|
61
|
-
}, [
|
|
62
|
+
}, [isControlled]);
|
|
62
63
|
const renderOutsideSlot = (slot, position) => {
|
|
63
64
|
if (slot.type === 'custom' && slot.placement !== 'outside') {
|
|
64
65
|
return null;
|
|
@@ -72,10 +73,15 @@ const InputBase = exports.InputBase = /*#__PURE__*/(0, _react.forwardRef)((_ref,
|
|
|
72
73
|
children: slot.label
|
|
73
74
|
});
|
|
74
75
|
case 'text':
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
76
|
+
{
|
|
77
|
+
// 클래스명은 리터럴로 쓴다 — MCP 의 BEM 추출기가 `ncua-input__${position}-text` 형태의
|
|
78
|
+
// 템플릿 리터럴에서는 `ncua-input__` 조각만 읽어 완성된 클래스를 잡지 못한다.
|
|
79
|
+
const textClass = position === 'leading' ? 'ncua-input__leading-text' : 'ncua-input__trailing-text';
|
|
80
|
+
return (0, _jsxRuntime.jsx)("span", {
|
|
81
|
+
className: (0, _classnames.default)(textClass, `${textClass}--${size}`),
|
|
82
|
+
children: slot.text
|
|
83
|
+
});
|
|
84
|
+
}
|
|
79
85
|
case 'custom':
|
|
80
86
|
return slot.children;
|
|
81
87
|
default:
|
|
@@ -498,6 +498,17 @@ Object.keys(_notification).forEach(function (key) {
|
|
|
498
498
|
}
|
|
499
499
|
});
|
|
500
500
|
});
|
|
501
|
+
var _postcodeSearchModal = require("./overlays/postcode-search-modal");
|
|
502
|
+
Object.keys(_postcodeSearchModal).forEach(function (key) {
|
|
503
|
+
if (key === "default" || key === "__esModule") return;
|
|
504
|
+
if (key in exports && exports[key] === _postcodeSearchModal[key]) return;
|
|
505
|
+
Object.defineProperty(exports, key, {
|
|
506
|
+
enumerable: true,
|
|
507
|
+
get: function () {
|
|
508
|
+
return _postcodeSearchModal[key];
|
|
509
|
+
}
|
|
510
|
+
});
|
|
511
|
+
});
|
|
501
512
|
var _tooltip = require("./overlays/tooltip");
|
|
502
513
|
Object.keys(_tooltip).forEach(function (key) {
|
|
503
514
|
if (key === "default" || key === "__esModule") return;
|
|
@@ -9,6 +9,7 @@ var _uiAdminIcon = require("@ncds/ui-admin-icon");
|
|
|
9
9
|
var _classnames = _interopRequireDefault(require("classnames"));
|
|
10
10
|
var _react = require("react");
|
|
11
11
|
var _color = require("../../../../constant/color");
|
|
12
|
+
var _notification = require("../../../../constant/notification");
|
|
12
13
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
13
14
|
const iconMap = {
|
|
14
15
|
neutral: _uiAdminIcon.MessageChatSquare,
|
|
@@ -35,6 +36,7 @@ const FullWidthNotification = exports.FullWidthNotification = /*#__PURE__*/(0, _
|
|
|
35
36
|
autoClose = 0,
|
|
36
37
|
supportTextLink,
|
|
37
38
|
onHidePermanently,
|
|
39
|
+
hidePermanentlyLabel = _notification.HIDE_PERMANENTLY_LABEL.fullWidth,
|
|
38
40
|
...rest
|
|
39
41
|
} = _ref;
|
|
40
42
|
const [shouldRemove, setShouldRemove] = (0, _react.useState)(false);
|
|
@@ -116,7 +118,7 @@ const FullWidthNotification = exports.FullWidthNotification = /*#__PURE__*/(0, _
|
|
|
116
118
|
type: "button",
|
|
117
119
|
className: (0, _classnames.default)('ncua-notification__action-button', 'ncua-notification__action-button--text', 'ncua-full-width-notification__link'),
|
|
118
120
|
onClick: onHidePermanently,
|
|
119
|
-
children:
|
|
121
|
+
children: hidePermanentlyLabel
|
|
120
122
|
}), onClose && (0, _jsxRuntime.jsx)("button", {
|
|
121
123
|
type: "button",
|
|
122
124
|
className: "ncua-full-width-notification__close-button",
|
|
@@ -33,6 +33,7 @@ const MessageNotification = exports.MessageNotification = /*#__PURE__*/(0, _reac
|
|
|
33
33
|
className,
|
|
34
34
|
actions,
|
|
35
35
|
onHidePermanently,
|
|
36
|
+
hidePermanentlyLabel,
|
|
36
37
|
...rest
|
|
37
38
|
} = _ref;
|
|
38
39
|
// message 타입은 neutral, error, warning, success 4가지 색상만 지원
|
|
@@ -56,6 +57,7 @@ const MessageNotification = exports.MessageNotification = /*#__PURE__*/(0, _reac
|
|
|
56
57
|
actions: actions,
|
|
57
58
|
onClose: onClose,
|
|
58
59
|
onHidePermanently: onHidePermanently,
|
|
60
|
+
hidePermanentlyLabel: hidePermanentlyLabel,
|
|
59
61
|
closeIconColor: _color.COLOR[iconColorMap[validColor] || 'gray700']
|
|
60
62
|
})]
|
|
61
63
|
})
|
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.MessageNotificationContent = exports.MessageNotificationActions = void 0;
|
|
7
7
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
8
8
|
var _uiAdminIcon = require("@ncds/ui-admin-icon");
|
|
9
|
+
var _notification = require("../../../../constant/notification");
|
|
9
10
|
var _button = require("../../action/button");
|
|
10
11
|
var _FeaturedIcon = require("../../image-and-icons/featured-icon/FeaturedIcon");
|
|
11
12
|
/** 아이콘 + 제목/서포팅 텍스트 영역. */
|
|
@@ -51,6 +52,7 @@ const MessageNotificationActions = _ref2 => {
|
|
|
51
52
|
actions,
|
|
52
53
|
onClose,
|
|
53
54
|
onHidePermanently,
|
|
55
|
+
hidePermanentlyLabel = _notification.HIDE_PERMANENTLY_LABEL.message,
|
|
54
56
|
closeIconColor
|
|
55
57
|
} = _ref2;
|
|
56
58
|
const hasActions = Boolean(actions?.length);
|
|
@@ -72,7 +74,7 @@ const MessageNotificationActions = _ref2 => {
|
|
|
72
74
|
type: "button",
|
|
73
75
|
className: "ncua-notification__action-button ncua-message-notification__hide-link",
|
|
74
76
|
onClick: onHidePermanently,
|
|
75
|
-
children:
|
|
77
|
+
children: hidePermanentlyLabel
|
|
76
78
|
}), onClose && (0, _jsxRuntime.jsx)("button", {
|
|
77
79
|
type: "button",
|
|
78
80
|
className: "ncua-message-notification__close-button",
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _react = require("react");
|
|
4
|
+
var _client = require("react-dom/client");
|
|
5
|
+
var _testUtils = require("react-dom/test-utils");
|
|
6
|
+
var _vitest = require("vitest");
|
|
7
|
+
var _FullWidthNotification = require("../FullWidthNotification");
|
|
8
|
+
var _MessageNotification = require("../MessageNotification");
|
|
9
|
+
var _Notification = require("../Notification");
|
|
10
|
+
// @vitest-environment jsdom
|
|
11
|
+
|
|
12
|
+
// React 18에서 act() 사용 시 필요한 플래그 (미설정 시 console.error 경고 발생)
|
|
13
|
+
globalThis.IS_REACT_ACT_ENVIRONMENT = true;
|
|
14
|
+
const SELECTOR = {
|
|
15
|
+
/** message 타입 — 고도몰이 textContent 덮어쓰기에 쓰는 하위호환 계약 선택자. */
|
|
16
|
+
MESSAGE_HIDE_LINK: '.ncua-message-notification__hide-link',
|
|
17
|
+
/** full-width 타입 — 다시보지 않기 버튼. */
|
|
18
|
+
FULL_WIDTH_LINK: '.ncua-full-width-notification__link',
|
|
19
|
+
ACTION_BUTTON: '.ncua-notification__action-button'
|
|
20
|
+
};
|
|
21
|
+
/** 각 타입의 현행 기본 문구. 표기 통일은 별도 결정 사항이므로 서로 다른 값을 그대로 유지한다. */
|
|
22
|
+
const DEFAULT_LABEL = {
|
|
23
|
+
MESSAGE: '다시 보지 않기',
|
|
24
|
+
FULL_WIDTH: '다시보지 않기'
|
|
25
|
+
};
|
|
26
|
+
const mounted = [];
|
|
27
|
+
function render(element) {
|
|
28
|
+
const container = document.createElement('div');
|
|
29
|
+
document.body.appendChild(container);
|
|
30
|
+
const root = (0, _client.createRoot)(container);
|
|
31
|
+
(0, _testUtils.act)(() => {
|
|
32
|
+
root.render(element);
|
|
33
|
+
});
|
|
34
|
+
mounted.push({
|
|
35
|
+
root,
|
|
36
|
+
container
|
|
37
|
+
});
|
|
38
|
+
return container;
|
|
39
|
+
}
|
|
40
|
+
function renderMessage() {
|
|
41
|
+
let props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
42
|
+
return render(/*#__PURE__*/(0, _react.createElement)(_MessageNotification.MessageNotification, {
|
|
43
|
+
title: '알림 제목',
|
|
44
|
+
...props
|
|
45
|
+
}));
|
|
46
|
+
}
|
|
47
|
+
function renderFullWidth() {
|
|
48
|
+
let props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
49
|
+
return render(/*#__PURE__*/(0, _react.createElement)(_FullWidthNotification.FullWidthNotification, {
|
|
50
|
+
title: '알림 제목',
|
|
51
|
+
...props
|
|
52
|
+
}));
|
|
53
|
+
}
|
|
54
|
+
function renderNotification() {
|
|
55
|
+
let props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
56
|
+
return render(/*#__PURE__*/(0, _react.createElement)(_Notification.Notification, {
|
|
57
|
+
title: '알림 제목',
|
|
58
|
+
...props
|
|
59
|
+
}));
|
|
60
|
+
}
|
|
61
|
+
(0, _vitest.afterEach)(() => {
|
|
62
|
+
for (const {
|
|
63
|
+
root,
|
|
64
|
+
container
|
|
65
|
+
} of mounted.splice(0)) {
|
|
66
|
+
(0, _testUtils.act)(() => {
|
|
67
|
+
root.unmount();
|
|
68
|
+
});
|
|
69
|
+
container.remove();
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
(0, _vitest.describe)('hidePermanentlyLabel (React) — message 타입', () => {
|
|
73
|
+
(0, _vitest.it)('R-1: prop 미지정 시 기본 문구 "다시 보지 않기"가 렌더된다', () => {
|
|
74
|
+
// Given: hidePermanentlyLabel 없이 onHidePermanently만 주어지고
|
|
75
|
+
// When: MessageNotification을 렌더하면
|
|
76
|
+
const container = renderMessage({
|
|
77
|
+
onHidePermanently: _vitest.vi.fn()
|
|
78
|
+
});
|
|
79
|
+
// Then: 현행 기본 문구가 그대로 노출된다 (시각적 변화 0)
|
|
80
|
+
const hideLink = container.querySelector(SELECTOR.MESSAGE_HIDE_LINK);
|
|
81
|
+
(0, _vitest.expect)(hideLink?.textContent).toBe(DEFAULT_LABEL.MESSAGE);
|
|
82
|
+
});
|
|
83
|
+
(0, _vitest.it)('R-2: prop 지정 시 그 값이 렌더된다', () => {
|
|
84
|
+
// Given: 커스텀 라벨이 주어지고
|
|
85
|
+
// When: 렌더하면
|
|
86
|
+
const container = renderMessage({
|
|
87
|
+
onHidePermanently: _vitest.vi.fn(),
|
|
88
|
+
hidePermanentlyLabel: '30일간 보지 않기'
|
|
89
|
+
});
|
|
90
|
+
// Then: 하드코딩 문구 대신 전달한 값이 노출된다
|
|
91
|
+
const hideLink = container.querySelector(SELECTOR.MESSAGE_HIDE_LINK);
|
|
92
|
+
(0, _vitest.expect)(hideLink?.textContent).toBe('30일간 보지 않기');
|
|
93
|
+
});
|
|
94
|
+
(0, _vitest.it)('R-3: ReactNode 라벨을 받아 엘리먼트로 렌더한다', () => {
|
|
95
|
+
// Given: 문자열이 아닌 ReactNode 라벨이 주어지고
|
|
96
|
+
const label = /*#__PURE__*/(0, _react.createElement)('span', {
|
|
97
|
+
className: 'custom-hide-label'
|
|
98
|
+
}, '커스텀 노드');
|
|
99
|
+
// When: 렌더하면
|
|
100
|
+
const container = renderMessage({
|
|
101
|
+
onHidePermanently: _vitest.vi.fn(),
|
|
102
|
+
hidePermanentlyLabel: label
|
|
103
|
+
});
|
|
104
|
+
// Then: 노드가 hide-link 내부에 그대로 마운트된다
|
|
105
|
+
const hideLink = container.querySelector(SELECTOR.MESSAGE_HIDE_LINK);
|
|
106
|
+
(0, _vitest.expect)(hideLink?.querySelector('.custom-hide-label')?.textContent).toBe('커스텀 노드');
|
|
107
|
+
});
|
|
108
|
+
(0, _vitest.it)('R-4: 라벨을 바꿔도 __hide-link 클래스 계약이 유지된다', () => {
|
|
109
|
+
// Given: 커스텀 라벨이 주어지고
|
|
110
|
+
// When: 렌더하면
|
|
111
|
+
const container = renderMessage({
|
|
112
|
+
onHidePermanently: _vitest.vi.fn(),
|
|
113
|
+
hidePermanentlyLabel: '커스텀'
|
|
114
|
+
});
|
|
115
|
+
// Then: 고도몰의 textContent 덮어쓰기가 계속 동작하도록 기존 클래스가 모두 남는다
|
|
116
|
+
const hideLink = container.querySelector(SELECTOR.MESSAGE_HIDE_LINK);
|
|
117
|
+
(0, _vitest.expect)(hideLink).not.toBeNull();
|
|
118
|
+
(0, _vitest.expect)(hideLink?.classList.contains('ncua-notification__action-button')).toBe(true);
|
|
119
|
+
(0, _vitest.expect)(hideLink?.classList.contains('ncua-message-notification__hide-link')).toBe(true);
|
|
120
|
+
});
|
|
121
|
+
(0, _vitest.it)('R-5: onHidePermanently 없이 라벨만 주면 버튼이 렌더되지 않는다', () => {
|
|
122
|
+
// Given: 핸들러 없이 라벨만 주어지고
|
|
123
|
+
// When: 렌더하면
|
|
124
|
+
const container = renderMessage({
|
|
125
|
+
hidePermanentlyLabel: '커스텀'
|
|
126
|
+
});
|
|
127
|
+
// Then: 라벨만으로는 버튼이 생기지 않는다 (핸들러가 렌더 조건)
|
|
128
|
+
(0, _vitest.expect)(container.querySelector(SELECTOR.MESSAGE_HIDE_LINK)).toBeNull();
|
|
129
|
+
});
|
|
130
|
+
(0, _vitest.it)('R-6: 라벨이 DOM 속성으로 새어나가지 않는다', () => {
|
|
131
|
+
// Given: 커스텀 라벨이 주어지고
|
|
132
|
+
// When: 렌더하면
|
|
133
|
+
const container = renderMessage({
|
|
134
|
+
onHidePermanently: _vitest.vi.fn(),
|
|
135
|
+
hidePermanentlyLabel: '커스텀'
|
|
136
|
+
});
|
|
137
|
+
// Then: rest 스프레드를 타고 루트 div의 속성으로 흘러들지 않는다
|
|
138
|
+
const root = container.querySelector('.ncua-message-notification');
|
|
139
|
+
(0, _vitest.expect)(root?.hasAttribute('hidepermanentlylabel')).toBe(false);
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
(0, _vitest.describe)('hidePermanentlyLabel (React) — full-width 타입', () => {
|
|
143
|
+
(0, _vitest.it)('R-7: prop 미지정 시 기본 문구 "다시보지 않기"가 렌더된다', () => {
|
|
144
|
+
// Given: hidePermanentlyLabel 없이 onHidePermanently만 주어지고
|
|
145
|
+
// When: FullWidthNotification을 렌더하면
|
|
146
|
+
const container = renderFullWidth({
|
|
147
|
+
onHidePermanently: _vitest.vi.fn()
|
|
148
|
+
});
|
|
149
|
+
// Then: message 타입과 다른 현행 문구가 그대로 유지된다 (표기 통일은 별도 결정)
|
|
150
|
+
const hideButton = container.querySelector(SELECTOR.FULL_WIDTH_LINK);
|
|
151
|
+
(0, _vitest.expect)(hideButton?.textContent).toBe(DEFAULT_LABEL.FULL_WIDTH);
|
|
152
|
+
});
|
|
153
|
+
(0, _vitest.it)('R-8: prop 지정 시 그 값이 렌더된다', () => {
|
|
154
|
+
// Given: 커스텀 라벨이 주어지고
|
|
155
|
+
// When: 렌더하면
|
|
156
|
+
const container = renderFullWidth({
|
|
157
|
+
onHidePermanently: _vitest.vi.fn(),
|
|
158
|
+
hidePermanentlyLabel: '오늘 하루 보지 않기'
|
|
159
|
+
});
|
|
160
|
+
// Then: 전달한 값이 노출된다
|
|
161
|
+
const hideButton = container.querySelector(SELECTOR.FULL_WIDTH_LINK);
|
|
162
|
+
(0, _vitest.expect)(hideButton?.textContent).toBe('오늘 하루 보지 않기');
|
|
163
|
+
});
|
|
164
|
+
(0, _vitest.it)('R-9: 라벨을 바꿔도 기존 클래스 계약이 유지된다', () => {
|
|
165
|
+
// Given: 커스텀 라벨이 주어지고
|
|
166
|
+
// When: 렌더하면
|
|
167
|
+
const container = renderFullWidth({
|
|
168
|
+
onHidePermanently: _vitest.vi.fn(),
|
|
169
|
+
hidePermanentlyLabel: '커스텀'
|
|
170
|
+
});
|
|
171
|
+
// Then: 액션 버튼 클래스가 그대로 남는다
|
|
172
|
+
const hideButton = container.querySelector(SELECTOR.FULL_WIDTH_LINK);
|
|
173
|
+
(0, _vitest.expect)(hideButton?.classList.contains('ncua-notification__action-button')).toBe(true);
|
|
174
|
+
(0, _vitest.expect)(hideButton?.classList.contains('ncua-notification__action-button--text')).toBe(true);
|
|
175
|
+
});
|
|
176
|
+
(0, _vitest.it)('R-10: onHidePermanently 없이 라벨만 주면 버튼이 렌더되지 않는다', () => {
|
|
177
|
+
// Given: 핸들러 없이 라벨만 주어지고
|
|
178
|
+
// When: 렌더하면
|
|
179
|
+
const container = renderFullWidth({
|
|
180
|
+
hidePermanentlyLabel: '커스텀'
|
|
181
|
+
});
|
|
182
|
+
// Then: 액션 버튼이 생기지 않는다
|
|
183
|
+
(0, _vitest.expect)(container.querySelector(SELECTOR.ACTION_BUTTON)).toBeNull();
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
(0, _vitest.describe)('hidePermanentlyLabel (React) — Notification 공유 Props 경유', () => {
|
|
187
|
+
(0, _vitest.it)('R-11: type="message"에서 공유 Props의 라벨이 전달된다', () => {
|
|
188
|
+
// Given: 공유 Notification props로 라벨이 주어지고
|
|
189
|
+
// When: type="message"로 렌더하면
|
|
190
|
+
const container = renderNotification({
|
|
191
|
+
type: 'message',
|
|
192
|
+
onHidePermanently: _vitest.vi.fn(),
|
|
193
|
+
hidePermanentlyLabel: '공유 프롭 라벨'
|
|
194
|
+
});
|
|
195
|
+
// Then: message 구현까지 라벨이 도달한다
|
|
196
|
+
(0, _vitest.expect)(container.querySelector(SELECTOR.MESSAGE_HIDE_LINK)?.textContent).toBe('공유 프롭 라벨');
|
|
197
|
+
});
|
|
198
|
+
(0, _vitest.it)('R-12: type="full-width"에서 공유 Props의 라벨이 전달된다', () => {
|
|
199
|
+
// Given: 공유 Notification props로 라벨이 주어지고
|
|
200
|
+
// When: type="full-width"로 렌더하면
|
|
201
|
+
const container = renderNotification({
|
|
202
|
+
type: 'full-width',
|
|
203
|
+
onHidePermanently: _vitest.vi.fn(),
|
|
204
|
+
hidePermanentlyLabel: '공유 프롭 라벨'
|
|
205
|
+
});
|
|
206
|
+
// Then: full-width 구현까지 라벨이 도달한다
|
|
207
|
+
(0, _vitest.expect)(container.querySelector(SELECTOR.FULL_WIDTH_LINK)?.textContent).toBe('공유 프롭 라벨');
|
|
208
|
+
});
|
|
209
|
+
});
|