@blastlabs/utils 1.22.0 → 2.1.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 +102 -8
- package/dist/components/dev/DevPanel.d.ts +16 -11
- package/dist/components/dev/DevPanel.d.ts.map +1 -1
- package/dist/components/dev/DevPanel.js +71 -77
- package/dist/components/dev/DevPanel.test.d.ts +2 -0
- package/dist/components/dev/DevPanel.test.d.ts.map +1 -0
- package/dist/components/dev/DevPanel.test.js +194 -0
- package/dist/components/dev/DevToolsProvider/DevToolsProvider.d.ts +97 -0
- package/dist/components/dev/DevToolsProvider/DevToolsProvider.d.ts.map +1 -0
- package/dist/components/dev/DevToolsProvider/DevToolsProvider.js +122 -0
- package/dist/components/dev/DevToolsProvider/DevToolsProvider.test.d.ts +2 -0
- package/dist/components/dev/DevToolsProvider/DevToolsProvider.test.d.ts.map +1 -0
- package/dist/components/dev/DevToolsProvider/DevToolsProvider.test.js +104 -0
- package/dist/components/dev/DevToolsProvider/index.d.ts +3 -0
- package/dist/components/dev/DevToolsProvider/index.d.ts.map +1 -0
- package/dist/components/dev/DevToolsProvider/index.js +1 -0
- package/dist/components/dev/FormDevTools/FormDevTools.d.ts +5 -70
- package/dist/components/dev/FormDevTools/FormDevTools.d.ts.map +1 -1
- package/dist/components/dev/FormDevTools/FormDevTools.js +163 -236
- package/dist/components/dev/FormDevTools/FormDevToolsContent.d.ts +27 -0
- package/dist/components/dev/FormDevTools/FormDevToolsContent.d.ts.map +1 -0
- package/dist/components/dev/FormDevTools/FormDevToolsContent.js +298 -0
- package/dist/components/dev/TimezoneDevTools/TimezoneDevTools.d.ts +29 -0
- package/dist/components/dev/TimezoneDevTools/TimezoneDevTools.d.ts.map +1 -0
- package/dist/components/dev/TimezoneDevTools/TimezoneDevTools.js +122 -0
- package/dist/components/dev/TimezoneDevTools/TimezoneDevToolsContent.d.ts +4 -0
- package/dist/components/dev/TimezoneDevTools/TimezoneDevToolsContent.d.ts.map +1 -0
- package/dist/components/dev/TimezoneDevTools/TimezoneDevToolsContent.js +121 -0
- package/dist/components/dev/TimezoneDevTools/index.d.ts +3 -0
- package/dist/components/dev/TimezoneDevTools/index.d.ts.map +1 -0
- package/dist/components/dev/TimezoneDevTools/index.js +1 -0
- package/dist/components/dev/TimezoneDevTools/styles.d.ts +12 -0
- package/dist/components/dev/TimezoneDevTools/styles.d.ts.map +1 -0
- package/dist/components/dev/TimezoneDevTools/styles.js +65 -0
- package/dist/components/dev/ZIndexDebugger.js +1 -1
- package/dist/components/dev/index.d.ts +4 -2
- package/dist/components/dev/index.d.ts.map +1 -1
- package/dist/components/dev/index.js +6 -1
- package/dist/date/index.d.ts +11 -0
- package/dist/date/index.d.ts.map +1 -1
- package/dist/date/index.js +43 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -74,25 +74,64 @@ function App() {
|
|
|
74
74
|
#### FormDevTools
|
|
75
75
|
|
|
76
76
|
react-hook-form의 상태를 실시간으로 시각화하는 개발용 컴포넌트입니다.
|
|
77
|
+
DevPanel과 통합하거나 별도로 사용할 수 있습니다.
|
|
77
78
|
|
|
79
|
+
**DevPanel과 함께 사용 (권장):**
|
|
78
80
|
```tsx
|
|
81
|
+
import { DevToolsProvider, DevPanel, useRegisterForm } from '@blastlabs/utils/components/dev';
|
|
79
82
|
import { useForm } from 'react-hook-form';
|
|
83
|
+
|
|
84
|
+
// Layout.tsx - Provider로 감싸기
|
|
85
|
+
function Layout() {
|
|
86
|
+
return (
|
|
87
|
+
<DevToolsProvider>
|
|
88
|
+
<YourApp />
|
|
89
|
+
</DevToolsProvider>
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// 페이지에서 form 등록
|
|
94
|
+
function MyFormPage() {
|
|
95
|
+
const form = useForm({
|
|
96
|
+
defaultValues: { username: '', email: '' }
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// form을 DevPanel에 등록
|
|
100
|
+
useRegisterForm(form);
|
|
101
|
+
|
|
102
|
+
return (
|
|
103
|
+
<form>
|
|
104
|
+
<input {...form.register('username')} />
|
|
105
|
+
<input {...form.register('email')} />
|
|
106
|
+
<button>Submit</button>
|
|
107
|
+
</form>
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// App.tsx - DevPanel 렌더링
|
|
112
|
+
function App() {
|
|
113
|
+
return (
|
|
114
|
+
<div>
|
|
115
|
+
{import.meta.env.DEV && <DevPanel />}
|
|
116
|
+
</div>
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
**별도 사용:**
|
|
122
|
+
```tsx
|
|
80
123
|
import { FormDevTools } from '@blastlabs/utils/components/dev';
|
|
81
124
|
|
|
82
125
|
function MyForm() {
|
|
83
126
|
const form = useForm({
|
|
84
|
-
defaultValues: {
|
|
85
|
-
username: '',
|
|
86
|
-
email: '',
|
|
87
|
-
age: 0,
|
|
88
|
-
}
|
|
127
|
+
defaultValues: { username: '', email: '' }
|
|
89
128
|
});
|
|
90
129
|
|
|
91
130
|
return (
|
|
92
|
-
<form
|
|
131
|
+
<form>
|
|
93
132
|
<input {...form.register('username')} />
|
|
94
133
|
<input {...form.register('email')} />
|
|
95
|
-
<button
|
|
134
|
+
<button>Submit</button>
|
|
96
135
|
|
|
97
136
|
{import.meta.env.DEV && <FormDevTools form={form} />}
|
|
98
137
|
</form>
|
|
@@ -105,9 +144,64 @@ function MyForm() {
|
|
|
105
144
|
- 에러(errors) 상태 확인
|
|
106
145
|
- 변경된 필드(dirtyFields) 추적
|
|
107
146
|
- 터치된 필드(touchedFields) 확인
|
|
108
|
-
- Mock 데이터 생성 기능
|
|
109
147
|
- 드래그 & 리사이즈 가능한 패널
|
|
110
148
|
|
|
149
|
+
#### DevPanel
|
|
150
|
+
|
|
151
|
+
여러 개발 도구를 하나의 패널에서 통합 관리하는 컴포넌트입니다.
|
|
152
|
+
|
|
153
|
+
```tsx
|
|
154
|
+
import { DevToolsProvider, DevPanel, useRegisterForm } from '@blastlabs/utils/components/dev';
|
|
155
|
+
|
|
156
|
+
// Layout.tsx - 앱 상단에서 한 번만 감싸기
|
|
157
|
+
function Layout() {
|
|
158
|
+
return (
|
|
159
|
+
<DevToolsProvider>
|
|
160
|
+
<YourApp />
|
|
161
|
+
</DevToolsProvider>
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// 페이지에서 form 등록
|
|
166
|
+
function MyFormPage() {
|
|
167
|
+
const form = useForm({
|
|
168
|
+
defaultValues: { username: '', email: '' }
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
// Form DevTools 사용을 위해 form 등록
|
|
172
|
+
useRegisterForm(form);
|
|
173
|
+
|
|
174
|
+
return (
|
|
175
|
+
<form>
|
|
176
|
+
<input {...form.register('username')} />
|
|
177
|
+
<input {...form.register('email')} />
|
|
178
|
+
<button>Submit</button>
|
|
179
|
+
</form>
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// App.tsx - DevPanel 렌더링
|
|
184
|
+
function App() {
|
|
185
|
+
return (
|
|
186
|
+
<div>
|
|
187
|
+
{import.meta.env.DEV && <DevPanel />}
|
|
188
|
+
</div>
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
**주요 기능:**
|
|
194
|
+
- 📝 Form DevTools - react-hook-form 상태 시각화 (form 등록 필요)
|
|
195
|
+
- 🌍 Timezone DevTools - 타임존 정보 확인
|
|
196
|
+
- 📐 Window Size - 윈도우 크기 표시 (토글 가능)
|
|
197
|
+
- 🔍 Z-Index Debugger - z-index 값 시각화 (토글 가능)
|
|
198
|
+
- 각 도구 독립적 토글
|
|
199
|
+
- 드래그 & 리사이즈 가능한 패널
|
|
200
|
+
|
|
201
|
+
**주의사항:**
|
|
202
|
+
- DevPanel을 사용하려면 앱 상단에서 DevToolsProvider로 감싸야 합니다
|
|
203
|
+
- Form DevTools를 사용하려면 페이지에서 useRegisterForm로 form을 등록해야 합니다
|
|
204
|
+
|
|
111
205
|
#### ApiLogger
|
|
112
206
|
|
|
113
207
|
API 요청/응답을 로깅하고 모니터링하는 컴포넌트입니다.
|
|
@@ -5,26 +5,31 @@ type Props = {
|
|
|
5
5
|
};
|
|
6
6
|
/**
|
|
7
7
|
* 개발자 도구 패널
|
|
8
|
-
*
|
|
8
|
+
* Layout에 한 번만 배치하고, 페이지에서 hook으로 form을 주입받습니다.
|
|
9
9
|
*
|
|
10
10
|
* @example
|
|
11
11
|
* ```tsx
|
|
12
|
-
* //
|
|
12
|
+
* // Layout.tsx (한 번만)
|
|
13
13
|
* import { DevPanel } from '@blastlabs/utils/components/dev';
|
|
14
14
|
*
|
|
15
|
-
* function
|
|
15
|
+
* function Layout() {
|
|
16
16
|
* return (
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
17
|
+
* <>
|
|
18
|
+
* <Outlet />
|
|
19
|
+
* <DevPanel />
|
|
20
|
+
* </>
|
|
20
21
|
* );
|
|
21
22
|
* }
|
|
22
|
-
* ```
|
|
23
23
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
24
|
+
* // 페이지에서 form 주입
|
|
25
|
+
* import { useRegisterForm } from '@blastlabs/utils/components/dev';
|
|
26
|
+
*
|
|
27
|
+
* function MyPage() {
|
|
28
|
+
* const form = useForm();
|
|
29
|
+
* useRegisterForm(form);
|
|
30
|
+
*
|
|
31
|
+
* return <form>...</form>;
|
|
32
|
+
* }
|
|
28
33
|
* ```
|
|
29
34
|
*/
|
|
30
35
|
export default function DevPanel({ position }: Props): React.JSX.Element;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DevPanel.d.ts","sourceRoot":"","sources":["../../../src/components/dev/DevPanel.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"DevPanel.d.ts","sourceRoot":"","sources":["../../../src/components/dev/DevPanel.tsx"],"names":[],"mappings":"AACA,OAAO,KAA6C,MAAM,OAAO,CAAC;AAOlE,KAAK,KAAK,GAAG;IACX,qCAAqC;IACrC,QAAQ,CAAC,EAAE,UAAU,GAAG,WAAW,GAAG,aAAa,GAAG,cAAc,CAAC;CACtE,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,EAAE,QAAyB,EAAE,EAAE,KAAK,qBAkPpE"}
|
|
@@ -1,37 +1,47 @@
|
|
|
1
|
-
|
|
1
|
+
'use client';
|
|
2
|
+
import React, { useState, useEffect } from 'react';
|
|
2
3
|
import { useWindowSize } from '../../hooks';
|
|
4
|
+
import { useDevTools } from './DevToolsProvider';
|
|
5
|
+
import FormDevToolsContent from './FormDevTools/FormDevToolsContent';
|
|
6
|
+
import TimezoneDevToolsContent from './TimezoneDevTools/TimezoneDevToolsContent';
|
|
7
|
+
import ZIndexDebugger from './ZIndexDebugger';
|
|
3
8
|
/**
|
|
4
9
|
* 개발자 도구 패널
|
|
5
|
-
*
|
|
10
|
+
* Layout에 한 번만 배치하고, 페이지에서 hook으로 form을 주입받습니다.
|
|
6
11
|
*
|
|
7
12
|
* @example
|
|
8
13
|
* ```tsx
|
|
9
|
-
* //
|
|
14
|
+
* // Layout.tsx (한 번만)
|
|
10
15
|
* import { DevPanel } from '@blastlabs/utils/components/dev';
|
|
11
16
|
*
|
|
12
|
-
* function
|
|
17
|
+
* function Layout() {
|
|
13
18
|
* return (
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
19
|
+
* <>
|
|
20
|
+
* <Outlet />
|
|
21
|
+
* <DevPanel />
|
|
22
|
+
* </>
|
|
17
23
|
* );
|
|
18
24
|
* }
|
|
19
|
-
* ```
|
|
20
25
|
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
26
|
+
* // 페이지에서 form 주입
|
|
27
|
+
* import { useRegisterForm } from '@blastlabs/utils/components/dev';
|
|
28
|
+
*
|
|
29
|
+
* function MyPage() {
|
|
30
|
+
* const form = useForm();
|
|
31
|
+
* useRegisterForm(form);
|
|
32
|
+
*
|
|
33
|
+
* return <form>...</form>;
|
|
34
|
+
* }
|
|
25
35
|
* ```
|
|
26
36
|
*/
|
|
27
37
|
export default function DevPanel({ position = 'bottom-right' }) {
|
|
28
|
-
const
|
|
29
|
-
const [showWindowSize, setShowWindowSize] = useState(false);
|
|
30
|
-
const [showRenderCount, setShowRenderCount] = useState(false);
|
|
31
|
-
const renderCount = useRef(0);
|
|
38
|
+
const { tools, toggleTool, getForm, isMenuOpen, toggleMenu, showWindowOverlay, toggleWindowOverlay, showZIndexDebugger, toggleZIndexDebugger, } = useDevTools();
|
|
32
39
|
const { width, height } = useWindowSize();
|
|
33
|
-
|
|
34
|
-
|
|
40
|
+
const [mounted, setMounted] = useState(false);
|
|
41
|
+
useEffect(() => {
|
|
42
|
+
setMounted(true);
|
|
43
|
+
}, []);
|
|
44
|
+
const form = getForm();
|
|
35
45
|
const positionStyles = {
|
|
36
46
|
'top-left': { top: 16, left: 16 },
|
|
37
47
|
'top-right': { top: 16, right: 16 },
|
|
@@ -118,79 +128,63 @@ export default function DevPanel({ position = 'bottom-right' }) {
|
|
|
118
128
|
left: isOn ? '18px' : '2px',
|
|
119
129
|
transition: 'left 0.2s',
|
|
120
130
|
});
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
color: 'white',
|
|
126
|
-
fontSize: '14px',
|
|
127
|
-
fontFamily: 'monospace',
|
|
128
|
-
borderRadius: '8px',
|
|
129
|
-
zIndex: 99998,
|
|
130
|
-
};
|
|
131
|
-
const handleClearLocalStorage = () => {
|
|
132
|
-
if (confirm('LocalStorage를 모두 삭제하시겠습니까?')) {
|
|
133
|
-
localStorage.clear();
|
|
134
|
-
alert('LocalStorage가 삭제되었습니다.');
|
|
135
|
-
}
|
|
136
|
-
};
|
|
137
|
-
const handleClearSessionStorage = () => {
|
|
138
|
-
if (confirm('SessionStorage를 모두 삭제하시겠습니까?')) {
|
|
139
|
-
sessionStorage.clear();
|
|
140
|
-
alert('SessionStorage가 삭제되었습니다.');
|
|
141
|
-
}
|
|
131
|
+
const disabledItemStyle = {
|
|
132
|
+
...toggleItemStyle,
|
|
133
|
+
opacity: 0.5,
|
|
134
|
+
cursor: 'not-allowed',
|
|
142
135
|
};
|
|
143
136
|
return (React.createElement(React.Fragment, null,
|
|
144
137
|
React.createElement("div", { style: containerStyle },
|
|
145
|
-
React.createElement("button", { onClick: () =>
|
|
146
|
-
|
|
138
|
+
React.createElement("button", { onClick: () => toggleMenu(), style: toggleButtonStyle, onMouseEnter: e => (e.currentTarget.style.backgroundColor = '#2563eb'), onMouseLeave: e => (e.currentTarget.style.backgroundColor = '#3b82f6') }, isMenuOpen ? '✕' : '🛠'),
|
|
139
|
+
isMenuOpen && (React.createElement("div", { style: panelStyle },
|
|
147
140
|
React.createElement("div", { style: headerStyle }, "\u2699\uFE0F \uAC1C\uBC1C\uC790 \uB3C4\uAD6C"),
|
|
148
141
|
React.createElement("div", { style: contentStyle },
|
|
149
|
-
React.createElement("div", { style: toggleItemStyle, onMouseEnter:
|
|
150
|
-
React.createElement("span", null, "\
|
|
151
|
-
React.createElement("div", { style: getSwitchStyle(
|
|
152
|
-
React.createElement("div", { style: getSwitchKnobStyle(
|
|
153
|
-
|
|
154
|
-
React.createElement("
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
142
|
+
form ? (React.createElement("div", { style: toggleItemStyle, onMouseEnter: e => (e.currentTarget.style.backgroundColor = '#f3f4f6'), onMouseLeave: e => (e.currentTarget.style.backgroundColor = 'transparent'), onClick: () => toggleTool('formDevTools') },
|
|
143
|
+
React.createElement("span", null, "\uD83D\uDCDD Form DevTools"),
|
|
144
|
+
React.createElement("div", { style: getSwitchStyle(tools.formDevTools) },
|
|
145
|
+
React.createElement("div", { style: getSwitchKnobStyle(tools.formDevTools) })))) : (React.createElement("div", { style: disabledItemStyle },
|
|
146
|
+
React.createElement("span", null, "\uD83D\uDCDD Form DevTools"),
|
|
147
|
+
React.createElement("div", { style: getSwitchStyle(false) },
|
|
148
|
+
React.createElement("div", { style: getSwitchKnobStyle(false) })))),
|
|
149
|
+
React.createElement("div", { style: toggleItemStyle, onMouseEnter: e => (e.currentTarget.style.backgroundColor = '#f3f4f6'), onMouseLeave: e => (e.currentTarget.style.backgroundColor = 'transparent'), onClick: () => toggleTool('timezoneDevTools') },
|
|
150
|
+
React.createElement("span", null, "\uD83C\uDF0D Timezone DevTools"),
|
|
151
|
+
React.createElement("div", { style: getSwitchStyle(tools.timezoneDevTools) },
|
|
152
|
+
React.createElement("div", { style: getSwitchKnobStyle(tools.timezoneDevTools) }))),
|
|
153
|
+
React.createElement("div", { style: toggleItemStyle, onMouseEnter: e => (e.currentTarget.style.backgroundColor = '#f3f4f6'), onMouseLeave: e => (e.currentTarget.style.backgroundColor = 'transparent'), onClick: () => toggleWindowOverlay() },
|
|
154
|
+
React.createElement("span", null, "\uD83D\uDCD0 Window Size"),
|
|
155
|
+
React.createElement("div", { style: getSwitchStyle(showWindowOverlay) },
|
|
156
|
+
React.createElement("div", { style: getSwitchKnobStyle(showWindowOverlay) }))),
|
|
157
|
+
React.createElement("div", { style: toggleItemStyle, onMouseEnter: e => (e.currentTarget.style.backgroundColor = '#f3f4f6'), onMouseLeave: e => (e.currentTarget.style.backgroundColor = 'transparent'), onClick: () => toggleZIndexDebugger() },
|
|
158
|
+
React.createElement("span", null, "\uD83D\uDD0D Z-Index Debugger"),
|
|
159
|
+
React.createElement("div", { style: getSwitchStyle(showZIndexDebugger) },
|
|
160
|
+
React.createElement("div", { style: getSwitchKnobStyle(showZIndexDebugger) }))))))),
|
|
161
|
+
tools.formDevTools && form && (React.createElement("div", { style: { position: 'fixed', top: 80, right: 16, zIndex: 99998 } },
|
|
162
|
+
React.createElement(FormDevToolsContent, { form: form }))),
|
|
163
|
+
tools.timezoneDevTools && (React.createElement("div", { style: { position: 'fixed', top: 80, left: 16, zIndex: 99998 } },
|
|
164
|
+
React.createElement(TimezoneDevToolsContent, null))),
|
|
165
|
+
showZIndexDebugger && (React.createElement("div", { style: { position: 'fixed', top: 80, right: 16, zIndex: 99997 } },
|
|
166
|
+
React.createElement(ZIndexDebugger, { position: "top-right" }))),
|
|
167
|
+
mounted && showWindowOverlay && (React.createElement("div", { "data-testid": "window-overlay", style: {
|
|
168
|
+
position: 'fixed',
|
|
169
|
+
padding: '8px 12px',
|
|
170
|
+
backgroundColor: 'rgba(0, 0, 0, 0.8)',
|
|
171
|
+
color: 'white',
|
|
172
|
+
fontSize: '14px',
|
|
173
|
+
fontFamily: 'monospace',
|
|
174
|
+
borderRadius: '8px',
|
|
175
|
+
zIndex: 99997,
|
|
174
176
|
top: 16,
|
|
175
177
|
left: 16,
|
|
176
178
|
} },
|
|
177
179
|
React.createElement("span", { style: { color: '#60a5fa' } }, "W:"),
|
|
178
|
-
|
|
180
|
+
" ",
|
|
179
181
|
React.createElement("span", { style: { fontWeight: 'bold' } },
|
|
180
182
|
width,
|
|
181
183
|
"px"),
|
|
182
184
|
React.createElement("span", { style: { color: '#9ca3af', margin: '0 4px' } }, "\u00D7"),
|
|
183
185
|
React.createElement("span", { style: { color: '#4ade80' } }, "H:"),
|
|
184
|
-
|
|
186
|
+
" ",
|
|
185
187
|
React.createElement("span", { style: { fontWeight: 'bold' } },
|
|
186
188
|
height,
|
|
187
|
-
"px")))
|
|
188
|
-
showRenderCount && (React.createElement("div", { style: {
|
|
189
|
-
...overlayStyle,
|
|
190
|
-
top: 16,
|
|
191
|
-
right: 16,
|
|
192
|
-
} },
|
|
193
|
-
React.createElement("span", { style: { color: '#fbbf24' } }, "Renders:"),
|
|
194
|
-
' ',
|
|
195
|
-
React.createElement("span", { style: { fontWeight: 'bold' } }, renderCount.current)))));
|
|
189
|
+
"px")))));
|
|
196
190
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DevPanel.test.d.ts","sourceRoot":"","sources":["../../../src/components/dev/DevPanel.test.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
3
|
+
import { render, screen } from '@testing-library/react';
|
|
4
|
+
import userEvent from '@testing-library/user-event';
|
|
5
|
+
import DevPanel from './DevPanel';
|
|
6
|
+
import { DevToolsProvider, useRegisterForm } from './DevToolsProvider';
|
|
7
|
+
// Mock useWindowSize
|
|
8
|
+
vi.mock('../../hooks', () => ({
|
|
9
|
+
useWindowSize: () => ({ width: 1920, height: 1080 }),
|
|
10
|
+
}));
|
|
11
|
+
// Mock FormDevToolsContent and TimezoneDevToolsContent
|
|
12
|
+
vi.mock('./FormDevTools/FormDevToolsContent', () => ({
|
|
13
|
+
default: () => React.createElement("div", { "data-testid": "form-devtools-panel" }, "Form DevTools Panel"),
|
|
14
|
+
}));
|
|
15
|
+
vi.mock('./TimezoneDevTools/TimezoneDevToolsContent', () => ({
|
|
16
|
+
default: () => React.createElement("div", { "data-testid": "timezone-devtools-panel" }, "Timezone DevTools Panel"),
|
|
17
|
+
}));
|
|
18
|
+
// Note: ZIndexDebugger is not mocked to test actual toggle behavior
|
|
19
|
+
// Mock form
|
|
20
|
+
const createMockForm = () => ({
|
|
21
|
+
formState: {
|
|
22
|
+
errors: {},
|
|
23
|
+
dirtyFields: {},
|
|
24
|
+
touchedFields: {},
|
|
25
|
+
isValid: true,
|
|
26
|
+
isSubmitting: false,
|
|
27
|
+
submitCount: 0,
|
|
28
|
+
defaultValues: { username: '', email: '' },
|
|
29
|
+
},
|
|
30
|
+
watch: vi.fn(() => ({ username: '', email: '' })),
|
|
31
|
+
setValue: vi.fn(),
|
|
32
|
+
trigger: vi.fn(),
|
|
33
|
+
});
|
|
34
|
+
function TestPage({ hasForm = true }) {
|
|
35
|
+
const form = createMockForm();
|
|
36
|
+
if (hasForm) {
|
|
37
|
+
useRegisterForm(form);
|
|
38
|
+
}
|
|
39
|
+
return React.createElement("div", null, "Test Page");
|
|
40
|
+
}
|
|
41
|
+
describe('DevPanel', () => {
|
|
42
|
+
beforeEach(() => {
|
|
43
|
+
vi.clearAllMocks();
|
|
44
|
+
});
|
|
45
|
+
describe('기본 동작', () => {
|
|
46
|
+
it('메인 토글 버튼이 렌더링된다', () => {
|
|
47
|
+
render(React.createElement(DevToolsProvider, null,
|
|
48
|
+
React.createElement(DevPanel, null)));
|
|
49
|
+
const toggleButton = screen.getByRole('button');
|
|
50
|
+
expect(toggleButton).toBeTruthy();
|
|
51
|
+
expect(toggleButton.textContent).toBe('🛠');
|
|
52
|
+
});
|
|
53
|
+
it('메뉴가 닫혀있을 때는 메뉴 패널이 보이지 않는다', () => {
|
|
54
|
+
render(React.createElement(DevToolsProvider, null,
|
|
55
|
+
React.createElement(DevPanel, null)));
|
|
56
|
+
expect(screen.queryByText('⚙️ 개발자 도구')).toBeNull();
|
|
57
|
+
});
|
|
58
|
+
it('윈도우 사이즈가 항상 표시된다', () => {
|
|
59
|
+
render(React.createElement(DevToolsProvider, null,
|
|
60
|
+
React.createElement(DevPanel, null)));
|
|
61
|
+
expect(screen.getByText(/W:/)).toBeTruthy();
|
|
62
|
+
expect(screen.getByText(/H:/)).toBeTruthy();
|
|
63
|
+
expect(screen.getByText('1920px')).toBeTruthy();
|
|
64
|
+
expect(screen.getByText('1080px')).toBeTruthy();
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
describe('메뉴 토글', () => {
|
|
68
|
+
it('메인 버튼 클릭 시 메뉴가 열린다', async () => {
|
|
69
|
+
const user = userEvent.setup();
|
|
70
|
+
render(React.createElement(DevToolsProvider, null,
|
|
71
|
+
React.createElement(DevPanel, null)));
|
|
72
|
+
const toggleButton = screen.getByRole('button');
|
|
73
|
+
expect(toggleButton.textContent).toBe('🛠');
|
|
74
|
+
await user.click(toggleButton);
|
|
75
|
+
expect(screen.getByText('⚙️ 개발자 도구')).toBeTruthy();
|
|
76
|
+
expect(toggleButton.textContent).toBe('✕');
|
|
77
|
+
});
|
|
78
|
+
it('메인 버튼 다시 클릭 시 메뉴가 닫힌다', async () => {
|
|
79
|
+
const user = userEvent.setup();
|
|
80
|
+
render(React.createElement(DevToolsProvider, null,
|
|
81
|
+
React.createElement(DevPanel, null)));
|
|
82
|
+
const toggleButton = screen.getByRole('button');
|
|
83
|
+
// 메뉴 열기
|
|
84
|
+
await user.click(toggleButton);
|
|
85
|
+
expect(screen.getByText('⚙️ 개발자 도구')).toBeTruthy();
|
|
86
|
+
// 메뉴 닫기
|
|
87
|
+
await user.click(toggleButton);
|
|
88
|
+
expect(screen.queryByText('⚙️ 개발자 도구')).toBeNull();
|
|
89
|
+
expect(toggleButton.textContent).toBe('🛠');
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
describe('툴 토글', () => {
|
|
93
|
+
it('메뉴에서 Form DevTools 토글 클릭 시 패널이 표시된다', async () => {
|
|
94
|
+
const user = userEvent.setup();
|
|
95
|
+
render(React.createElement(DevToolsProvider, null,
|
|
96
|
+
React.createElement(TestPage, { hasForm: true }),
|
|
97
|
+
React.createElement(DevPanel, null)));
|
|
98
|
+
const toggleButton = screen.getByRole('button');
|
|
99
|
+
await user.click(toggleButton);
|
|
100
|
+
const formDevToolsToggle = screen.getByText('📝 Form DevTools');
|
|
101
|
+
await user.click(formDevToolsToggle);
|
|
102
|
+
expect(screen.getByTestId('form-devtools-panel')).toBeTruthy();
|
|
103
|
+
});
|
|
104
|
+
it('메뉴에서 Timezone DevTools 토글 클릭 시 패널이 표시된다', async () => {
|
|
105
|
+
const user = userEvent.setup();
|
|
106
|
+
render(React.createElement(DevToolsProvider, null,
|
|
107
|
+
React.createElement(DevPanel, null)));
|
|
108
|
+
const toggleButton = screen.getByRole('button');
|
|
109
|
+
await user.click(toggleButton);
|
|
110
|
+
const timezoneDevToolsToggle = screen.getByText('🌍 Timezone DevTools');
|
|
111
|
+
await user.click(timezoneDevToolsToggle);
|
|
112
|
+
expect(screen.getByTestId('timezone-devtools-panel')).toBeTruthy();
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
describe('독립적 토글 동작', () => {
|
|
116
|
+
it('메뉴를 닫아도 각 툴 패널은 유지된다', async () => {
|
|
117
|
+
const user = userEvent.setup();
|
|
118
|
+
render(React.createElement(DevToolsProvider, null,
|
|
119
|
+
React.createElement(TestPage, { hasForm: true }),
|
|
120
|
+
React.createElement(DevPanel, null)));
|
|
121
|
+
const toggleButton = screen.getByRole('button');
|
|
122
|
+
// 메뉴 열기
|
|
123
|
+
await user.click(toggleButton);
|
|
124
|
+
// Form DevTools 켜기
|
|
125
|
+
const formToggle = screen.getByText('📝 Form DevTools');
|
|
126
|
+
await user.click(formToggle);
|
|
127
|
+
// 메뉴 닫기
|
|
128
|
+
await user.click(toggleButton);
|
|
129
|
+
// 메뉴는 닫혀야 함
|
|
130
|
+
expect(screen.queryByText('⚙️ 개발자 도구')).toBeNull();
|
|
131
|
+
// Form DevTools 패널은 유지되어야 함
|
|
132
|
+
expect(screen.getByTestId('form-devtools-panel')).toBeTruthy();
|
|
133
|
+
});
|
|
134
|
+
it('각 툴이 독립적으로 토글된다', async () => {
|
|
135
|
+
const user = userEvent.setup();
|
|
136
|
+
render(React.createElement(DevToolsProvider, null,
|
|
137
|
+
React.createElement(TestPage, { hasForm: true }),
|
|
138
|
+
React.createElement(DevPanel, null)));
|
|
139
|
+
const toggleButton = screen.getByRole('button');
|
|
140
|
+
// 메뉴 열기
|
|
141
|
+
await user.click(toggleButton);
|
|
142
|
+
// Form DevTools만 켜기
|
|
143
|
+
const formToggle = screen.getByText('📝 Form DevTools');
|
|
144
|
+
await user.click(formToggle);
|
|
145
|
+
// 메뉴 닫기
|
|
146
|
+
await user.click(toggleButton);
|
|
147
|
+
// Form DevTools 패널만 있어야 함
|
|
148
|
+
expect(screen.getByTestId('form-devtools-panel')).toBeTruthy();
|
|
149
|
+
expect(screen.queryByTestId('timezone-devtools-panel')).toBeNull();
|
|
150
|
+
// 메뉴 다시 열기
|
|
151
|
+
await user.click(toggleButton);
|
|
152
|
+
// Timezone DevTools 켜기
|
|
153
|
+
const timezoneToggle = screen.getByText('🌍 Timezone DevTools');
|
|
154
|
+
await user.click(timezoneToggle);
|
|
155
|
+
// 메뉴 닫기
|
|
156
|
+
await user.click(toggleButton);
|
|
157
|
+
// 두 패널 모두 있어야 함
|
|
158
|
+
expect(screen.getByTestId('form-devtools-panel')).toBeTruthy();
|
|
159
|
+
expect(screen.getByTestId('timezone-devtools-panel')).toBeTruthy();
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
describe('패널 토글', () => {
|
|
163
|
+
it('Window Size Overlay 토글', async () => {
|
|
164
|
+
const user = userEvent.setup();
|
|
165
|
+
render(React.createElement(DevToolsProvider, null,
|
|
166
|
+
React.createElement(DevPanel, null)));
|
|
167
|
+
// 윈도우 사이즈가 항상 표시됨
|
|
168
|
+
expect(screen.getByText(/W:/)).toBeTruthy();
|
|
169
|
+
expect(screen.getByText(/H:/)).toBeTruthy();
|
|
170
|
+
expect(screen.getByText('1920px')).toBeTruthy();
|
|
171
|
+
expect(screen.getByText('1080px')).toBeTruthy();
|
|
172
|
+
const toggleButton = screen.getByRole('button');
|
|
173
|
+
await user.click(toggleButton);
|
|
174
|
+
const windowToggle = screen.getByText('📐 Window Size');
|
|
175
|
+
await user.click(windowToggle);
|
|
176
|
+
// 숨겨졸 때 윈도우 사이즈가 사라짐
|
|
177
|
+
expect(screen.queryByText(/W:/)).toBeNull();
|
|
178
|
+
expect(screen.queryByText(/H:/)).toBeNull();
|
|
179
|
+
});
|
|
180
|
+
it('ZIndex Debugger 토글', async () => {
|
|
181
|
+
const user = userEvent.setup();
|
|
182
|
+
render(React.createElement(DevToolsProvider, null,
|
|
183
|
+
React.createElement(DevPanel, null)));
|
|
184
|
+
// 초기 상태에서는 렌더링되지 않음
|
|
185
|
+
expect(screen.queryByTestId('zindex-debugger')).toBeNull();
|
|
186
|
+
const toggleButton = screen.getByRole('button');
|
|
187
|
+
await user.click(toggleButton);
|
|
188
|
+
const zIndexToggle = screen.getByText('🔍 Z-Index Debugger');
|
|
189
|
+
await user.click(zIndexToggle);
|
|
190
|
+
// 토글 후 ZIndexDebugger가 렌더링됨
|
|
191
|
+
expect(screen.getByTestId('zindex-debugger')).toBeTruthy();
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
});
|