@blastlabs/utils 1.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +267 -0
- package/dist/components/dev/ApiLogger.d.ts +136 -0
- package/dist/components/dev/ApiLogger.d.ts.map +1 -0
- package/dist/components/dev/ApiLogger.js +408 -0
- package/dist/components/dev/DevPanel.d.ts +32 -0
- package/dist/components/dev/DevPanel.d.ts.map +1 -0
- package/dist/components/dev/DevPanel.js +196 -0
- package/dist/components/dev/FormDevTools/FormDevTools.d.ts +136 -0
- package/dist/components/dev/FormDevTools/FormDevTools.d.ts.map +1 -0
- package/dist/components/dev/FormDevTools/FormDevTools.js +442 -0
- package/dist/components/dev/FormDevTools/index.d.ts +3 -0
- package/dist/components/dev/FormDevTools/index.d.ts.map +1 -0
- package/dist/components/dev/FormDevTools/index.js +1 -0
- package/dist/components/dev/FormDevTools/styles.d.ts +45 -0
- package/dist/components/dev/FormDevTools/styles.d.ts.map +1 -0
- package/dist/components/dev/FormDevTools/styles.js +197 -0
- package/dist/components/dev/IdSelector.d.ts +50 -0
- package/dist/components/dev/IdSelector.d.ts.map +1 -0
- package/dist/components/dev/IdSelector.js +129 -0
- package/dist/components/dev/WindowSizeDisplay.d.ts +44 -0
- package/dist/components/dev/WindowSizeDisplay.d.ts.map +1 -0
- package/dist/components/dev/WindowSizeDisplay.js +74 -0
- package/dist/components/dev/ZIndexDebugger.d.ts +32 -0
- package/dist/components/dev/ZIndexDebugger.d.ts.map +1 -0
- package/dist/components/dev/ZIndexDebugger.js +184 -0
- package/dist/components/dev/index.d.ts +15 -0
- package/dist/components/dev/index.d.ts.map +1 -0
- package/dist/components/dev/index.js +12 -0
- package/dist/components/index.d.ts +8 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +7 -0
- package/dist/date/index.d.ts +64 -0
- package/dist/date/index.d.ts.map +1 -0
- package/dist/date/index.js +92 -0
- package/dist/date/index.test.d.ts +2 -0
- package/dist/date/index.test.d.ts.map +1 -0
- package/dist/date/index.test.js +166 -0
- package/dist/form/__tests__/formatter.test.d.ts +2 -0
- package/dist/form/__tests__/formatter.test.d.ts.map +1 -0
- package/dist/form/__tests__/formatter.test.js +74 -0
- package/dist/form/__tests__/helpers.test.d.ts +2 -0
- package/dist/form/__tests__/helpers.test.d.ts.map +1 -0
- package/dist/form/__tests__/helpers.test.js +42 -0
- package/dist/form/__tests__/validation.test.d.ts +2 -0
- package/dist/form/__tests__/validation.test.d.ts.map +1 -0
- package/dist/form/__tests__/validation.test.js +67 -0
- package/dist/form/formatter.d.ts +34 -0
- package/dist/form/formatter.d.ts.map +1 -0
- package/dist/form/formatter.js +76 -0
- package/dist/form/helpers.d.ts +16 -0
- package/dist/form/helpers.d.ts.map +1 -0
- package/dist/form/helpers.js +34 -0
- package/dist/form/index.d.ts +9 -0
- package/dist/form/index.d.ts.map +1 -0
- package/dist/form/index.js +11 -0
- package/dist/form/validation.d.ts +33 -0
- package/dist/form/validation.d.ts.map +1 -0
- package/dist/form/validation.js +56 -0
- package/dist/hooks/index.d.ts +19 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +23 -0
- package/dist/hooks/useClickOutside.d.ts +49 -0
- package/dist/hooks/useClickOutside.d.ts.map +1 -0
- package/dist/hooks/useClickOutside.js +94 -0
- package/dist/hooks/useCopyToClipboard.d.ts +67 -0
- package/dist/hooks/useCopyToClipboard.d.ts.map +1 -0
- package/dist/hooks/useCopyToClipboard.js +79 -0
- package/dist/hooks/useDebounce.d.ts +47 -0
- package/dist/hooks/useDebounce.d.ts.map +1 -0
- package/dist/hooks/useDebounce.js +60 -0
- package/dist/hooks/useEventListener.d.ts +79 -0
- package/dist/hooks/useEventListener.d.ts.map +1 -0
- package/dist/hooks/useEventListener.js +33 -0
- package/dist/hooks/useIntersectionObserver.d.ts +109 -0
- package/dist/hooks/useIntersectionObserver.d.ts.map +1 -0
- package/dist/hooks/useIntersectionObserver.js +128 -0
- package/dist/hooks/useLocalStorage.d.ts +19 -0
- package/dist/hooks/useLocalStorage.d.ts.map +1 -0
- package/dist/hooks/useLocalStorage.js +91 -0
- package/dist/hooks/useMediaQuery.d.ts +56 -0
- package/dist/hooks/useMediaQuery.d.ts.map +1 -0
- package/dist/hooks/useMediaQuery.js +104 -0
- package/dist/hooks/usePrevious.d.ts +58 -0
- package/dist/hooks/usePrevious.d.ts.map +1 -0
- package/dist/hooks/usePrevious.js +67 -0
- package/dist/hooks/useSessionStorage.d.ts +19 -0
- package/dist/hooks/useSessionStorage.d.ts.map +1 -0
- package/dist/hooks/useSessionStorage.js +85 -0
- package/dist/hooks/useThrottle.d.ts +57 -0
- package/dist/hooks/useThrottle.d.ts.map +1 -0
- package/dist/hooks/useThrottle.js +80 -0
- package/dist/hooks/useToggle.d.ts +49 -0
- package/dist/hooks/useToggle.d.ts.map +1 -0
- package/dist/hooks/useToggle.js +56 -0
- package/dist/hooks/useWindowSize.d.ts +58 -0
- package/dist/hooks/useWindowSize.d.ts.map +1 -0
- package/dist/hooks/useWindowSize.js +79 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/mock/form.d.ts +41 -0
- package/dist/mock/form.d.ts.map +1 -0
- package/dist/mock/form.js +195 -0
- package/dist/mock/generators.d.ts +112 -0
- package/dist/mock/generators.d.ts.map +1 -0
- package/dist/mock/generators.js +195 -0
- package/dist/mock/index.d.ts +8 -0
- package/dist/mock/index.d.ts.map +1 -0
- package/dist/mock/index.js +9 -0
- package/dist/number/format.d.ts +116 -0
- package/dist/number/format.d.ts.map +1 -0
- package/dist/number/format.js +165 -0
- package/dist/number/index.d.ts +7 -0
- package/dist/number/index.d.ts.map +1 -0
- package/dist/number/index.js +7 -0
- package/dist/string/__tests__/case.test.d.ts +2 -0
- package/dist/string/__tests__/case.test.d.ts.map +1 -0
- package/dist/string/__tests__/case.test.js +61 -0
- package/dist/string/__tests__/manipulation.test.d.ts +2 -0
- package/dist/string/__tests__/manipulation.test.d.ts.map +1 -0
- package/dist/string/__tests__/manipulation.test.js +109 -0
- package/dist/string/__tests__/validation.test.d.ts +2 -0
- package/dist/string/__tests__/validation.test.d.ts.map +1 -0
- package/dist/string/__tests__/validation.test.js +101 -0
- package/dist/string/case.d.ts +42 -0
- package/dist/string/case.d.ts.map +1 -0
- package/dist/string/case.js +71 -0
- package/dist/string/index.d.ts +9 -0
- package/dist/string/index.d.ts.map +1 -0
- package/dist/string/index.js +11 -0
- package/dist/string/manipulation.d.ts +61 -0
- package/dist/string/manipulation.d.ts.map +1 -0
- package/dist/string/manipulation.js +106 -0
- package/dist/string/validation.d.ts +79 -0
- package/dist/string/validation.d.ts.map +1 -0
- package/dist/string/validation.js +115 -0
- package/package.json +86 -0
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import React, { useState, useEffect } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* z-index 값을 시각화하는 개발용 컴포넌트
|
|
4
|
+
* 페이지의 모든 요소의 z-index를 하이라이트하고 목록으로 표시합니다.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```tsx
|
|
8
|
+
* // Vite 프로젝트
|
|
9
|
+
* import { ZIndexDebugger } from 'goodchuck-utils/components/dev';
|
|
10
|
+
*
|
|
11
|
+
* function App() {
|
|
12
|
+
* return (
|
|
13
|
+
* <div>
|
|
14
|
+
* {import.meta.env.DEV && <ZIndexDebugger />}
|
|
15
|
+
* </div>
|
|
16
|
+
* );
|
|
17
|
+
* }
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```tsx
|
|
22
|
+
* // Create React App 프로젝트
|
|
23
|
+
* {process.env.NODE_ENV === 'development' && <ZIndexDebugger position="top-right" />}
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export default function ZIndexDebugger({ position = 'bottom-left' }) {
|
|
27
|
+
const [isActive, setIsActive] = useState(false);
|
|
28
|
+
const [elements, setElements] = useState([]);
|
|
29
|
+
const [hoveredElement, setHoveredElement] = useState(null);
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
if (!isActive) {
|
|
32
|
+
setElements([]);
|
|
33
|
+
setHoveredElement(null);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const scanElements = () => {
|
|
37
|
+
const allElements = document.querySelectorAll('*');
|
|
38
|
+
const elementsWithZIndex = [];
|
|
39
|
+
allElements.forEach((el) => {
|
|
40
|
+
if (!(el instanceof HTMLElement))
|
|
41
|
+
return;
|
|
42
|
+
const computedStyle = window.getComputedStyle(el);
|
|
43
|
+
const zIndex = computedStyle.zIndex;
|
|
44
|
+
// z-index가 설정된 요소만 수집 (auto가 아닌 경우)
|
|
45
|
+
if (zIndex !== 'auto' && zIndex !== '0') {
|
|
46
|
+
elementsWithZIndex.push({
|
|
47
|
+
element: el,
|
|
48
|
+
zIndex,
|
|
49
|
+
tagName: el.tagName.toLowerCase(),
|
|
50
|
+
id: el.id || undefined,
|
|
51
|
+
className: el.className || undefined,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
// z-index 값으로 정렬 (높은 순)
|
|
56
|
+
elementsWithZIndex.sort((a, b) => {
|
|
57
|
+
const zA = parseInt(a.zIndex) || 0;
|
|
58
|
+
const zB = parseInt(b.zIndex) || 0;
|
|
59
|
+
return zB - zA;
|
|
60
|
+
});
|
|
61
|
+
setElements(elementsWithZIndex);
|
|
62
|
+
};
|
|
63
|
+
scanElements();
|
|
64
|
+
// DOM 변경 감지
|
|
65
|
+
const observer = new MutationObserver(scanElements);
|
|
66
|
+
observer.observe(document.body, {
|
|
67
|
+
childList: true,
|
|
68
|
+
subtree: true,
|
|
69
|
+
attributes: true,
|
|
70
|
+
attributeFilter: ['style', 'class'],
|
|
71
|
+
});
|
|
72
|
+
return () => observer.disconnect();
|
|
73
|
+
}, [isActive]);
|
|
74
|
+
// 호버된 요소 하이라이트
|
|
75
|
+
useEffect(() => {
|
|
76
|
+
if (!hoveredElement)
|
|
77
|
+
return;
|
|
78
|
+
const originalOutline = hoveredElement.style.outline;
|
|
79
|
+
const originalOutlineOffset = hoveredElement.style.outlineOffset;
|
|
80
|
+
hoveredElement.style.outline = '3px solid #f59e0b';
|
|
81
|
+
hoveredElement.style.outlineOffset = '2px';
|
|
82
|
+
return () => {
|
|
83
|
+
hoveredElement.style.outline = originalOutline;
|
|
84
|
+
hoveredElement.style.outlineOffset = originalOutlineOffset;
|
|
85
|
+
};
|
|
86
|
+
}, [hoveredElement]);
|
|
87
|
+
const positionStyles = {
|
|
88
|
+
'top-left': { top: 16, left: 16 },
|
|
89
|
+
'top-right': { top: 16, right: 16 },
|
|
90
|
+
'bottom-left': { bottom: 16, left: 16 },
|
|
91
|
+
'bottom-right': { bottom: 16, right: 16 },
|
|
92
|
+
};
|
|
93
|
+
const containerStyle = {
|
|
94
|
+
position: 'fixed',
|
|
95
|
+
...positionStyles[position],
|
|
96
|
+
zIndex: 999999,
|
|
97
|
+
fontFamily: 'system-ui, -apple-system, sans-serif',
|
|
98
|
+
};
|
|
99
|
+
const buttonStyle = {
|
|
100
|
+
padding: '8px 16px',
|
|
101
|
+
backgroundColor: isActive ? '#ef4444' : '#3b82f6',
|
|
102
|
+
color: 'white',
|
|
103
|
+
border: 'none',
|
|
104
|
+
borderRadius: '8px',
|
|
105
|
+
cursor: 'pointer',
|
|
106
|
+
fontSize: '13px',
|
|
107
|
+
fontWeight: 600,
|
|
108
|
+
boxShadow: '0 4px 6px rgba(0, 0, 0, 0.1)',
|
|
109
|
+
transition: 'background-color 0.2s',
|
|
110
|
+
};
|
|
111
|
+
const panelStyle = {
|
|
112
|
+
marginTop: '8px',
|
|
113
|
+
backgroundColor: 'white',
|
|
114
|
+
borderRadius: '12px',
|
|
115
|
+
boxShadow: '0 10px 25px rgba(0, 0, 0, 0.15)',
|
|
116
|
+
border: '1px solid #e5e7eb',
|
|
117
|
+
width: '320px',
|
|
118
|
+
maxHeight: '400px',
|
|
119
|
+
overflow: 'hidden',
|
|
120
|
+
display: 'flex',
|
|
121
|
+
flexDirection: 'column',
|
|
122
|
+
};
|
|
123
|
+
const headerStyle = {
|
|
124
|
+
padding: '12px 16px',
|
|
125
|
+
borderBottom: '1px solid #e5e7eb',
|
|
126
|
+
fontWeight: 'bold',
|
|
127
|
+
fontSize: '14px',
|
|
128
|
+
color: '#111827',
|
|
129
|
+
backgroundColor: '#f9fafb',
|
|
130
|
+
};
|
|
131
|
+
const listContainerStyle = {
|
|
132
|
+
overflowY: 'auto',
|
|
133
|
+
maxHeight: '350px',
|
|
134
|
+
};
|
|
135
|
+
const itemStyle = (isHovered) => ({
|
|
136
|
+
padding: '10px 16px',
|
|
137
|
+
borderBottom: '1px solid #f3f4f6',
|
|
138
|
+
cursor: 'pointer',
|
|
139
|
+
backgroundColor: isHovered ? '#fef3c7' : 'white',
|
|
140
|
+
transition: 'background-color 0.15s',
|
|
141
|
+
});
|
|
142
|
+
const zIndexBadgeStyle = {
|
|
143
|
+
display: 'inline-block',
|
|
144
|
+
padding: '2px 8px',
|
|
145
|
+
backgroundColor: '#dbeafe',
|
|
146
|
+
color: '#1e40af',
|
|
147
|
+
borderRadius: '6px',
|
|
148
|
+
fontSize: '12px',
|
|
149
|
+
fontWeight: 'bold',
|
|
150
|
+
fontFamily: 'monospace',
|
|
151
|
+
marginRight: '8px',
|
|
152
|
+
};
|
|
153
|
+
const tagStyle = {
|
|
154
|
+
fontSize: '12px',
|
|
155
|
+
color: '#6b7280',
|
|
156
|
+
fontFamily: 'monospace',
|
|
157
|
+
};
|
|
158
|
+
const getElementLabel = (info) => {
|
|
159
|
+
let label = info.tagName;
|
|
160
|
+
if (info.id)
|
|
161
|
+
label += `#${info.id}`;
|
|
162
|
+
if (info.className && typeof info.className === 'string') {
|
|
163
|
+
const classes = info.className.split(' ').filter(Boolean).slice(0, 2);
|
|
164
|
+
if (classes.length > 0) {
|
|
165
|
+
label += `.${classes.join('.')}`;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return label.length > 40 ? label.slice(0, 40) + '...' : label;
|
|
169
|
+
};
|
|
170
|
+
const handleElementClick = (element) => {
|
|
171
|
+
element.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
|
172
|
+
};
|
|
173
|
+
return (React.createElement("div", { style: containerStyle },
|
|
174
|
+
React.createElement("button", { onClick: () => setIsActive(!isActive), style: buttonStyle, onMouseEnter: (e) => (e.currentTarget.style.backgroundColor = isActive ? '#dc2626' : '#2563eb'), onMouseLeave: (e) => (e.currentTarget.style.backgroundColor = isActive ? '#ef4444' : '#3b82f6') }, isActive ? '🔴 Z-Index 디버거 종료' : '🔍 Z-Index 디버거'),
|
|
175
|
+
isActive && (React.createElement("div", { style: panelStyle },
|
|
176
|
+
React.createElement("div", { style: headerStyle },
|
|
177
|
+
"\uD83D\uDCCA Z-Index \uBAA9\uB85D (",
|
|
178
|
+
elements.length,
|
|
179
|
+
"\uAC1C)"),
|
|
180
|
+
React.createElement("div", { style: listContainerStyle }, elements.length === 0 ? (React.createElement("div", { style: { padding: '20px', textAlign: 'center', color: '#9ca3af', fontSize: '13px' } }, "z-index\uAC00 \uC124\uC815\uB41C \uC694\uC18C\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.")) : (elements.map((info, index) => (React.createElement("div", { key: index, style: itemStyle(hoveredElement === info.element), onMouseEnter: () => setHoveredElement(info.element), onMouseLeave: () => setHoveredElement(null), onClick: () => handleElementClick(info.element) },
|
|
181
|
+
React.createElement("div", null,
|
|
182
|
+
React.createElement("span", { style: zIndexBadgeStyle }, info.zIndex),
|
|
183
|
+
React.createElement("span", { style: tagStyle }, getElementLabel(info))))))))))));
|
|
184
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Development Components
|
|
3
|
+
*
|
|
4
|
+
* 개발 환경에서 사용하는 유틸리티 컴포넌트들입니다.
|
|
5
|
+
* production 환경에서는 제외하는 것을 권장합니다.
|
|
6
|
+
*/
|
|
7
|
+
export { default as IdSelector } from './IdSelector';
|
|
8
|
+
export { default as WindowSizeDisplay } from './WindowSizeDisplay';
|
|
9
|
+
export { default as DevPanel } from './DevPanel';
|
|
10
|
+
export { default as ZIndexDebugger } from './ZIndexDebugger';
|
|
11
|
+
export { default as ApiLogger, addApiLog, clearApiLogs } from './ApiLogger';
|
|
12
|
+
export { default as FormDevTools } from './FormDevTools';
|
|
13
|
+
export type { FormDevToolsProps, UseFormReturn as FormDevToolsUseFormReturn } from './FormDevTools';
|
|
14
|
+
export type { ApiLogEntry } from './ApiLogger';
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/dev/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACnE,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC5E,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACzD,YAAY,EAAE,iBAAiB,EAAE,aAAa,IAAI,yBAAyB,EAAE,MAAM,gBAAgB,CAAC;AACpG,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Development Components
|
|
3
|
+
*
|
|
4
|
+
* 개발 환경에서 사용하는 유틸리티 컴포넌트들입니다.
|
|
5
|
+
* production 환경에서는 제외하는 것을 권장합니다.
|
|
6
|
+
*/
|
|
7
|
+
export { default as IdSelector } from './IdSelector';
|
|
8
|
+
export { default as WindowSizeDisplay } from './WindowSizeDisplay';
|
|
9
|
+
export { default as DevPanel } from './DevPanel';
|
|
10
|
+
export { default as ZIndexDebugger } from './ZIndexDebugger';
|
|
11
|
+
export { default as ApiLogger, addApiLog, clearApiLogs } from './ApiLogger';
|
|
12
|
+
export { default as FormDevTools } from './FormDevTools';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,cAAc,OAAO,CAAC"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import dayjs from 'dayjs';
|
|
2
|
+
import 'dayjs/locale/ko';
|
|
3
|
+
/**
|
|
4
|
+
* 날짜를 지정된 포맷으로 변환
|
|
5
|
+
* @param date - 변환할 날짜 (Date, string, number)
|
|
6
|
+
* @param format - 포맷 문자열 (기본값: 'YYYY-MM-DD HH:mm:ss')
|
|
7
|
+
*/
|
|
8
|
+
export declare function formatDate(date?: Date | string | number, format?: string): string;
|
|
9
|
+
/**
|
|
10
|
+
* 현재 날짜/시간 반환
|
|
11
|
+
* @param format - 포맷 문자열 (선택)
|
|
12
|
+
*/
|
|
13
|
+
export declare function now(format?: string): string | Date;
|
|
14
|
+
/**
|
|
15
|
+
* 상대 시간 반환 (예: "3시간 전")
|
|
16
|
+
* @param date - 기준 날짜
|
|
17
|
+
* @param locale - 로케일 (기본값: 'ko')
|
|
18
|
+
*/
|
|
19
|
+
export declare function fromNow(date: Date | string | number, locale?: string): string;
|
|
20
|
+
/**
|
|
21
|
+
* 두 날짜 사이의 차이 계산
|
|
22
|
+
* @param date1 - 첫 번째 날짜
|
|
23
|
+
* @param date2 - 두 번째 날짜
|
|
24
|
+
* @param unit - 단위 ('day', 'hour', 'minute' 등)
|
|
25
|
+
*/
|
|
26
|
+
export declare function diffDate(date1: Date | string | number, date2: Date | string | number, unit?: dayjs.OpUnitType): number;
|
|
27
|
+
/**
|
|
28
|
+
* 날짜에 시간 더하기
|
|
29
|
+
* @param date - 기준 날짜
|
|
30
|
+
* @param value - 더할 값
|
|
31
|
+
* @param unit - 단위 ('day', 'hour', 'minute' 등)
|
|
32
|
+
*/
|
|
33
|
+
export declare function addDate(date: Date | string | number, value: number, unit?: dayjs.ManipulateType): Date;
|
|
34
|
+
/**
|
|
35
|
+
* 날짜에 시간 빼기
|
|
36
|
+
* @param date - 기준 날짜
|
|
37
|
+
* @param value - 뺄 값
|
|
38
|
+
* @param unit - 단위 ('day', 'hour', 'minute' 등)
|
|
39
|
+
*/
|
|
40
|
+
export declare function subtractDate(date: Date | string | number, value: number, unit?: dayjs.ManipulateType): Date;
|
|
41
|
+
/**
|
|
42
|
+
* 날짜가 특정 날짜보다 이전인지 확인
|
|
43
|
+
*/
|
|
44
|
+
export declare function isBefore(date1: Date | string | number, date2: Date | string | number): boolean;
|
|
45
|
+
/**
|
|
46
|
+
* 날짜가 특정 날짜보다 이후인지 확인
|
|
47
|
+
*/
|
|
48
|
+
export declare function isAfter(date1: Date | string | number, date2: Date | string | number): boolean;
|
|
49
|
+
/**
|
|
50
|
+
* 두 날짜가 같은지 확인
|
|
51
|
+
* @param unit - 비교 단위 (기본값: 'millisecond')
|
|
52
|
+
*/
|
|
53
|
+
export declare function isSame(date1: Date | string | number, date2: Date | string | number, unit?: dayjs.OpUnitType): boolean;
|
|
54
|
+
/**
|
|
55
|
+
* 날짜가 유효한지 확인
|
|
56
|
+
*/
|
|
57
|
+
export declare function isValidDate(date: any): boolean;
|
|
58
|
+
/**
|
|
59
|
+
* 타임존 변환
|
|
60
|
+
* @param date - 변환할 날짜
|
|
61
|
+
* @param tz - 타임존 (예: 'Asia/Seoul')
|
|
62
|
+
*/
|
|
63
|
+
export declare function toTimezone(date: Date | string | number, tz: string): Date;
|
|
64
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/date/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,OAAO,iBAAiB,CAAC;AAMzB;;;;GAIG;AACH,wBAAgB,UAAU,CACxB,IAAI,GAAE,IAAI,GAAG,MAAM,GAAG,MAAmB,EACzC,MAAM,GAAE,MAA8B,GACrC,MAAM,CAER;AAED;;;GAGG;AACH,wBAAgB,GAAG,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGlD;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,EAAE,MAAM,GAAE,MAAa,GAAG,MAAM,CAEnF;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CACtB,KAAK,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,EAC7B,KAAK,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,EAC7B,IAAI,GAAE,KAAK,CAAC,UAAkB,GAC7B,MAAM,CAER;AAED;;;;;GAKG;AACH,wBAAgB,OAAO,CACrB,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,EAC5B,KAAK,EAAE,MAAM,EACb,IAAI,GAAE,KAAK,CAAC,cAAsB,GACjC,IAAI,CAEN;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,EAC5B,KAAK,EAAE,MAAM,EACb,IAAI,GAAE,KAAK,CAAC,cAAsB,GACjC,IAAI,CAEN;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,EAAE,KAAK,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAE9F;AAED;;GAEG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,EAAE,KAAK,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAE7F;AAED;;;GAGG;AACH,wBAAgB,MAAM,CACpB,KAAK,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,EAC7B,KAAK,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,EAC7B,IAAI,GAAE,KAAK,CAAC,UAA0B,GACrC,OAAO,CAET;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,GAAG,GAAG,OAAO,CAE9C;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAEzE"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import dayjs from 'dayjs';
|
|
2
|
+
import utc from 'dayjs/plugin/utc';
|
|
3
|
+
import timezone from 'dayjs/plugin/timezone';
|
|
4
|
+
import relativeTime from 'dayjs/plugin/relativeTime';
|
|
5
|
+
import 'dayjs/locale/ko';
|
|
6
|
+
dayjs.extend(utc);
|
|
7
|
+
dayjs.extend(timezone);
|
|
8
|
+
dayjs.extend(relativeTime);
|
|
9
|
+
/**
|
|
10
|
+
* 날짜를 지정된 포맷으로 변환
|
|
11
|
+
* @param date - 변환할 날짜 (Date, string, number)
|
|
12
|
+
* @param format - 포맷 문자열 (기본값: 'YYYY-MM-DD HH:mm:ss')
|
|
13
|
+
*/
|
|
14
|
+
export function formatDate(date = new Date(), format = 'YYYY-MM-DD HH:mm:ss') {
|
|
15
|
+
return dayjs(date).format(format);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* 현재 날짜/시간 반환
|
|
19
|
+
* @param format - 포맷 문자열 (선택)
|
|
20
|
+
*/
|
|
21
|
+
export function now(format) {
|
|
22
|
+
const current = dayjs();
|
|
23
|
+
return format ? current.format(format) : current.toDate();
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* 상대 시간 반환 (예: "3시간 전")
|
|
27
|
+
* @param date - 기준 날짜
|
|
28
|
+
* @param locale - 로케일 (기본값: 'ko')
|
|
29
|
+
*/
|
|
30
|
+
export function fromNow(date, locale = 'ko') {
|
|
31
|
+
return dayjs(date).locale(locale).fromNow();
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* 두 날짜 사이의 차이 계산
|
|
35
|
+
* @param date1 - 첫 번째 날짜
|
|
36
|
+
* @param date2 - 두 번째 날짜
|
|
37
|
+
* @param unit - 단위 ('day', 'hour', 'minute' 등)
|
|
38
|
+
*/
|
|
39
|
+
export function diffDate(date1, date2, unit = 'day') {
|
|
40
|
+
return dayjs(date1).diff(dayjs(date2), unit);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* 날짜에 시간 더하기
|
|
44
|
+
* @param date - 기준 날짜
|
|
45
|
+
* @param value - 더할 값
|
|
46
|
+
* @param unit - 단위 ('day', 'hour', 'minute' 등)
|
|
47
|
+
*/
|
|
48
|
+
export function addDate(date, value, unit = 'day') {
|
|
49
|
+
return dayjs(date).add(value, unit).toDate();
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* 날짜에 시간 빼기
|
|
53
|
+
* @param date - 기준 날짜
|
|
54
|
+
* @param value - 뺄 값
|
|
55
|
+
* @param unit - 단위 ('day', 'hour', 'minute' 등)
|
|
56
|
+
*/
|
|
57
|
+
export function subtractDate(date, value, unit = 'day') {
|
|
58
|
+
return dayjs(date).subtract(value, unit).toDate();
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* 날짜가 특정 날짜보다 이전인지 확인
|
|
62
|
+
*/
|
|
63
|
+
export function isBefore(date1, date2) {
|
|
64
|
+
return dayjs(date1).isBefore(dayjs(date2));
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* 날짜가 특정 날짜보다 이후인지 확인
|
|
68
|
+
*/
|
|
69
|
+
export function isAfter(date1, date2) {
|
|
70
|
+
return dayjs(date1).isAfter(dayjs(date2));
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* 두 날짜가 같은지 확인
|
|
74
|
+
* @param unit - 비교 단위 (기본값: 'millisecond')
|
|
75
|
+
*/
|
|
76
|
+
export function isSame(date1, date2, unit = 'millisecond') {
|
|
77
|
+
return dayjs(date1).isSame(dayjs(date2), unit);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* 날짜가 유효한지 확인
|
|
81
|
+
*/
|
|
82
|
+
export function isValidDate(date) {
|
|
83
|
+
return dayjs(date).isValid();
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* 타임존 변환
|
|
87
|
+
* @param date - 변환할 날짜
|
|
88
|
+
* @param tz - 타임존 (예: 'Asia/Seoul')
|
|
89
|
+
*/
|
|
90
|
+
export function toTimezone(date, tz) {
|
|
91
|
+
return dayjs(date).tz(tz).toDate();
|
|
92
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../../src/date/index.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { formatDate, now, fromNow, diffDate, addDate, subtractDate, isBefore, isAfter, isSame, isValidDate, toTimezone, } from './index';
|
|
3
|
+
describe('Date Utils', () => {
|
|
4
|
+
describe('formatDate', () => {
|
|
5
|
+
it('should format date with default format', () => {
|
|
6
|
+
const date = new Date('2024-01-15 10:30:45');
|
|
7
|
+
const result = formatDate(date);
|
|
8
|
+
expect(result).toBe('2024-01-15 10:30:45');
|
|
9
|
+
});
|
|
10
|
+
it('should format date with custom format', () => {
|
|
11
|
+
const date = new Date('2024-01-15');
|
|
12
|
+
const result = formatDate(date, 'YYYY년 MM월 DD일');
|
|
13
|
+
expect(result).toBe('2024년 01월 15일');
|
|
14
|
+
});
|
|
15
|
+
it('should format string date', () => {
|
|
16
|
+
const result = formatDate('2024-01-15', 'YYYY-MM-DD');
|
|
17
|
+
expect(result).toBe('2024-01-15');
|
|
18
|
+
});
|
|
19
|
+
it('should format timestamp', () => {
|
|
20
|
+
const timestamp = new Date('2024-01-15').getTime();
|
|
21
|
+
const result = formatDate(timestamp, 'YYYY-MM-DD');
|
|
22
|
+
expect(result).toBe('2024-01-15');
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
describe('now', () => {
|
|
26
|
+
it('should return formatted current date when format is provided', () => {
|
|
27
|
+
const result = now('YYYY-MM-DD');
|
|
28
|
+
expect(result).toMatch(/^\d{4}-\d{2}-\d{2}$/);
|
|
29
|
+
});
|
|
30
|
+
it('should return Date object when no format is provided', () => {
|
|
31
|
+
const result = now();
|
|
32
|
+
expect(result).toBeInstanceOf(Date);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
describe('fromNow', () => {
|
|
36
|
+
it('should return relative time in Korean', () => {
|
|
37
|
+
const yesterday = new Date();
|
|
38
|
+
yesterday.setDate(yesterday.getDate() - 1);
|
|
39
|
+
const result = fromNow(yesterday, 'ko');
|
|
40
|
+
expect(result).toContain('전');
|
|
41
|
+
});
|
|
42
|
+
it('should return relative time in English', () => {
|
|
43
|
+
const yesterday = new Date();
|
|
44
|
+
yesterday.setDate(yesterday.getDate() - 1);
|
|
45
|
+
const result = fromNow(yesterday, 'en');
|
|
46
|
+
expect(result).toContain('ago');
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
describe('diffDate', () => {
|
|
50
|
+
it('should calculate difference in days', () => {
|
|
51
|
+
const date1 = new Date('2024-01-20');
|
|
52
|
+
const date2 = new Date('2024-01-15');
|
|
53
|
+
const result = diffDate(date1, date2, 'day');
|
|
54
|
+
expect(result).toBe(5);
|
|
55
|
+
});
|
|
56
|
+
it('should calculate difference in hours', () => {
|
|
57
|
+
const date1 = new Date('2024-01-15 15:00:00');
|
|
58
|
+
const date2 = new Date('2024-01-15 12:00:00');
|
|
59
|
+
const result = diffDate(date1, date2, 'hour');
|
|
60
|
+
expect(result).toBe(3);
|
|
61
|
+
});
|
|
62
|
+
it('should handle negative differences', () => {
|
|
63
|
+
const date1 = new Date('2024-01-15');
|
|
64
|
+
const date2 = new Date('2024-01-20');
|
|
65
|
+
const result = diffDate(date1, date2, 'day');
|
|
66
|
+
expect(result).toBe(-5);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
describe('addDate', () => {
|
|
70
|
+
it('should add days to date', () => {
|
|
71
|
+
const date = new Date('2024-01-15');
|
|
72
|
+
const result = addDate(date, 5, 'day');
|
|
73
|
+
expect(formatDate(result, 'YYYY-MM-DD')).toBe('2024-01-20');
|
|
74
|
+
});
|
|
75
|
+
it('should add hours to date', () => {
|
|
76
|
+
const date = new Date('2024-01-15 10:00:00');
|
|
77
|
+
const result = addDate(date, 3, 'hour');
|
|
78
|
+
expect(formatDate(result, 'YYYY-MM-DD HH:mm:ss')).toBe('2024-01-15 13:00:00');
|
|
79
|
+
});
|
|
80
|
+
it('should add months to date', () => {
|
|
81
|
+
const date = new Date('2024-01-15');
|
|
82
|
+
const result = addDate(date, 2, 'month');
|
|
83
|
+
expect(formatDate(result, 'YYYY-MM-DD')).toBe('2024-03-15');
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
describe('subtractDate', () => {
|
|
87
|
+
it('should subtract days from date', () => {
|
|
88
|
+
const date = new Date('2024-01-20');
|
|
89
|
+
const result = subtractDate(date, 5, 'day');
|
|
90
|
+
expect(formatDate(result, 'YYYY-MM-DD')).toBe('2024-01-15');
|
|
91
|
+
});
|
|
92
|
+
it('should subtract hours from date', () => {
|
|
93
|
+
const date = new Date('2024-01-15 13:00:00');
|
|
94
|
+
const result = subtractDate(date, 3, 'hour');
|
|
95
|
+
expect(formatDate(result, 'YYYY-MM-DD HH:mm:ss')).toBe('2024-01-15 10:00:00');
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
describe('isBefore', () => {
|
|
99
|
+
it('should return true if first date is before second', () => {
|
|
100
|
+
const date1 = new Date('2024-01-15');
|
|
101
|
+
const date2 = new Date('2024-01-20');
|
|
102
|
+
expect(isBefore(date1, date2)).toBe(true);
|
|
103
|
+
});
|
|
104
|
+
it('should return false if first date is after second', () => {
|
|
105
|
+
const date1 = new Date('2024-01-20');
|
|
106
|
+
const date2 = new Date('2024-01-15');
|
|
107
|
+
expect(isBefore(date1, date2)).toBe(false);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
describe('isAfter', () => {
|
|
111
|
+
it('should return true if first date is after second', () => {
|
|
112
|
+
const date1 = new Date('2024-01-20');
|
|
113
|
+
const date2 = new Date('2024-01-15');
|
|
114
|
+
expect(isAfter(date1, date2)).toBe(true);
|
|
115
|
+
});
|
|
116
|
+
it('should return false if first date is before second', () => {
|
|
117
|
+
const date1 = new Date('2024-01-15');
|
|
118
|
+
const date2 = new Date('2024-01-20');
|
|
119
|
+
expect(isAfter(date1, date2)).toBe(false);
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
describe('isSame', () => {
|
|
123
|
+
it('should return true for exact same dates', () => {
|
|
124
|
+
const date1 = new Date('2024-01-15 10:30:45');
|
|
125
|
+
const date2 = new Date('2024-01-15 10:30:45');
|
|
126
|
+
expect(isSame(date1, date2)).toBe(true);
|
|
127
|
+
});
|
|
128
|
+
it('should return true for same day (ignoring time)', () => {
|
|
129
|
+
const date1 = new Date('2024-01-15 10:00:00');
|
|
130
|
+
const date2 = new Date('2024-01-15 15:00:00');
|
|
131
|
+
expect(isSame(date1, date2, 'day')).toBe(true);
|
|
132
|
+
});
|
|
133
|
+
it('should return false for different days', () => {
|
|
134
|
+
const date1 = new Date('2024-01-15');
|
|
135
|
+
const date2 = new Date('2024-01-16');
|
|
136
|
+
expect(isSame(date1, date2, 'day')).toBe(false);
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
describe('isValidDate', () => {
|
|
140
|
+
it('should return true for valid dates', () => {
|
|
141
|
+
expect(isValidDate(new Date('2024-01-15'))).toBe(true);
|
|
142
|
+
expect(isValidDate('2024-01-15')).toBe(true);
|
|
143
|
+
expect(isValidDate(1705276800000)).toBe(true);
|
|
144
|
+
});
|
|
145
|
+
it('should return false for invalid dates', () => {
|
|
146
|
+
expect(isValidDate('invalid-date')).toBe(false);
|
|
147
|
+
expect(isValidDate(NaN)).toBe(false);
|
|
148
|
+
expect(isValidDate(null)).toBe(false);
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
describe('toTimezone', () => {
|
|
152
|
+
it('should convert to specific timezone', () => {
|
|
153
|
+
const date = new Date('2024-01-15T00:00:00Z');
|
|
154
|
+
const result = toTimezone(date, 'Asia/Seoul');
|
|
155
|
+
expect(result).toBeInstanceOf(Date);
|
|
156
|
+
});
|
|
157
|
+
it('should handle different timezones', () => {
|
|
158
|
+
const date = new Date('2024-01-15T12:00:00Z');
|
|
159
|
+
const nyTime = toTimezone(date, 'America/New_York');
|
|
160
|
+
const seoulTime = toTimezone(date, 'Asia/Seoul');
|
|
161
|
+
expect(nyTime).toBeInstanceOf(Date);
|
|
162
|
+
expect(seoulTime).toBeInstanceOf(Date);
|
|
163
|
+
expect(nyTime.getTime()).toBe(seoulTime.getTime());
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatter.test.d.ts","sourceRoot":"","sources":["../../../src/form/__tests__/formatter.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { formatPhoneNumber, formatBusinessNumber, formatCreditCard, extractNumbers, formatCurrency, maskResidentNumber, maskCreditCard, } from '../formatter';
|
|
3
|
+
describe('Form Formatters', () => {
|
|
4
|
+
describe('formatPhoneNumber', () => {
|
|
5
|
+
it('should format phone numbers correctly', () => {
|
|
6
|
+
expect(formatPhoneNumber('01012345678')).toBe('010-1234-5678');
|
|
7
|
+
expect(formatPhoneNumber('0212345678')).toBe('021-2345-678');
|
|
8
|
+
expect(formatPhoneNumber('010')).toBe('010');
|
|
9
|
+
expect(formatPhoneNumber('0101234')).toBe('010-1234');
|
|
10
|
+
});
|
|
11
|
+
it('should handle already formatted numbers', () => {
|
|
12
|
+
expect(formatPhoneNumber('010-1234-5678')).toBe('010-1234-5678');
|
|
13
|
+
});
|
|
14
|
+
it('should limit to 11 digits', () => {
|
|
15
|
+
expect(formatPhoneNumber('010123456789999')).toBe('010-1234-5678');
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
describe('formatBusinessNumber', () => {
|
|
19
|
+
it('should format business numbers correctly', () => {
|
|
20
|
+
expect(formatBusinessNumber('1234567890')).toBe('123-45-67890');
|
|
21
|
+
expect(formatBusinessNumber('123')).toBe('123');
|
|
22
|
+
expect(formatBusinessNumber('12345')).toBe('123-45');
|
|
23
|
+
});
|
|
24
|
+
it('should limit to 10 digits', () => {
|
|
25
|
+
expect(formatBusinessNumber('12345678901234')).toBe('123-45-67890');
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
describe('formatCreditCard', () => {
|
|
29
|
+
it('should format credit card numbers', () => {
|
|
30
|
+
expect(formatCreditCard('1234567890123456')).toBe('1234-5678-9012-3456');
|
|
31
|
+
expect(formatCreditCard('1234')).toBe('1234');
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
describe('extractNumbers', () => {
|
|
35
|
+
it('should extract only numbers', () => {
|
|
36
|
+
expect(extractNumbers('abc123def456')).toBe('123456');
|
|
37
|
+
expect(extractNumbers('010-1234-5678')).toBe('01012345678');
|
|
38
|
+
expect(extractNumbers('no numbers')).toBe('');
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
describe('formatCurrency', () => {
|
|
42
|
+
it('should format numbers with commas', () => {
|
|
43
|
+
expect(formatCurrency(1234567)).toBe('1,234,567원');
|
|
44
|
+
expect(formatCurrency(1000)).toBe('1,000원');
|
|
45
|
+
expect(formatCurrency(0)).toBe('0원');
|
|
46
|
+
});
|
|
47
|
+
it('should handle string input', () => {
|
|
48
|
+
expect(formatCurrency('1234567')).toBe('1,234,567원');
|
|
49
|
+
});
|
|
50
|
+
it('should allow custom currency', () => {
|
|
51
|
+
expect(formatCurrency(1000, '달러')).toBe('1,000달러');
|
|
52
|
+
});
|
|
53
|
+
it('should handle invalid input', () => {
|
|
54
|
+
expect(formatCurrency('invalid')).toBe('0원');
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
describe('maskResidentNumber', () => {
|
|
58
|
+
it('should mask resident registration number', () => {
|
|
59
|
+
expect(maskResidentNumber('1234561234567')).toBe('123456-*******');
|
|
60
|
+
expect(maskResidentNumber('123456-1234567')).toBe('123456-*******');
|
|
61
|
+
});
|
|
62
|
+
it('should handle partial input', () => {
|
|
63
|
+
expect(maskResidentNumber('12345')).toBe('12345');
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
describe('maskCreditCard', () => {
|
|
67
|
+
it('should mask credit card number', () => {
|
|
68
|
+
expect(maskCreditCard('1234567890123456')).toBe('1234-****-****-3456');
|
|
69
|
+
});
|
|
70
|
+
it('should handle partial input', () => {
|
|
71
|
+
expect(maskCreditCard('1234567')).toBe('1234567');
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.test.d.ts","sourceRoot":"","sources":["../../../src/form/__tests__/helpers.test.ts"],"names":[],"mappings":""}
|