@ncds/ui-admin 1.8.4 → 1.8.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/featuredIcon.js +87 -0
- package/dist/cjs/assets/scripts/notification/FloatingNotification.js +178 -0
- package/dist/cjs/assets/scripts/notification/FullWidthNotification.js +133 -0
- package/dist/cjs/assets/scripts/notification/MessageNotification.js +159 -0
- package/dist/cjs/assets/scripts/notification/Notification.js +120 -0
- package/dist/cjs/assets/scripts/notification/const/classNames.js +50 -0
- package/dist/cjs/assets/scripts/notification/const/icons.js +31 -0
- package/dist/cjs/assets/scripts/notification/const/index.js +87 -0
- package/dist/cjs/assets/scripts/notification/const/sizes.js +46 -0
- package/dist/cjs/assets/scripts/notification/const/types.js +14 -0
- package/dist/cjs/assets/scripts/notification/index.js +116 -0
- package/dist/cjs/assets/scripts/notification/positionSync.js +180 -0
- package/dist/cjs/assets/scripts/notification/utils.js +122 -0
- package/dist/cjs/assets/scripts/shared/ButtonCloseX.js +45 -0
- package/dist/cjs/assets/scripts/utils/sanitize.js +39 -0
- package/dist/cjs/src/components/data-display/data-grid/DataGrid.js +5 -1
- package/dist/cjs/src/components/data-display/table/Table.js +118 -96
- package/dist/cjs/src/components/data-display/table/useTableScrollbars.js +187 -0
- package/dist/cjs/src/components/forms-and-input/combo-box/ComboBox.js +11 -10
- package/dist/cjs/src/components/forms-and-input/image-file-input/ImageFileInput.js +5 -2
- package/dist/cjs/src/components/forms-and-input/select-box/SelectBox.js +67 -29
- package/dist/cjs/src/components/overlays/dropdown/Dropdown.js +47 -19
- package/dist/cjs/src/components/overlays/notification/CalloutNotification.js +25 -0
- package/dist/cjs/src/components/overlays/notification/FloatingNotification.js +86 -13
- package/dist/cjs/src/components/overlays/notification/Notification.js +7 -0
- package/dist/cjs/src/components/overlays/notification/host.js +12 -0
- package/dist/cjs/src/components/overlays/tooltip/Tooltip.js +57 -44
- package/dist/cjs/src/components/select-dropdown/SelectDropdown.js +2 -1
- package/dist/cjs/src/contexts/FloatingContext.js +11 -0
- package/dist/cjs/src/contexts/index.js +16 -0
- package/dist/cjs/src/hooks/index.js +11 -0
- package/dist/cjs/src/hooks/useFloatingPosition.js +78 -0
- package/dist/cjs/src/hooks/usePortalState.js +17 -0
- package/dist/cjs/src/utils/dropdown/maxSelection.js +35 -0
- package/dist/cjs/src/utils/dropdown/multiSelect.js +72 -15
- package/dist/esm/assets/scripts/featuredIcon.js +80 -0
- package/dist/esm/assets/scripts/notification/FloatingNotification.js +171 -0
- package/dist/esm/assets/scripts/notification/FullWidthNotification.js +126 -0
- package/dist/esm/assets/scripts/notification/MessageNotification.js +152 -0
- package/dist/esm/assets/scripts/notification/Notification.js +113 -0
- package/dist/esm/assets/scripts/notification/const/classNames.js +44 -0
- package/dist/esm/assets/scripts/notification/const/icons.js +25 -0
- package/dist/esm/assets/scripts/notification/const/index.js +4 -0
- package/dist/esm/assets/scripts/notification/const/sizes.js +40 -0
- package/dist/esm/assets/scripts/notification/const/types.js +8 -0
- package/dist/esm/assets/scripts/notification/index.js +10 -0
- package/dist/esm/assets/scripts/notification/positionSync.js +171 -0
- package/dist/esm/assets/scripts/notification/utils.js +109 -0
- package/dist/esm/assets/scripts/shared/ButtonCloseX.js +37 -0
- package/dist/esm/assets/scripts/utils/sanitize.js +31 -0
- package/dist/esm/src/components/data-display/data-grid/DataGrid.js +5 -1
- package/dist/esm/src/components/data-display/table/Table.js +118 -96
- package/dist/esm/src/components/data-display/table/useTableScrollbars.js +179 -0
- package/dist/esm/src/components/forms-and-input/combo-box/ComboBox.js +11 -10
- package/dist/esm/src/components/forms-and-input/image-file-input/ImageFileInput.js +5 -2
- package/dist/esm/src/components/forms-and-input/select-box/SelectBox.js +67 -29
- package/dist/esm/src/components/overlays/dropdown/Dropdown.js +47 -19
- package/dist/esm/src/components/overlays/notification/CalloutNotification.js +19 -0
- package/dist/esm/src/components/overlays/notification/FloatingNotification.js +86 -14
- package/dist/esm/src/components/overlays/notification/Notification.js +7 -0
- package/dist/esm/src/components/overlays/notification/host.js +9 -0
- package/dist/esm/src/components/overlays/tooltip/Tooltip.js +58 -45
- package/dist/esm/src/components/select-dropdown/SelectDropdown.js +2 -1
- package/dist/esm/src/contexts/FloatingContext.js +4 -0
- package/dist/esm/src/contexts/index.js +1 -0
- package/dist/esm/src/hooks/index.js +1 -0
- package/dist/esm/src/hooks/useFloatingPosition.js +71 -0
- package/dist/esm/src/hooks/usePortalState.js +10 -0
- package/dist/esm/src/utils/dropdown/maxSelection.js +27 -0
- package/dist/esm/src/utils/dropdown/multiSelect.js +70 -14
- package/dist/temp/assets/scripts/featuredIcon.d.ts +22 -0
- package/dist/temp/assets/scripts/featuredIcon.js +79 -0
- package/dist/temp/assets/scripts/notification/FloatingNotification.d.ts +24 -0
- package/dist/temp/assets/scripts/notification/FloatingNotification.js +156 -0
- package/dist/temp/assets/scripts/notification/FullWidthNotification.d.ts +21 -0
- package/dist/temp/assets/scripts/notification/FullWidthNotification.js +111 -0
- package/dist/temp/assets/scripts/notification/MessageNotification.d.ts +22 -0
- package/dist/temp/assets/scripts/notification/MessageNotification.js +140 -0
- package/dist/temp/assets/scripts/notification/Notification.d.ts +22 -0
- package/dist/temp/assets/scripts/notification/Notification.js +112 -0
- package/dist/temp/assets/scripts/notification/const/classNames.d.ts +43 -0
- package/dist/temp/assets/scripts/notification/const/classNames.js +44 -0
- package/dist/temp/assets/scripts/notification/const/icons.d.ts +25 -0
- package/dist/temp/assets/scripts/notification/const/icons.js +25 -0
- package/dist/temp/assets/scripts/notification/const/index.d.ts +5 -0
- package/dist/temp/assets/scripts/notification/const/index.js +4 -0
- package/dist/temp/assets/scripts/notification/const/sizes.d.ts +32 -0
- package/dist/temp/assets/scripts/notification/const/sizes.js +40 -0
- package/dist/temp/assets/scripts/notification/const/types.d.ts +19 -0
- package/dist/temp/assets/scripts/notification/const/types.js +8 -0
- package/dist/temp/assets/scripts/notification/index.d.ts +8 -0
- package/dist/temp/assets/scripts/notification/index.js +10 -0
- package/dist/temp/assets/scripts/notification/positionSync.d.ts +50 -0
- package/dist/temp/assets/scripts/notification/positionSync.js +170 -0
- package/dist/temp/assets/scripts/notification/utils.d.ts +8 -0
- package/dist/temp/assets/scripts/notification/utils.js +115 -0
- package/dist/temp/assets/scripts/shared/ButtonCloseX.d.ts +5 -0
- package/dist/temp/assets/scripts/shared/ButtonCloseX.js +33 -0
- package/dist/temp/assets/scripts/utils/sanitize.d.ts +22 -0
- package/dist/temp/assets/scripts/utils/sanitize.js +31 -0
- package/dist/temp/src/components/data-display/data-grid/DataGrid.js +1 -1
- package/dist/temp/src/components/data-display/data-grid/DataGrid.types.d.ts +7 -0
- package/dist/temp/src/components/data-display/table/Table.d.ts +4 -1
- package/dist/temp/src/components/data-display/table/Table.js +53 -68
- package/dist/temp/src/components/data-display/table/types.d.ts +18 -0
- package/dist/temp/src/components/data-display/table/useTableScrollbars.d.ts +25 -0
- package/dist/temp/src/components/data-display/table/useTableScrollbars.js +136 -0
- package/dist/temp/src/components/forms-and-input/combo-box/ComboBox.d.ts +8 -0
- package/dist/temp/src/components/forms-and-input/combo-box/ComboBox.js +7 -11
- package/dist/temp/src/components/forms-and-input/image-file-input/ImageFileInput.js +1 -1
- package/dist/temp/src/components/forms-and-input/select-box/SelectBox.d.ts +13 -0
- package/dist/temp/src/components/forms-and-input/select-box/SelectBox.js +30 -3
- package/dist/temp/src/components/overlays/dropdown/Dropdown.d.ts +5 -0
- package/dist/temp/src/components/overlays/dropdown/Dropdown.js +35 -11
- package/dist/temp/src/components/overlays/notification/CalloutNotification.d.ts +9 -0
- package/dist/temp/src/components/overlays/notification/CalloutNotification.js +6 -0
- package/dist/temp/src/components/overlays/notification/FloatingNotification.d.ts +15 -0
- package/dist/temp/src/components/overlays/notification/FloatingNotification.js +81 -13
- package/dist/temp/src/components/overlays/notification/Notification.d.ts +18 -3
- package/dist/temp/src/components/overlays/notification/Notification.js +4 -0
- package/dist/temp/src/components/overlays/notification/host.d.ts +9 -0
- package/dist/temp/src/components/overlays/notification/host.js +9 -0
- package/dist/temp/src/components/overlays/tooltip/Tooltip.d.ts +5 -1
- package/dist/temp/src/components/overlays/tooltip/Tooltip.js +25 -22
- package/dist/temp/src/components/select-dropdown/SelectDropdown.d.ts +6 -0
- package/dist/temp/src/components/select-dropdown/SelectDropdown.js +2 -2
- package/dist/temp/src/contexts/FloatingContext.d.ts +6 -0
- package/dist/temp/src/contexts/FloatingContext.js +4 -0
- package/dist/temp/src/contexts/index.d.ts +1 -0
- package/dist/temp/src/contexts/index.js +1 -0
- package/dist/temp/src/hooks/index.d.ts +1 -0
- package/dist/temp/src/hooks/index.js +1 -0
- package/dist/temp/src/hooks/useFloatingPosition.d.ts +19 -0
- package/dist/temp/src/hooks/useFloatingPosition.js +55 -0
- package/dist/temp/src/hooks/usePortalState.d.ts +6 -0
- package/dist/temp/src/hooks/usePortalState.js +7 -0
- package/dist/temp/src/utils/dropdown/maxSelection.d.ts +24 -0
- package/dist/temp/src/utils/dropdown/maxSelection.js +28 -0
- package/dist/temp/src/utils/dropdown/multiSelect.d.ts +42 -2
- package/dist/temp/src/utils/dropdown/multiSelect.js +66 -13
- package/dist/types/assets/scripts/featuredIcon.d.ts +22 -0
- package/dist/types/assets/scripts/notification/FloatingNotification.d.ts +24 -0
- package/dist/types/assets/scripts/notification/FullWidthNotification.d.ts +21 -0
- package/dist/types/assets/scripts/notification/MessageNotification.d.ts +22 -0
- package/dist/types/assets/scripts/notification/Notification.d.ts +22 -0
- package/dist/types/assets/scripts/notification/const/classNames.d.ts +43 -0
- package/dist/types/assets/scripts/notification/const/icons.d.ts +25 -0
- package/dist/types/assets/scripts/notification/const/index.d.ts +5 -0
- package/dist/types/assets/scripts/notification/const/sizes.d.ts +32 -0
- package/dist/types/assets/scripts/notification/const/types.d.ts +19 -0
- package/dist/types/assets/scripts/notification/index.d.ts +8 -0
- package/dist/types/assets/scripts/notification/positionSync.d.ts +50 -0
- package/dist/types/assets/scripts/notification/utils.d.ts +8 -0
- package/dist/types/assets/scripts/shared/ButtonCloseX.d.ts +5 -0
- package/dist/types/assets/scripts/utils/sanitize.d.ts +22 -0
- package/dist/types/src/components/data-display/data-grid/DataGrid.types.d.ts +7 -0
- package/dist/types/src/components/data-display/table/Table.d.ts +4 -1
- package/dist/types/src/components/data-display/table/types.d.ts +18 -0
- package/dist/types/src/components/data-display/table/useTableScrollbars.d.ts +25 -0
- package/dist/types/src/components/forms-and-input/combo-box/ComboBox.d.ts +8 -0
- package/dist/types/src/components/forms-and-input/select-box/SelectBox.d.ts +13 -0
- package/dist/types/src/components/overlays/dropdown/Dropdown.d.ts +5 -0
- package/dist/types/src/components/overlays/notification/CalloutNotification.d.ts +9 -0
- package/dist/types/src/components/overlays/notification/FloatingNotification.d.ts +15 -0
- package/dist/types/src/components/overlays/notification/Notification.d.ts +18 -3
- package/dist/types/src/components/overlays/notification/host.d.ts +9 -0
- package/dist/types/src/components/overlays/tooltip/Tooltip.d.ts +5 -1
- package/dist/types/src/components/select-dropdown/SelectDropdown.d.ts +6 -0
- package/dist/types/src/contexts/FloatingContext.d.ts +6 -0
- package/dist/types/src/contexts/index.d.ts +1 -0
- package/dist/types/src/hooks/index.d.ts +1 -0
- package/dist/types/src/hooks/useFloatingPosition.d.ts +19 -0
- package/dist/types/src/hooks/usePortalState.d.ts +6 -0
- package/dist/types/src/utils/dropdown/maxSelection.d.ts +24 -0
- package/dist/types/src/utils/dropdown/multiSelect.d.ts +42 -2
- package/dist/ui-admin/assets/styles/style.css +304 -64
- package/package.json +1 -1
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { BaseNotificationOptions } from './const';
|
|
2
|
+
export interface MessageNotificationOptions extends BaseNotificationOptions {
|
|
3
|
+
type?: 'message';
|
|
4
|
+
}
|
|
5
|
+
export declare class MessageNotification {
|
|
6
|
+
private element;
|
|
7
|
+
private options;
|
|
8
|
+
private autoCloseTimer?;
|
|
9
|
+
private featuredIcon?;
|
|
10
|
+
constructor(options: MessageNotificationOptions);
|
|
11
|
+
private createElement;
|
|
12
|
+
private buildTemplate;
|
|
13
|
+
private renderHidePermanentlyButton;
|
|
14
|
+
private renderCloseButton;
|
|
15
|
+
private bindEvents;
|
|
16
|
+
private setupAutoClose;
|
|
17
|
+
getElement(): HTMLElement;
|
|
18
|
+
appendTo(parent: HTMLElement): void;
|
|
19
|
+
remove(): void;
|
|
20
|
+
destroy(): void;
|
|
21
|
+
static create(options: MessageNotificationOptions): MessageNotification;
|
|
22
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { FeaturedIcon } from '../featuredIcon';
|
|
2
|
+
import { sanitizeHtml } from '../utils/sanitize';
|
|
3
|
+
import { CLASS_NAMES, FLOATING_ICON_MAP, MESSAGE_SIZES, SVG_ICONS } from './const';
|
|
4
|
+
import { bindNotificationEvents, createWrapperElement, renderActions, renderSupportingText, setupAutoClose, } from './utils';
|
|
5
|
+
export class MessageNotification {
|
|
6
|
+
constructor(options) {
|
|
7
|
+
this.options = {
|
|
8
|
+
color: 'neutral',
|
|
9
|
+
className: '',
|
|
10
|
+
actions: [],
|
|
11
|
+
autoClose: 0,
|
|
12
|
+
supportingText: undefined,
|
|
13
|
+
...options,
|
|
14
|
+
};
|
|
15
|
+
this.element = this.createElement();
|
|
16
|
+
this.bindEvents();
|
|
17
|
+
this.setupAutoClose();
|
|
18
|
+
}
|
|
19
|
+
createElement() {
|
|
20
|
+
const { title, supportingText, color, className, actions, onClose, onHidePermanently } = this.options;
|
|
21
|
+
// message 타입은 neutral, error, warning, success 4가지 색상만 지원
|
|
22
|
+
let actualColor = color;
|
|
23
|
+
if (color === 'info') {
|
|
24
|
+
actualColor = 'neutral';
|
|
25
|
+
}
|
|
26
|
+
const wrapper = createWrapperElement(CLASS_NAMES.MESSAGE.BASE, actualColor, className);
|
|
27
|
+
const iconFunction = FLOATING_ICON_MAP[actualColor];
|
|
28
|
+
// FeaturedIcon 생성
|
|
29
|
+
let featuredIconElement = null;
|
|
30
|
+
if (iconFunction) {
|
|
31
|
+
const iconSvg = iconFunction(MESSAGE_SIZES.ICON_PIXEL);
|
|
32
|
+
this.featuredIcon = FeaturedIcon.create({
|
|
33
|
+
svgString: iconSvg,
|
|
34
|
+
theme: 'light-circle',
|
|
35
|
+
color: actualColor,
|
|
36
|
+
size: MESSAGE_SIZES.FEATURED_ICON,
|
|
37
|
+
});
|
|
38
|
+
featuredIconElement = this.featuredIcon.getElement();
|
|
39
|
+
}
|
|
40
|
+
wrapper.innerHTML = sanitizeHtml(this.buildTemplate({
|
|
41
|
+
title,
|
|
42
|
+
supportingText,
|
|
43
|
+
actions,
|
|
44
|
+
onClose,
|
|
45
|
+
onHidePermanently,
|
|
46
|
+
}));
|
|
47
|
+
// FeaturedIcon을 content-wrapper에 추가
|
|
48
|
+
if (featuredIconElement) {
|
|
49
|
+
const contentWrapper = wrapper.querySelector(`.${CLASS_NAMES.MESSAGE.CONTENT_WRAPPER}`);
|
|
50
|
+
if (contentWrapper) {
|
|
51
|
+
contentWrapper.insertBefore(featuredIconElement, contentWrapper.firstChild);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return wrapper;
|
|
55
|
+
}
|
|
56
|
+
buildTemplate(params) {
|
|
57
|
+
const { title, supportingText, actions, onClose, onHidePermanently } = params;
|
|
58
|
+
return `
|
|
59
|
+
<div class="${CLASS_NAMES.MESSAGE.CONTAINER}">
|
|
60
|
+
<div class="${CLASS_NAMES.MESSAGE.CONTENT}">
|
|
61
|
+
<div class="${CLASS_NAMES.MESSAGE.CONTENT_WRAPPER}">
|
|
62
|
+
<div class="${CLASS_NAMES.MESSAGE.TEXT_CONTAINER}">
|
|
63
|
+
<span class="${CLASS_NAMES.MESSAGE.TITLE}">${title}</span>
|
|
64
|
+
${renderSupportingText(supportingText, CLASS_NAMES.MESSAGE.SUPPORTING_TEXT)}
|
|
65
|
+
</div>
|
|
66
|
+
</div>
|
|
67
|
+
<div class="${CLASS_NAMES.MESSAGE.ACTIONS_CONTAINER}">
|
|
68
|
+
${actions && actions.length > 0 ? renderActions(actions, CLASS_NAMES.MESSAGE.ACTIONS) : ''}
|
|
69
|
+
</div>
|
|
70
|
+
<div class="${CLASS_NAMES.MESSAGE.ACTIONS_CONTAINER}">
|
|
71
|
+
${this.renderHidePermanentlyButton(onHidePermanently)}
|
|
72
|
+
${this.renderCloseButton(onClose)}
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
`;
|
|
77
|
+
}
|
|
78
|
+
renderHidePermanentlyButton(onHidePermanently) {
|
|
79
|
+
if (!onHidePermanently)
|
|
80
|
+
return '';
|
|
81
|
+
return `
|
|
82
|
+
<button type="button" class="${CLASS_NAMES.COMMON.ACTION_BUTTON} ${CLASS_NAMES.COMMON.ACTION_BUTTON}--text ${CLASS_NAMES.MESSAGE.HIDE_LINK}" data-hide-permanently="true">
|
|
83
|
+
다시 보지 않기
|
|
84
|
+
</button>
|
|
85
|
+
`;
|
|
86
|
+
}
|
|
87
|
+
renderCloseButton(onClose) {
|
|
88
|
+
if (!onClose)
|
|
89
|
+
return '';
|
|
90
|
+
return `
|
|
91
|
+
<button type="button" class="${CLASS_NAMES.MESSAGE.CLOSE_BUTTON}" aria-label="알림 닫기">
|
|
92
|
+
${SVG_ICONS['x-close'](MESSAGE_SIZES.CLOSE_BUTTON).replace('stroke="currentColor"', `stroke="#2F2F30"`)}
|
|
93
|
+
</button>
|
|
94
|
+
`;
|
|
95
|
+
}
|
|
96
|
+
bindEvents() {
|
|
97
|
+
bindNotificationEvents(this.element, this.options.actions, this.options.onClose, () => this.remove());
|
|
98
|
+
// 다시보지 않기 버튼 이벤트 바인딩
|
|
99
|
+
if (this.options.onHidePermanently) {
|
|
100
|
+
const hidePermanentlyButton = this.element.querySelector('[data-hide-permanently="true"]');
|
|
101
|
+
if (hidePermanentlyButton) {
|
|
102
|
+
hidePermanentlyButton.addEventListener('click', () => {
|
|
103
|
+
this.options.onHidePermanently?.();
|
|
104
|
+
this.remove();
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
setupAutoClose() {
|
|
110
|
+
this.autoCloseTimer = setupAutoClose(this.options.autoClose, this.options.onClose, () => this.remove());
|
|
111
|
+
}
|
|
112
|
+
// Public methods
|
|
113
|
+
getElement() {
|
|
114
|
+
return this.element;
|
|
115
|
+
}
|
|
116
|
+
appendTo(parent) {
|
|
117
|
+
parent.appendChild(this.element);
|
|
118
|
+
}
|
|
119
|
+
remove() {
|
|
120
|
+
if (this.autoCloseTimer) {
|
|
121
|
+
clearTimeout(this.autoCloseTimer);
|
|
122
|
+
this.autoCloseTimer = undefined;
|
|
123
|
+
}
|
|
124
|
+
if (this.element?.parentNode) {
|
|
125
|
+
this.element.parentNode.removeChild(this.element);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
destroy() {
|
|
129
|
+
// FeaturedIcon 정리
|
|
130
|
+
if (this.featuredIcon) {
|
|
131
|
+
this.featuredIcon.destroy();
|
|
132
|
+
this.featuredIcon = undefined;
|
|
133
|
+
}
|
|
134
|
+
this.remove();
|
|
135
|
+
}
|
|
136
|
+
// Static factory methods
|
|
137
|
+
static create(options) {
|
|
138
|
+
return new MessageNotification(options);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { BaseNotificationOptions, NotificationColor } from './const';
|
|
2
|
+
export interface NotificationOptions extends BaseNotificationOptions {
|
|
3
|
+
type?: 'full-width' | 'floating' | 'message';
|
|
4
|
+
}
|
|
5
|
+
export declare class NcuaNotification {
|
|
6
|
+
private instance;
|
|
7
|
+
private resolvedType;
|
|
8
|
+
constructor(options: NotificationOptions);
|
|
9
|
+
getElement(): HTMLElement;
|
|
10
|
+
appendTo(parent: HTMLElement): void;
|
|
11
|
+
remove(): void;
|
|
12
|
+
destroy(): void;
|
|
13
|
+
show(parent?: HTMLElement): void;
|
|
14
|
+
static create(options: NotificationOptions): NcuaNotification;
|
|
15
|
+
static createWithColor(color: NotificationColor, title: string, supportingText?: string, options?: Partial<NotificationOptions>): NcuaNotification;
|
|
16
|
+
static success(title: string, supportingText?: string, options?: Partial<NotificationOptions>): NcuaNotification;
|
|
17
|
+
static error(title: string, supportingText?: string, options?: Partial<NotificationOptions>): NcuaNotification;
|
|
18
|
+
static warning(title: string, supportingText?: string, options?: Partial<NotificationOptions>): NcuaNotification;
|
|
19
|
+
static info(title: string, supportingText?: string, options?: Partial<NotificationOptions>): NcuaNotification;
|
|
20
|
+
static neutral(title: string, supportingText?: string, options?: Partial<NotificationOptions>): NcuaNotification;
|
|
21
|
+
static showFullWidth(options: Omit<NotificationOptions, 'type'>): NcuaNotification;
|
|
22
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { FloatingNotification } from './FloatingNotification';
|
|
2
|
+
import { FullWidthNotification } from './FullWidthNotification';
|
|
3
|
+
import { MessageNotification } from './MessageNotification';
|
|
4
|
+
import { mountFloatingNotificationHost } from './positionSync';
|
|
5
|
+
// 통합 Notification 클래스 (글로벌 Web Notifications API와의 식별자 충돌을 피하기 위해 NcuaNotification 으로 명명)
|
|
6
|
+
export class NcuaNotification {
|
|
7
|
+
constructor(options) {
|
|
8
|
+
const { type = 'floating', ...baseOptions } = options;
|
|
9
|
+
this.resolvedType = type;
|
|
10
|
+
if (type === 'message') {
|
|
11
|
+
this.instance = new MessageNotification(baseOptions);
|
|
12
|
+
}
|
|
13
|
+
else if (type === 'full-width') {
|
|
14
|
+
this.instance = new FullWidthNotification(baseOptions);
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
this.instance = new FloatingNotification(baseOptions);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
// 모든 메서드를 instance에 위임
|
|
21
|
+
getElement() {
|
|
22
|
+
return this.instance.getElement();
|
|
23
|
+
}
|
|
24
|
+
appendTo(parent) {
|
|
25
|
+
return this.instance.appendTo(parent);
|
|
26
|
+
}
|
|
27
|
+
remove() {
|
|
28
|
+
return this.instance.remove();
|
|
29
|
+
}
|
|
30
|
+
destroy() {
|
|
31
|
+
return this.instance.destroy();
|
|
32
|
+
}
|
|
33
|
+
show(parent) {
|
|
34
|
+
// 사용자가 부모를 명시한 경우 기존 동작 유지 (legacy 호환).
|
|
35
|
+
if (parent) {
|
|
36
|
+
this.instance.appendTo(parent);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
// §5.1 — floating 은 자동으로 우측 상단 호스트에 append.
|
|
40
|
+
// 시각적으로는 최신 토스트가 상단에 노출되고, 이전 토스트들은 그 아래로 12px 씩 겹쳐 쌓인다
|
|
41
|
+
// (LIFO, §5.4 "최신 상단" 준수. godomall5 등 기존 admin wrapper 와 동일 정책.
|
|
42
|
+
// 겹침 너비는 --ncua-floating-notification-stack-overlap CSS 변수로 오버라이드 가능).
|
|
43
|
+
//
|
|
44
|
+
// SSR 가드는 mountFloatingNotificationHost 내부의 isBrowserEnv() 로 위임 — null 이면
|
|
45
|
+
// 토스트가 표시될 환경이 아니라는 의미이므로 silently return 한다 (document.body 에 append
|
|
46
|
+
// 시도하는 fallthrough 는 SSR 에서 ReferenceError 를 일으키므로 금지).
|
|
47
|
+
if (this.resolvedType === 'floating') {
|
|
48
|
+
const host = mountFloatingNotificationHost();
|
|
49
|
+
if (host) {
|
|
50
|
+
this.instance.appendTo(host);
|
|
51
|
+
}
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
// full-width / message는 기존대로 body에 append.
|
|
55
|
+
this.instance.appendTo(document.body);
|
|
56
|
+
}
|
|
57
|
+
// Static factory methods
|
|
58
|
+
static create(options) {
|
|
59
|
+
return new NcuaNotification(options);
|
|
60
|
+
}
|
|
61
|
+
// Convenience method for creating notifications with specific color
|
|
62
|
+
static createWithColor(color, title, supportingText, options) {
|
|
63
|
+
const autoCloseMap = {
|
|
64
|
+
success: 3000,
|
|
65
|
+
error: 5000,
|
|
66
|
+
warning: 3000,
|
|
67
|
+
info: 3000,
|
|
68
|
+
neutral: 0,
|
|
69
|
+
};
|
|
70
|
+
return new NcuaNotification({
|
|
71
|
+
title,
|
|
72
|
+
supportingText,
|
|
73
|
+
color,
|
|
74
|
+
type: 'floating',
|
|
75
|
+
autoClose: autoCloseMap[color],
|
|
76
|
+
...options,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
// 클래스를 생성하지 않고도 기본 floating 알림 생성을 하기 위한 함수들
|
|
80
|
+
static success(title, supportingText, options) {
|
|
81
|
+
const notification = NcuaNotification.createWithColor('success', title, supportingText, options);
|
|
82
|
+
notification.show();
|
|
83
|
+
return notification;
|
|
84
|
+
}
|
|
85
|
+
static error(title, supportingText, options) {
|
|
86
|
+
const notification = NcuaNotification.createWithColor('error', title, supportingText, options);
|
|
87
|
+
notification.show();
|
|
88
|
+
return notification;
|
|
89
|
+
}
|
|
90
|
+
static warning(title, supportingText, options) {
|
|
91
|
+
const notification = NcuaNotification.createWithColor('warning', title, supportingText, options);
|
|
92
|
+
notification.show();
|
|
93
|
+
return notification;
|
|
94
|
+
}
|
|
95
|
+
static info(title, supportingText, options) {
|
|
96
|
+
const notification = NcuaNotification.createWithColor('info', title, supportingText, options);
|
|
97
|
+
notification.show();
|
|
98
|
+
return notification;
|
|
99
|
+
}
|
|
100
|
+
static neutral(title, supportingText, options) {
|
|
101
|
+
const notification = NcuaNotification.createWithColor('neutral', title, supportingText, options);
|
|
102
|
+
notification.show();
|
|
103
|
+
return notification;
|
|
104
|
+
}
|
|
105
|
+
// showFullWidth method for backward compatibility
|
|
106
|
+
static showFullWidth(options) {
|
|
107
|
+
return new NcuaNotification({
|
|
108
|
+
...options,
|
|
109
|
+
type: 'full-width',
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export declare const CLASS_NAMES: {
|
|
2
|
+
readonly FULL_WIDTH: {
|
|
3
|
+
readonly BASE: "ncua-full-width-notification";
|
|
4
|
+
readonly CONTAINER: "ncua-full-width-notification__container";
|
|
5
|
+
readonly CONTENT: "ncua-full-width-notification__content";
|
|
6
|
+
readonly CONTENT_WRAPPER: "ncua-full-width-notification__content-wrapper";
|
|
7
|
+
readonly ICON: "ncua-full-width-notification__icon";
|
|
8
|
+
readonly TEXT_CONTAINER: "ncua-full-width-notification__text-container";
|
|
9
|
+
readonly TITLE: "ncua-full-width-notification__title";
|
|
10
|
+
readonly SUPPORTING_TEXT: "ncua-full-width-notification__supporting-text";
|
|
11
|
+
readonly ACTIONS_CONTAINER: "ncua-full-width-notification__actions-container";
|
|
12
|
+
readonly ACTIONS: "ncua-full-width-notification__actions";
|
|
13
|
+
readonly CLOSE_BUTTON: "ncua-full-width-notification__close-button";
|
|
14
|
+
};
|
|
15
|
+
readonly FLOATING: {
|
|
16
|
+
readonly BASE: "ncua-floating-notification";
|
|
17
|
+
readonly CONTAINER: "ncua-floating-notification__container";
|
|
18
|
+
readonly CONTENT: "ncua-floating-notification__content";
|
|
19
|
+
readonly TEXT_CONTAINER: "ncua-floating-notification__text-container";
|
|
20
|
+
readonly TITLE_WRAPPER: "ncua-floating-notification__title-wrapper";
|
|
21
|
+
readonly TITLE: "ncua-floating-notification__title";
|
|
22
|
+
readonly SUPPORTING_TEXT: "ncua-floating-notification__supporting-text";
|
|
23
|
+
readonly ACTIONS: "ncua-floating-notification__actions";
|
|
24
|
+
readonly CLOSE_BUTTON: "ncua-floating-notification__close-button";
|
|
25
|
+
};
|
|
26
|
+
readonly MESSAGE: {
|
|
27
|
+
readonly BASE: "ncua-message-notification";
|
|
28
|
+
readonly CONTAINER: "ncua-message-notification__container";
|
|
29
|
+
readonly CONTENT: "ncua-message-notification__content";
|
|
30
|
+
readonly CONTENT_WRAPPER: "ncua-message-notification__content-wrapper";
|
|
31
|
+
readonly ICON: "ncua-message-notification__icon";
|
|
32
|
+
readonly TEXT_CONTAINER: "ncua-message-notification__text-container";
|
|
33
|
+
readonly TITLE: "ncua-message-notification__title";
|
|
34
|
+
readonly SUPPORTING_TEXT: "ncua-message-notification__supporting-text";
|
|
35
|
+
readonly ACTIONS_CONTAINER: "ncua-message-notification__actions-container";
|
|
36
|
+
readonly ACTIONS: "ncua-message-notification__actions";
|
|
37
|
+
readonly HIDE_LINK: "ncua-message-notification__hide-link";
|
|
38
|
+
readonly CLOSE_BUTTON: "ncua-message-notification__close-button";
|
|
39
|
+
};
|
|
40
|
+
readonly COMMON: {
|
|
41
|
+
readonly ACTION_BUTTON: "ncua-notification__action-button";
|
|
42
|
+
};
|
|
43
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// CSS class names
|
|
2
|
+
export const CLASS_NAMES = {
|
|
3
|
+
FULL_WIDTH: {
|
|
4
|
+
BASE: 'ncua-full-width-notification',
|
|
5
|
+
CONTAINER: 'ncua-full-width-notification__container',
|
|
6
|
+
CONTENT: 'ncua-full-width-notification__content',
|
|
7
|
+
CONTENT_WRAPPER: 'ncua-full-width-notification__content-wrapper',
|
|
8
|
+
ICON: 'ncua-full-width-notification__icon',
|
|
9
|
+
TEXT_CONTAINER: 'ncua-full-width-notification__text-container',
|
|
10
|
+
TITLE: 'ncua-full-width-notification__title',
|
|
11
|
+
SUPPORTING_TEXT: 'ncua-full-width-notification__supporting-text',
|
|
12
|
+
ACTIONS_CONTAINER: 'ncua-full-width-notification__actions-container',
|
|
13
|
+
ACTIONS: 'ncua-full-width-notification__actions',
|
|
14
|
+
CLOSE_BUTTON: 'ncua-full-width-notification__close-button',
|
|
15
|
+
},
|
|
16
|
+
FLOATING: {
|
|
17
|
+
BASE: 'ncua-floating-notification',
|
|
18
|
+
CONTAINER: 'ncua-floating-notification__container',
|
|
19
|
+
CONTENT: 'ncua-floating-notification__content',
|
|
20
|
+
TEXT_CONTAINER: 'ncua-floating-notification__text-container',
|
|
21
|
+
TITLE_WRAPPER: 'ncua-floating-notification__title-wrapper',
|
|
22
|
+
TITLE: 'ncua-floating-notification__title',
|
|
23
|
+
SUPPORTING_TEXT: 'ncua-floating-notification__supporting-text',
|
|
24
|
+
ACTIONS: 'ncua-floating-notification__actions',
|
|
25
|
+
CLOSE_BUTTON: 'ncua-floating-notification__close-button',
|
|
26
|
+
},
|
|
27
|
+
MESSAGE: {
|
|
28
|
+
BASE: 'ncua-message-notification',
|
|
29
|
+
CONTAINER: 'ncua-message-notification__container',
|
|
30
|
+
CONTENT: 'ncua-message-notification__content',
|
|
31
|
+
CONTENT_WRAPPER: 'ncua-message-notification__content-wrapper',
|
|
32
|
+
ICON: 'ncua-message-notification__icon',
|
|
33
|
+
TEXT_CONTAINER: 'ncua-message-notification__text-container',
|
|
34
|
+
TITLE: 'ncua-message-notification__title',
|
|
35
|
+
SUPPORTING_TEXT: 'ncua-message-notification__supporting-text',
|
|
36
|
+
ACTIONS_CONTAINER: 'ncua-message-notification__actions-container',
|
|
37
|
+
ACTIONS: 'ncua-message-notification__actions',
|
|
38
|
+
HIDE_LINK: 'ncua-message-notification__hide-link',
|
|
39
|
+
CLOSE_BUTTON: 'ncua-message-notification__close-button',
|
|
40
|
+
},
|
|
41
|
+
COMMON: {
|
|
42
|
+
ACTION_BUTTON: 'ncua-notification__action-button',
|
|
43
|
+
},
|
|
44
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { NotificationColor } from './types';
|
|
2
|
+
export declare const SVG_ICONS: {
|
|
3
|
+
readonly 'pin-02': (size: string) => string;
|
|
4
|
+
readonly 'alert-triangle': (size: string) => string;
|
|
5
|
+
readonly 'alert-circle': (size: string) => string;
|
|
6
|
+
readonly 'check-circle': (size: string) => string;
|
|
7
|
+
readonly 'info-circle': (size: string) => string;
|
|
8
|
+
readonly 'message-chat-square': (size: string) => string;
|
|
9
|
+
readonly 'x-close': (size: string) => string;
|
|
10
|
+
};
|
|
11
|
+
export declare const FLOATING_ICON_MAP: Partial<Record<NotificationColor, (size: string) => string>>;
|
|
12
|
+
export declare const FULL_WIDTH_ICON_MAP: {
|
|
13
|
+
readonly neutral: (size: string) => string;
|
|
14
|
+
readonly error: (size: string) => string;
|
|
15
|
+
readonly warning: (size: string) => string;
|
|
16
|
+
readonly success: (size: string) => string;
|
|
17
|
+
readonly info: (size: string) => string;
|
|
18
|
+
};
|
|
19
|
+
export declare const ICON_MAP: {
|
|
20
|
+
readonly neutral: (size: string) => string;
|
|
21
|
+
readonly error: (size: string) => string;
|
|
22
|
+
readonly warning: (size: string) => string;
|
|
23
|
+
readonly success: (size: string) => string;
|
|
24
|
+
readonly info: (size: string) => string;
|
|
25
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// SVG 아이콘들 (크기는 동적으로 설정)
|
|
2
|
+
export const SVG_ICONS = {
|
|
3
|
+
'pin-02': (size) => `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" fill="none" viewBox="0 0 24 24" stroke="none"><path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8.377 15.616 2.72 21.273m8.974-14.631-1.56 1.56a2 2 0 0 1-.264.242 1 1 0 0 1-.207.111c-.082.032-.17.05-.347.085l-3.665.733c-.952.19-1.428.286-1.65.537a1 1 0 0 0-.243.8c.046.333.39.677 1.076 1.363l7.086 7.086c.686.687 1.03 1.03 1.362 1.076a1 1 0 0 0 .801-.242c.251-.223.346-.7.537-1.651l.733-3.665c.035-.176.053-.265.085-.347a1 1 0 0 1 .11-.207c.051-.072.115-.136.242-.263l1.561-1.561c.082-.082.122-.122.167-.158q.06-.047.126-.085c.05-.029.103-.051.208-.097l2.495-1.069c.727-.312 1.091-.467 1.256-.72a1 1 0 0 0 .144-.747c-.06-.295-.34-.575-.9-1.135l-5.142-5.143c-.56-.56-.84-.84-1.135-.9a1 1 0 0 0-.748.145c-.252.165-.407.529-.72 1.256l-1.068 2.495a2 2 0 0 1-.097.208 1 1 0 0 1-.085.126 2 2 0 0 1-.158.167"></path></svg>`,
|
|
4
|
+
'alert-triangle': (size) => `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" fill="none" viewBox="0 0 24 24" stroke="none"><path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v4m0 4h.01M10.615 3.892 2.39 18.098c-.456.788-.684 1.182-.65 1.506a1 1 0 0 0 .406.705c.263.191.718.191 1.629.191h16.45c.91 0 1.365 0 1.628-.191a1 1 0 0 0 .407-.705c.034-.324-.195-.718-.65-1.506L13.383 3.892c-.454-.785-.681-1.178-.978-1.31a1 1 0 0 0-.812 0c-.297.132-.524.525-.979 1.31"></path></svg>`,
|
|
5
|
+
'alert-circle': (size) => `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" fill="none" viewBox="0 0 24 24" stroke="none"><path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M22 12c0 5.523-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2s10 4.477 10 10"></path></svg>`,
|
|
6
|
+
'check-circle': (size) => `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" fill="none" viewBox="0 0 24 24" stroke="none"><path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m7.5 12 3 3 6-6m5.5 3c0 5.523-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2s10 4.477 10 10"></path></svg>`,
|
|
7
|
+
'info-circle': (size) => `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" fill="none" viewBox="0 0 24 24" stroke="none" color="#5720B7" class="ncua-full-width-notification__icon"><path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 16v-4m0-4h.01M22 12c0 5.523-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2s10 4.477 10 10"></path></svg>`,
|
|
8
|
+
'message-chat-square': (size) => `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" fill="none" viewBox="0 0 24 24" stroke="none" color="#0C111D" class="ncua-full-width-notification__icon"><path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m10 15-3.075 3.114c-.43.434-.644.651-.828.666a.5.5 0 0 1-.421-.172c-.12-.14-.12-.446-.12-1.056v-1.56c0-.548-.449-.944-.99-1.024v0a3 3 0 0 1-2.534-2.533C2 12.219 2 11.96 2 11.445V6.8c0-1.68 0-2.52.327-3.162a3 3 0 0 1 1.311-1.311C4.28 2 5.12 2 6.8 2h7.4c1.68 0 2.52 0 3.162.327a3 3 0 0 1 1.311 1.311C19 4.28 19 5.12 19 6.8V11m0 11-2.176-1.513c-.306-.213-.46-.32-.626-.395a2 2 0 0 0-.462-.145c-.18-.033-.367-.033-.74-.033H13.2c-1.12 0-1.68 0-2.108-.218a2 2 0 0 1-.874-.874C10 18.394 10 17.834 10 16.714V14.2c0-1.12 0-1.68.218-2.108a2 2 0 0 1 .874-.874C11.52 11 12.08 11 13.2 11h5.6c1.12 0 1.68 0 2.108.218a2 2 0 0 1 .874.874C22 12.52 22 13.08 22 14.2v2.714c0 .932 0 1.398-.152 1.766a2 2 0 0 1-1.083 1.082c-.367.152-.833.152-1.765.152z"></path></svg>`,
|
|
9
|
+
'x-close': (size) => `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" fill="none" viewBox="0 0 24 24" stroke="none"><path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M18 6 6 18M6 6l12 12"></path></svg>`,
|
|
10
|
+
};
|
|
11
|
+
export const FLOATING_ICON_MAP = {
|
|
12
|
+
neutral: SVG_ICONS['pin-02'],
|
|
13
|
+
error: SVG_ICONS['alert-triangle'],
|
|
14
|
+
warning: SVG_ICONS['alert-circle'],
|
|
15
|
+
success: SVG_ICONS['check-circle'],
|
|
16
|
+
// info는 floating에서는 지원하지 않음
|
|
17
|
+
};
|
|
18
|
+
export const FULL_WIDTH_ICON_MAP = {
|
|
19
|
+
neutral: SVG_ICONS['message-chat-square'],
|
|
20
|
+
error: SVG_ICONS['alert-triangle'],
|
|
21
|
+
warning: SVG_ICONS['alert-triangle'],
|
|
22
|
+
success: SVG_ICONS['check-circle'],
|
|
23
|
+
info: SVG_ICONS['info-circle'],
|
|
24
|
+
};
|
|
25
|
+
export const ICON_MAP = FULL_WIDTH_ICON_MAP;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export type { NotificationColor, NotificationHierarchy, NotificationAction, BaseNotificationOptions } from './types';
|
|
2
|
+
export { SVG_ICONS, FLOATING_ICON_MAP, FULL_WIDTH_ICON_MAP, ICON_MAP } from './icons';
|
|
3
|
+
export { CLASS_NAMES } from './classNames';
|
|
4
|
+
export { FEATURED_ICON_SIZES, ICON_PIXEL_SIZES, CLOSE_BUTTON_SIZES, CLOSE_BUTTON_SVG_SIZES, FULL_WIDTH_SIZES, MESSAGE_SIZES, getSizes, } from './sizes';
|
|
5
|
+
export { MESSAGE_CLOSE_ICON_COLORS } from './types';
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { SVG_ICONS, FLOATING_ICON_MAP, FULL_WIDTH_ICON_MAP, ICON_MAP } from './icons';
|
|
2
|
+
export { CLASS_NAMES } from './classNames';
|
|
3
|
+
export { FEATURED_ICON_SIZES, ICON_PIXEL_SIZES, CLOSE_BUTTON_SIZES, CLOSE_BUTTON_SVG_SIZES, FULL_WIDTH_SIZES, MESSAGE_SIZES, getSizes, } from './sizes';
|
|
4
|
+
export { MESSAGE_CLOSE_ICON_COLORS } from './types';
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export declare const FEATURED_ICON_SIZES: {
|
|
2
|
+
readonly MOBILE: "md";
|
|
3
|
+
readonly DESKTOP: "sm";
|
|
4
|
+
};
|
|
5
|
+
export declare const ICON_PIXEL_SIZES: {
|
|
6
|
+
readonly MOBILE: "20";
|
|
7
|
+
readonly DESKTOP: "16";
|
|
8
|
+
readonly FULL_WIDTH: "16";
|
|
9
|
+
};
|
|
10
|
+
export declare const CLOSE_BUTTON_SIZES: {
|
|
11
|
+
readonly MOBILE: "sm";
|
|
12
|
+
readonly DESKTOP: "xs";
|
|
13
|
+
};
|
|
14
|
+
export declare const CLOSE_BUTTON_SVG_SIZES: {
|
|
15
|
+
readonly xs: 16;
|
|
16
|
+
readonly sm: 20;
|
|
17
|
+
};
|
|
18
|
+
export declare const FULL_WIDTH_SIZES: {
|
|
19
|
+
readonly ICON: "16";
|
|
20
|
+
readonly CLOSE_BUTTON: "20";
|
|
21
|
+
};
|
|
22
|
+
export declare const MESSAGE_SIZES: {
|
|
23
|
+
readonly FEATURED_ICON: "lg";
|
|
24
|
+
readonly ICON_PIXEL: "24";
|
|
25
|
+
readonly CLOSE_BUTTON: "20";
|
|
26
|
+
};
|
|
27
|
+
export declare const getSizes: {
|
|
28
|
+
readonly featuredIcon: (isMobile: boolean) => "sm" | "md";
|
|
29
|
+
readonly iconPixel: (isMobile: boolean) => "20" | "16";
|
|
30
|
+
readonly closeButton: (isMobile: boolean) => "xs" | "sm";
|
|
31
|
+
readonly closeButtonSvg: (size: keyof typeof CLOSE_BUTTON_SVG_SIZES) => 16 | 20;
|
|
32
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// 알림 컴포넌트 사이즈 관련 상수들
|
|
2
|
+
// FeaturedIcon 사이즈
|
|
3
|
+
export const FEATURED_ICON_SIZES = {
|
|
4
|
+
MOBILE: 'md',
|
|
5
|
+
DESKTOP: 'sm',
|
|
6
|
+
};
|
|
7
|
+
// SVG 아이콘 픽셀 사이즈
|
|
8
|
+
export const ICON_PIXEL_SIZES = {
|
|
9
|
+
MOBILE: '20',
|
|
10
|
+
DESKTOP: '16',
|
|
11
|
+
FULL_WIDTH: '16', // Full-width는 항상 고정
|
|
12
|
+
};
|
|
13
|
+
// 닫기 버튼 사이즈
|
|
14
|
+
export const CLOSE_BUTTON_SIZES = {
|
|
15
|
+
MOBILE: 'sm',
|
|
16
|
+
DESKTOP: 'xs',
|
|
17
|
+
};
|
|
18
|
+
// 닫기 버튼 SVG 픽셀 사이즈
|
|
19
|
+
export const CLOSE_BUTTON_SVG_SIZES = {
|
|
20
|
+
xs: 16,
|
|
21
|
+
sm: 20,
|
|
22
|
+
};
|
|
23
|
+
// Full-width 알림 고정 사이즈
|
|
24
|
+
export const FULL_WIDTH_SIZES = {
|
|
25
|
+
ICON: '16',
|
|
26
|
+
CLOSE_BUTTON: '20',
|
|
27
|
+
};
|
|
28
|
+
// Message 알림 고정 사이즈
|
|
29
|
+
export const MESSAGE_SIZES = {
|
|
30
|
+
FEATURED_ICON: 'lg',
|
|
31
|
+
ICON_PIXEL: '24',
|
|
32
|
+
CLOSE_BUTTON: '20',
|
|
33
|
+
};
|
|
34
|
+
// 사이즈 유틸리티 함수들
|
|
35
|
+
export const getSizes = {
|
|
36
|
+
featuredIcon: (isMobile) => (isMobile ? FEATURED_ICON_SIZES.MOBILE : FEATURED_ICON_SIZES.DESKTOP),
|
|
37
|
+
iconPixel: (isMobile) => (isMobile ? ICON_PIXEL_SIZES.MOBILE : ICON_PIXEL_SIZES.DESKTOP),
|
|
38
|
+
closeButton: (isMobile) => (isMobile ? CLOSE_BUTTON_SIZES.MOBILE : CLOSE_BUTTON_SIZES.DESKTOP),
|
|
39
|
+
closeButtonSvg: (size) => CLOSE_BUTTON_SVG_SIZES[size],
|
|
40
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export type NotificationColor = 'neutral' | 'error' | 'warning' | 'success' | 'info';
|
|
2
|
+
export type NotificationHierarchy = 'link' | 'link-gray';
|
|
3
|
+
export interface NotificationAction {
|
|
4
|
+
label: string;
|
|
5
|
+
onClick: () => void;
|
|
6
|
+
hierarchy?: NotificationHierarchy;
|
|
7
|
+
}
|
|
8
|
+
export interface BaseNotificationOptions {
|
|
9
|
+
title: string;
|
|
10
|
+
supportingText?: string;
|
|
11
|
+
color?: NotificationColor;
|
|
12
|
+
onClose?: () => void;
|
|
13
|
+
className?: string;
|
|
14
|
+
actions?: NotificationAction[];
|
|
15
|
+
autoClose?: number;
|
|
16
|
+
supportTextLink?: string;
|
|
17
|
+
onHidePermanently?: () => void;
|
|
18
|
+
}
|
|
19
|
+
export declare const MESSAGE_CLOSE_ICON_COLORS: Record<NotificationColor, string>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type { BaseNotificationOptions, NotificationAction, NotificationColor, NotificationHierarchy } from './const';
|
|
2
|
+
export { CLASS_NAMES, FLOATING_ICON_MAP, FULL_WIDTH_ICON_MAP, ICON_MAP, SVG_ICONS } from './const';
|
|
3
|
+
export { FloatingNotification, type FloatingNotificationOptions } from './FloatingNotification';
|
|
4
|
+
export { FullWidthNotification, type FullWidthNotificationOptions } from './FullWidthNotification';
|
|
5
|
+
export { MessageNotification, type MessageNotificationOptions } from './MessageNotification';
|
|
6
|
+
export { NcuaNotification as Notification, type NotificationOptions } from './Notification';
|
|
7
|
+
export { mountFloatingNotificationHost, startPositionSync, stopPositionSync, syncNow, } from './positionSync';
|
|
8
|
+
export * from './utils';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { CLASS_NAMES, FLOATING_ICON_MAP, FULL_WIDTH_ICON_MAP, ICON_MAP, SVG_ICONS } from './const';
|
|
2
|
+
export { FloatingNotification } from './FloatingNotification';
|
|
3
|
+
export { FullWidthNotification } from './FullWidthNotification';
|
|
4
|
+
export { MessageNotification } from './MessageNotification';
|
|
5
|
+
export { NcuaNotification as Notification } from './Notification';
|
|
6
|
+
// DES-SPEC-027 §5.1 — Floating notification 호스트 + 위치 동기화 (vanilla/React 공유 진입점).
|
|
7
|
+
// mountFloatingNotificationHost 가 자동으로 startPositionSync 를 호출하므로 일반 사용자는
|
|
8
|
+
// start/stop/syncNow 를 직접 부를 일이 없다 — HMR/SSR/테스트 정리용으로만 노출.
|
|
9
|
+
export { mountFloatingNotificationHost, startPositionSync, stopPositionSync, syncNow, } from './positionSync';
|
|
10
|
+
export * from './utils';
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Floating Notification 호스트 싱글톤 + 위치 동기화
|
|
3
|
+
*
|
|
4
|
+
* 본 모듈은 다음 두 가지 책임을 가진다:
|
|
5
|
+
* 1. `.ncua-floating-notification-host` 싱글톤을 document.body 에 생성·재사용 (mountFloatingNotificationHost).
|
|
6
|
+
* 2. `.ncua-page-title` 의 rect.bottom 을 추적해 `--ncua-page-title-bottom` CSS 변수로 갱신.
|
|
7
|
+
*
|
|
8
|
+
* 두 책임을 한 파일에 두는 이유: 호스트가 처음 생성될 때 positionSync 가 함께 시작되며,
|
|
9
|
+
* React 측 훅과 vanilla 측 `NcuaNotification.show()` 가 동일 함수를 공유해 호스트 생성 로직이
|
|
10
|
+
* 한 곳에서만 유지되도록 한다.
|
|
11
|
+
*
|
|
12
|
+
* NCDS DES-SPEC-027 §5.1
|
|
13
|
+
* · Toast top 좌표 = PageTitle.bottom + 16px (viewport 기준).
|
|
14
|
+
* · PageTitle 이 sticky 로 Default/Fixed 변형 사이 높이가 변동(120/56px)하므로 단순 height
|
|
15
|
+
* 가 아닌 getBoundingClientRect().bottom 을 기준으로 동적 계산해야 한다.
|
|
16
|
+
*
|
|
17
|
+
* 동작 특성:
|
|
18
|
+
* - 다중 호출 idempotent. ensure/start 가 여러 번 호출되어도 호스트와 리스너는 한 벌만.
|
|
19
|
+
* - scroll/resize 는 rAF 로 throttle.
|
|
20
|
+
* - PageTitle 추가/제거를 MutationObserver 로 감지해 재바인딩 — body subtree 변경마다
|
|
21
|
+
* 호출되므로 콜백 자체도 rAF 로 한 프레임당 한 번만 querySelector 가 돌도록 보호.
|
|
22
|
+
* - SSR 가드: window/document 미정의 환경에서 ensure/start 는 no-op.
|
|
23
|
+
*
|
|
24
|
+
* 내부 상태는 모듈 최상단에 흩어진 `let` 대신 한 객체로 묶어 테스트/HMR 에서 일괄 초기화·검사하기
|
|
25
|
+
* 쉽도록 한다. 외부에는 함수만 노출되므로 캡슐화는 유지된다.
|
|
26
|
+
*/
|
|
27
|
+
/**
|
|
28
|
+
* `.ncua-floating-notification-host` 싱글톤을 보장한다.
|
|
29
|
+
* **side-effect 함수** — 단순 조회가 아니라 다음을 모두 수행:
|
|
30
|
+
* · document.body 에 `<div class="ncua-floating-notification-host">` 를 (필요 시) append
|
|
31
|
+
* · 첫 호출 시 startPositionSync() 로 window scroll/resize/MutationObserver/ResizeObserver 부착
|
|
32
|
+
* · 한 번 만든 호스트는 페이지 lifetime 동안 유지 — 컴포넌트 언마운트 시에도 제거하지 않는다
|
|
33
|
+
* (다음 토스트의 mount 비용을 줄이기 위해 의도된 설계)
|
|
34
|
+
*
|
|
35
|
+
* React 측 hook 과 vanilla 측 `NcuaNotification.show()` 가 모두 이 함수를 사용해 호스트 생성
|
|
36
|
+
* 진입점이 한 곳만 존재한다.
|
|
37
|
+
*
|
|
38
|
+
* @returns 생성되었거나 이미 존재하는 호스트 엘리먼트. SSR 환경에서는 null.
|
|
39
|
+
*/
|
|
40
|
+
export declare function mountFloatingNotificationHost(): HTMLElement | null;
|
|
41
|
+
/**
|
|
42
|
+
* PageTitle ↔ Floating Host 위치 동기화 시작 (idempotent).
|
|
43
|
+
* `mountFloatingNotificationHost()` 가 자동 호출하므로 일반 사용자는 직접 부를 필요 없음.
|
|
44
|
+
* SSR/테스트에서 수동 제어가 필요할 때만 export 됨.
|
|
45
|
+
*/
|
|
46
|
+
export declare function startPositionSync(): void;
|
|
47
|
+
/** 동기화 중단 + 리소스 해제. 테스트 종료/HMR 정리 등에 사용. */
|
|
48
|
+
export declare function stopPositionSync(): void;
|
|
49
|
+
/** 외부에서 PageTitle.bottom 값을 강제로 다시 측정해 반영하고 싶을 때. */
|
|
50
|
+
export declare function syncNow(): void;
|