@blastlabs/utils 1.11.1 → 1.12.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/dist/components/dev/ApiLogger.d.ts +1 -1
- package/dist/components/dev/ApiLogger.js +2 -2
- package/dist/components/dev/DevPanel.d.ts +1 -1
- package/dist/components/dev/DevPanel.js +2 -2
- package/dist/components/dev/FormDevTools/FormDevTools.d.ts +1 -1
- package/dist/components/dev/FormDevTools/FormDevTools.js +2 -2
- package/dist/components/dev/FormDevTools/index.d.ts +1 -1
- package/dist/components/dev/FormDevTools/index.d.ts.map +1 -1
- package/dist/components/dev/{IdSelector.d.ts → IdSelector/IdSelector.d.ts} +3 -4
- package/dist/components/dev/IdSelector/IdSelector.d.ts.map +1 -0
- package/dist/components/dev/IdSelector/IdSelector.js +60 -0
- package/dist/components/dev/IdSelector/IdSelector.test.d.ts +2 -0
- package/dist/components/dev/IdSelector/IdSelector.test.d.ts.map +1 -0
- package/dist/components/dev/IdSelector/IdSelector.test.js +203 -0
- package/dist/components/dev/IdSelector/LoginCard.d.ts +17 -0
- package/dist/components/dev/IdSelector/LoginCard.d.ts.map +1 -0
- package/dist/components/dev/IdSelector/LoginCard.js +16 -0
- package/dist/components/dev/IdSelector/index.d.ts +3 -0
- package/dist/components/dev/IdSelector/index.d.ts.map +1 -0
- package/dist/components/dev/IdSelector/index.js +1 -0
- package/dist/components/dev/IdSelector/styles.d.ts +16 -0
- package/dist/components/dev/IdSelector/styles.d.ts.map +1 -0
- package/dist/components/dev/IdSelector/styles.js +66 -0
- package/dist/components/dev/WindowSizeDisplay.d.ts +1 -1
- package/dist/components/dev/WindowSizeDisplay.js +2 -2
- package/dist/components/dev/ZIndexDebugger.d.ts +1 -1
- package/dist/components/dev/ZIndexDebugger.js +1 -1
- package/dist/components/dev/index.d.ts +2 -1
- package/dist/components/dev/index.d.ts.map +1 -1
- package/dist/hooks/event/index.d.ts +6 -0
- package/dist/hooks/event/index.d.ts.map +1 -0
- package/dist/hooks/event/index.js +5 -0
- package/dist/hooks/event/useClickOutside.d.ts.map +1 -0
- package/dist/hooks/event/useEventListener.d.ts.map +1 -0
- package/dist/hooks/form/__tests__/useCRUDForm.test.d.ts +2 -0
- package/dist/hooks/form/__tests__/useCRUDForm.test.d.ts.map +1 -0
- package/dist/hooks/form/__tests__/useCRUDForm.test.js +487 -0
- package/dist/hooks/form/index.d.ts +5 -0
- package/dist/hooks/form/index.d.ts.map +1 -0
- package/dist/hooks/form/index.js +4 -0
- package/dist/hooks/form/useCRUDForm.d.ts +232 -0
- package/dist/hooks/form/useCRUDForm.d.ts.map +1 -0
- package/dist/hooks/form/useCRUDForm.js +287 -0
- package/dist/hooks/index.d.ts +9 -14
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +16 -19
- package/dist/hooks/performance/index.d.ts +7 -0
- package/dist/hooks/performance/index.d.ts.map +1 -0
- package/dist/hooks/performance/index.js +6 -0
- package/dist/hooks/performance/useDebounce.d.ts.map +1 -0
- package/dist/hooks/performance/useIntersectionObserver.d.ts.map +1 -0
- package/dist/hooks/performance/useThrottle.d.ts.map +1 -0
- package/dist/hooks/state/index.d.ts +6 -0
- package/dist/hooks/state/index.d.ts.map +1 -0
- package/dist/hooks/state/index.js +5 -0
- package/dist/hooks/state/usePrevious.d.ts.map +1 -0
- package/dist/hooks/state/useToggle.d.ts.map +1 -0
- package/dist/hooks/storage/index.d.ts +7 -0
- package/dist/hooks/storage/index.d.ts.map +1 -0
- package/dist/hooks/storage/index.js +6 -0
- package/dist/hooks/storage/useCopyToClipboard.d.ts.map +1 -0
- package/dist/hooks/storage/useLocalStorage.d.ts.map +1 -0
- package/dist/hooks/storage/useSessionStorage.d.ts.map +1 -0
- package/dist/hooks/time/__tests__/useCountdown.test.d.ts +2 -0
- package/dist/hooks/time/__tests__/useCountdown.test.d.ts.map +1 -0
- package/dist/hooks/time/__tests__/useCountdown.test.js +150 -0
- package/dist/hooks/time/__tests__/useInterval.test.d.ts +2 -0
- package/dist/hooks/time/__tests__/useInterval.test.d.ts.map +1 -0
- package/dist/hooks/time/__tests__/useInterval.test.js +39 -0
- package/dist/hooks/time/__tests__/useStopwatch.test.d.ts +2 -0
- package/dist/hooks/time/__tests__/useStopwatch.test.d.ts.map +1 -0
- package/dist/hooks/time/__tests__/useStopwatch.test.js +149 -0
- package/dist/hooks/time/index.d.ts +7 -0
- package/dist/hooks/time/index.d.ts.map +1 -0
- package/dist/hooks/time/index.js +6 -0
- package/dist/hooks/time/useCountdown.d.ts +116 -0
- package/dist/hooks/time/useCountdown.d.ts.map +1 -0
- package/dist/hooks/time/useCountdown.js +152 -0
- package/dist/hooks/time/useInterval.d.ts +40 -0
- package/dist/hooks/time/useInterval.d.ts.map +1 -0
- package/dist/hooks/time/useInterval.js +61 -0
- package/dist/hooks/time/useStopwatch.d.ts +142 -0
- package/dist/hooks/time/useStopwatch.d.ts.map +1 -0
- package/dist/hooks/time/useStopwatch.js +179 -0
- package/dist/hooks/ui/index.d.ts +6 -0
- package/dist/hooks/ui/index.d.ts.map +1 -0
- package/dist/hooks/ui/index.js +5 -0
- package/dist/hooks/ui/useMediaQuery.d.ts.map +1 -0
- package/dist/hooks/ui/useWindowSize.d.ts.map +1 -0
- package/package.json +14 -4
- package/dist/components/dev/IdSelector.d.ts.map +0 -1
- package/dist/components/dev/IdSelector.js +0 -129
- package/dist/hooks/useClickOutside.d.ts.map +0 -1
- package/dist/hooks/useCopyToClipboard.d.ts.map +0 -1
- package/dist/hooks/useDebounce.d.ts.map +0 -1
- package/dist/hooks/useEventListener.d.ts.map +0 -1
- package/dist/hooks/useIntersectionObserver.d.ts.map +0 -1
- package/dist/hooks/useLocalStorage.d.ts.map +0 -1
- package/dist/hooks/useMediaQuery.d.ts.map +0 -1
- package/dist/hooks/usePrevious.d.ts.map +0 -1
- package/dist/hooks/useSessionStorage.d.ts.map +0 -1
- package/dist/hooks/useThrottle.d.ts.map +0 -1
- package/dist/hooks/useToggle.d.ts.map +0 -1
- package/dist/hooks/useWindowSize.d.ts.map +0 -1
- /package/dist/hooks/{useClickOutside.d.ts → event/useClickOutside.d.ts} +0 -0
- /package/dist/hooks/{useClickOutside.js → event/useClickOutside.js} +0 -0
- /package/dist/hooks/{useEventListener.d.ts → event/useEventListener.d.ts} +0 -0
- /package/dist/hooks/{useEventListener.js → event/useEventListener.js} +0 -0
- /package/dist/hooks/{useDebounce.d.ts → performance/useDebounce.d.ts} +0 -0
- /package/dist/hooks/{useDebounce.js → performance/useDebounce.js} +0 -0
- /package/dist/hooks/{useIntersectionObserver.d.ts → performance/useIntersectionObserver.d.ts} +0 -0
- /package/dist/hooks/{useIntersectionObserver.js → performance/useIntersectionObserver.js} +0 -0
- /package/dist/hooks/{useThrottle.d.ts → performance/useThrottle.d.ts} +0 -0
- /package/dist/hooks/{useThrottle.js → performance/useThrottle.js} +0 -0
- /package/dist/hooks/{usePrevious.d.ts → state/usePrevious.d.ts} +0 -0
- /package/dist/hooks/{usePrevious.js → state/usePrevious.js} +0 -0
- /package/dist/hooks/{useToggle.d.ts → state/useToggle.d.ts} +0 -0
- /package/dist/hooks/{useToggle.js → state/useToggle.js} +0 -0
- /package/dist/hooks/{useCopyToClipboard.d.ts → storage/useCopyToClipboard.d.ts} +0 -0
- /package/dist/hooks/{useCopyToClipboard.js → storage/useCopyToClipboard.js} +0 -0
- /package/dist/hooks/{useLocalStorage.d.ts → storage/useLocalStorage.d.ts} +0 -0
- /package/dist/hooks/{useLocalStorage.js → storage/useLocalStorage.js} +0 -0
- /package/dist/hooks/{useSessionStorage.d.ts → storage/useSessionStorage.d.ts} +0 -0
- /package/dist/hooks/{useSessionStorage.js → storage/useSessionStorage.js} +0 -0
- /package/dist/hooks/{useMediaQuery.d.ts → ui/useMediaQuery.d.ts} +0 -0
- /package/dist/hooks/{useMediaQuery.js → ui/useMediaQuery.js} +0 -0
- /package/dist/hooks/{useWindowSize.d.ts → ui/useWindowSize.d.ts} +0 -0
- /package/dist/hooks/{useWindowSize.js → ui/useWindowSize.js} +0 -0
|
@@ -34,7 +34,7 @@ export declare function clearApiLogs(): void;
|
|
|
34
34
|
* ```tsx
|
|
35
35
|
* // Axios interceptor 사용 (가장 일반적)
|
|
36
36
|
* import axios from 'axios';
|
|
37
|
-
* import { ApiLogger, addApiLog } from '
|
|
37
|
+
* import { ApiLogger, addApiLog } from '@blastlabs/utils/components/dev';
|
|
38
38
|
*
|
|
39
39
|
* // Request interceptor
|
|
40
40
|
* axios.interceptors.request.use(
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useState, useEffect } from 'react';
|
|
2
|
-
import { useCopyToClipboard } from '../../hooks
|
|
2
|
+
import { useCopyToClipboard } from '../../hooks';
|
|
3
3
|
// 전역 로그 저장소
|
|
4
4
|
let globalLogs = [];
|
|
5
5
|
let logListeners = [];
|
|
@@ -31,7 +31,7 @@ export function clearApiLogs() {
|
|
|
31
31
|
* ```tsx
|
|
32
32
|
* // Axios interceptor 사용 (가장 일반적)
|
|
33
33
|
* import axios from 'axios';
|
|
34
|
-
* import { ApiLogger, addApiLog } from '
|
|
34
|
+
* import { ApiLogger, addApiLog } from '@blastlabs/utils/components/dev';
|
|
35
35
|
*
|
|
36
36
|
* // Request interceptor
|
|
37
37
|
* axios.interceptors.request.use(
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useState, useRef } from 'react';
|
|
2
|
-
import { useWindowSize } from '../../hooks
|
|
2
|
+
import { useWindowSize } from '../../hooks';
|
|
3
3
|
/**
|
|
4
4
|
* 개발자 도구 패널
|
|
5
5
|
* 여러 개발용 도구를 하나의 패널에서 관리할 수 있습니다.
|
|
@@ -7,7 +7,7 @@ import { useWindowSize } from '../../hooks/useWindowSize';
|
|
|
7
7
|
* @example
|
|
8
8
|
* ```tsx
|
|
9
9
|
* // Vite 프로젝트
|
|
10
|
-
* import { DevPanel } from '
|
|
10
|
+
* import { DevPanel } from '@blastlabs/utils/components/dev';
|
|
11
11
|
*
|
|
12
12
|
* function App() {
|
|
13
13
|
* return (
|
|
@@ -45,7 +45,7 @@ export type Props = {
|
|
|
45
45
|
* ```tsx
|
|
46
46
|
* // Vite 프로젝트 - 간단한 사용법
|
|
47
47
|
* import { useForm } from 'react-hook-form';
|
|
48
|
-
* import { FormDevTools } from '
|
|
48
|
+
* import { FormDevTools } from '@blastlabs/utils/components/dev';
|
|
49
49
|
*
|
|
50
50
|
* function MyForm() {
|
|
51
51
|
* const form = useForm({
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useState, useRef, useEffect } from 'react';
|
|
2
|
-
import { useCopyToClipboard } from '../../../hooks
|
|
2
|
+
import { useCopyToClipboard } from '../../../hooks';
|
|
3
3
|
import { getContainerStyle, getToggleButtonStyle, getPanelStyle, headerStyle, headerTitleStyle, getStatusBadgeStyle, getCopyButtonStyle, tabContainerStyle, getTabStyle, contentStyle, sectionTitleStyle, codeBlockStyle, errorItemStyle, errorLabelStyle, errorMessageStyle, statsContainerStyle, statCardStyle, statLabelStyle, statValueStyle, resizeHandleStyle, resizeHandleIndicatorStyle, } from './styles';
|
|
4
4
|
/**
|
|
5
5
|
* react-hook-form의 상태를 실시간으로 시각화하는 개발용 컴포넌트
|
|
@@ -9,7 +9,7 @@ import { getContainerStyle, getToggleButtonStyle, getPanelStyle, headerStyle, he
|
|
|
9
9
|
* ```tsx
|
|
10
10
|
* // Vite 프로젝트 - 간단한 사용법
|
|
11
11
|
* import { useForm } from 'react-hook-form';
|
|
12
|
-
* import { FormDevTools } from '
|
|
12
|
+
* import { FormDevTools } from '@blastlabs/utils/components/dev';
|
|
13
13
|
*
|
|
14
14
|
* function MyForm() {
|
|
15
15
|
* const form = useForm({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/dev/FormDevTools/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACzC,YAAY,EAAE,KAAK,IAAI,iBAAiB,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/dev/FormDevTools/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACzC,YAAY,EAAE,KAAK,IAAI,iBAAiB,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
type LoginInfo = {
|
|
2
|
+
export type LoginInfo = {
|
|
3
3
|
id: string;
|
|
4
4
|
pw: string;
|
|
5
5
|
memo: string;
|
|
6
6
|
};
|
|
7
|
-
type Props = {
|
|
7
|
+
export type Props = {
|
|
8
8
|
onLogin: (email: string, password: string) => Promise<void>;
|
|
9
9
|
infos: LoginInfo[];
|
|
10
10
|
};
|
|
@@ -14,7 +14,7 @@ type Props = {
|
|
|
14
14
|
* @example
|
|
15
15
|
* ```tsx
|
|
16
16
|
* // Vite 프로젝트
|
|
17
|
-
* import { IdSelector } from '
|
|
17
|
+
* import { IdSelector } from '@blastlabs/utils/components/dev';
|
|
18
18
|
*
|
|
19
19
|
* function LoginPage() {
|
|
20
20
|
* const handleLogin = async (email: string, password: string) => {
|
|
@@ -46,5 +46,4 @@ type Props = {
|
|
|
46
46
|
* ```
|
|
47
47
|
*/
|
|
48
48
|
export default function IdSelector({ onLogin, infos }: Props): React.JSX.Element;
|
|
49
|
-
export {};
|
|
50
49
|
//# sourceMappingURL=IdSelector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IdSelector.d.ts","sourceRoot":"","sources":["../../../../src/components/dev/IdSelector/IdSelector.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAIxC,MAAM,MAAM,SAAS,GAAG;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,KAAK,GAAG;IAClB,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5D,KAAK,EAAE,SAAS,EAAE,CAAC;CACpB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,MAAM,CAAC,OAAO,UAAU,UAAU,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,KAAK,qBAoC3D"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { LoginCard } from './LoginCard';
|
|
3
|
+
import { getContainerStyle, getHeaderStyle } from './styles';
|
|
4
|
+
/**
|
|
5
|
+
* 개발용 로그인 shortcut 컴포넌트
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```tsx
|
|
9
|
+
* // Vite 프로젝트
|
|
10
|
+
* import { IdSelector } from '@blastlabs/utils/components/dev';
|
|
11
|
+
*
|
|
12
|
+
* function LoginPage() {
|
|
13
|
+
* const handleLogin = async (email: string, password: string) => {
|
|
14
|
+
* await loginAPI(email, password);
|
|
15
|
+
* };
|
|
16
|
+
*
|
|
17
|
+
* const devAccounts = [
|
|
18
|
+
* { id: 'admin@test.com', pw: 'admin123', memo: '관리자' },
|
|
19
|
+
* { id: 'user@test.com', pw: 'user123', memo: '일반 사용자' },
|
|
20
|
+
* ];
|
|
21
|
+
*
|
|
22
|
+
* return (
|
|
23
|
+
* <div>
|
|
24
|
+
* <LoginForm />
|
|
25
|
+
* {import.meta.env.DEV && (
|
|
26
|
+
* <IdSelector onLogin={handleLogin} infos={devAccounts} />
|
|
27
|
+
* )}
|
|
28
|
+
* </div>
|
|
29
|
+
* );
|
|
30
|
+
* }
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```tsx
|
|
35
|
+
* // Create React App 프로젝트
|
|
36
|
+
* {process.env.NODE_ENV === 'development' && (
|
|
37
|
+
* <IdSelector onLogin={handleLogin} infos={devAccounts} />
|
|
38
|
+
* )}
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export default function IdSelector({ onLogin, infos }) {
|
|
42
|
+
const [loading, setLoading] = useState(null);
|
|
43
|
+
const [hoveredIndex, setHoveredIndex] = useState(null);
|
|
44
|
+
const [hoveredButton, setHoveredButton] = useState(null);
|
|
45
|
+
const handleQuickLogin = async (info, index) => {
|
|
46
|
+
setLoading(index);
|
|
47
|
+
try {
|
|
48
|
+
await onLogin(info.id, info.pw);
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
// 에러는 무시하고 상태만 해제 (에러 처리는 onLogin 호출자가 담당)
|
|
52
|
+
}
|
|
53
|
+
finally {
|
|
54
|
+
setLoading(null);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
return (React.createElement("div", { style: getContainerStyle() },
|
|
58
|
+
React.createElement("div", { style: getHeaderStyle() }, "\uD83D\uDE80 \uAC1C\uBC1C\uC6A9 \uBE60\uB978 \uB85C\uADF8\uC778"),
|
|
59
|
+
infos.map((info, index) => (React.createElement(LoginCard, { key: index, info: info, index: index, loading: loading, hoveredIndex: hoveredIndex, hoveredButton: hoveredButton, onMouseEnter: () => setHoveredIndex(index), onMouseLeave: () => setHoveredIndex(null), onButtonMouseEnter: () => setHoveredButton(index), onButtonMouseLeave: () => setHoveredButton(null), onLogin: handleQuickLogin })))));
|
|
60
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IdSelector.test.d.ts","sourceRoot":"","sources":["../../../../src/components/dev/IdSelector/IdSelector.test.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
3
|
+
import { render, screen, waitFor } from '@testing-library/react';
|
|
4
|
+
import userEvent from '@testing-library/user-event';
|
|
5
|
+
import IdSelector from './IdSelector';
|
|
6
|
+
describe('IdSelector', () => {
|
|
7
|
+
const mockOnLogin = vi.fn();
|
|
8
|
+
const defaultInfos = [
|
|
9
|
+
{ id: 'admin@test.com', pw: 'admin123', memo: '관리자' },
|
|
10
|
+
{ id: 'user@test.com', pw: 'user123', memo: '일반 사용자' },
|
|
11
|
+
];
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
vi.clearAllMocks();
|
|
14
|
+
});
|
|
15
|
+
afterEach(() => {
|
|
16
|
+
vi.restoreAllMocks();
|
|
17
|
+
});
|
|
18
|
+
describe('렌더링', () => {
|
|
19
|
+
it('컴포넌트가 정상적으로 렌더링된다', () => {
|
|
20
|
+
render(React.createElement(IdSelector, { onLogin: mockOnLogin, infos: defaultInfos }));
|
|
21
|
+
expect(screen.getByText('🚀 개발용 빠른 로그인')).toBeTruthy();
|
|
22
|
+
});
|
|
23
|
+
it('전달된 모든 로그인 정보를 렌더링한다', () => {
|
|
24
|
+
render(React.createElement(IdSelector, { onLogin: mockOnLogin, infos: defaultInfos }));
|
|
25
|
+
expect(screen.getByText('관리자')).toBeTruthy();
|
|
26
|
+
expect(screen.getByText('일반 사용자')).toBeTruthy();
|
|
27
|
+
expect(screen.getByText('admin@test.com')).toBeTruthy();
|
|
28
|
+
expect(screen.getByText('user@test.com')).toBeTruthy();
|
|
29
|
+
});
|
|
30
|
+
it('각 카드에 ID와 PW 정보를 표시한다', () => {
|
|
31
|
+
render(React.createElement(IdSelector, { onLogin: mockOnLogin, infos: defaultInfos }));
|
|
32
|
+
// ID와 PW는 여러 카드에 나타나므로 getAllByText 사용
|
|
33
|
+
const idLabels = screen.getAllByText('ID');
|
|
34
|
+
const pwLabels = screen.getAllByText('PW');
|
|
35
|
+
expect(idLabels).toHaveLength(2);
|
|
36
|
+
expect(pwLabels).toHaveLength(2);
|
|
37
|
+
defaultInfos.forEach((info) => {
|
|
38
|
+
expect(screen.getByText(info.id)).toBeTruthy();
|
|
39
|
+
expect(screen.getByText(info.pw)).toBeTruthy();
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
it('빈 배열이 전달되면 카드가 렌더링되지 않는다', () => {
|
|
43
|
+
render(React.createElement(IdSelector, { onLogin: mockOnLogin, infos: [] }));
|
|
44
|
+
expect(screen.getByText('🚀 개발용 빠른 로그인')).toBeTruthy();
|
|
45
|
+
expect(screen.queryByRole('button')).toBeNull();
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
describe('로그인 기능', () => {
|
|
49
|
+
it('로그인 버튼 클릭 시 onLogin이 올바른 인자로 호출된다', async () => {
|
|
50
|
+
const user = userEvent.setup();
|
|
51
|
+
mockOnLogin.mockResolvedValue(undefined);
|
|
52
|
+
render(React.createElement(IdSelector, { onLogin: mockOnLogin, infos: defaultInfos }));
|
|
53
|
+
const adminButton = screen.getByRole('button', { name: '관리자' });
|
|
54
|
+
await user.click(adminButton);
|
|
55
|
+
await waitFor(() => {
|
|
56
|
+
expect(mockOnLogin).toHaveBeenCalledWith('admin@test.com', 'admin123');
|
|
57
|
+
expect(mockOnLogin).toHaveBeenCalledTimes(1);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
it('여러 버튼을 순차적으로 클릭하면 각각의 정보로 onLogin이 호출된다', async () => {
|
|
61
|
+
const user = userEvent.setup();
|
|
62
|
+
mockOnLogin.mockResolvedValue(undefined);
|
|
63
|
+
render(React.createElement(IdSelector, { onLogin: mockOnLogin, infos: defaultInfos }));
|
|
64
|
+
const adminButton = screen.getByRole('button', { name: '관리자' });
|
|
65
|
+
const userButton = screen.getByRole('button', { name: '일반 사용자' });
|
|
66
|
+
await user.click(adminButton);
|
|
67
|
+
await waitFor(() => {
|
|
68
|
+
expect(mockOnLogin).toHaveBeenCalledWith('admin@test.com', 'admin123');
|
|
69
|
+
});
|
|
70
|
+
await user.click(userButton);
|
|
71
|
+
await waitFor(() => {
|
|
72
|
+
expect(mockOnLogin).toHaveBeenCalledWith('user@test.com', 'user123');
|
|
73
|
+
});
|
|
74
|
+
expect(mockOnLogin).toHaveBeenCalledTimes(2);
|
|
75
|
+
});
|
|
76
|
+
it('로그인 중일 때 버튼이 비활성화되고 텍스트가 변경된다', async () => {
|
|
77
|
+
const user = userEvent.setup();
|
|
78
|
+
let resolveLogin;
|
|
79
|
+
const loginPromise = new Promise((resolve) => {
|
|
80
|
+
resolveLogin = resolve;
|
|
81
|
+
});
|
|
82
|
+
mockOnLogin.mockReturnValue(loginPromise);
|
|
83
|
+
render(React.createElement(IdSelector, { onLogin: mockOnLogin, infos: defaultInfos }));
|
|
84
|
+
const adminButton = screen.getByRole('button', { name: '관리자' });
|
|
85
|
+
await user.click(adminButton);
|
|
86
|
+
await waitFor(() => {
|
|
87
|
+
expect(screen.getByText('로그인 중...')).toBeTruthy();
|
|
88
|
+
expect(adminButton.disabled).toBe(true);
|
|
89
|
+
});
|
|
90
|
+
resolveLogin();
|
|
91
|
+
await waitFor(() => {
|
|
92
|
+
expect(screen.getByText('관리자')).toBeTruthy();
|
|
93
|
+
expect(adminButton.disabled).toBe(false);
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
it('로그인 실패 시에도 로딩 상태가 해제된다', async () => {
|
|
97
|
+
const user = userEvent.setup();
|
|
98
|
+
const error = new Error('로그인 실패');
|
|
99
|
+
mockOnLogin.mockRejectedValue(error);
|
|
100
|
+
render(React.createElement(IdSelector, { onLogin: mockOnLogin, infos: defaultInfos }));
|
|
101
|
+
const adminButton = screen.getByRole('button', { name: '관리자' });
|
|
102
|
+
// 에러가 발생하더라도 catch 블록에서 처리되고 finally에서 상태가 해제됨
|
|
103
|
+
await user.click(adminButton);
|
|
104
|
+
// 에러가 발생하더라도 catch 블록에서 처리되고 상태가 해제되므로 기다림
|
|
105
|
+
await waitFor(() => {
|
|
106
|
+
expect(screen.getByText('관리자')).toBeTruthy();
|
|
107
|
+
expect(adminButton.disabled).toBe(false);
|
|
108
|
+
}, { timeout: 3000 });
|
|
109
|
+
// 에러가 발생했는지 확인
|
|
110
|
+
expect(mockOnLogin).toHaveBeenCalled();
|
|
111
|
+
});
|
|
112
|
+
it('한 카드가 로딩 중일 때 다른 카드의 버튼도 클릭 가능하다', async () => {
|
|
113
|
+
const user = userEvent.setup();
|
|
114
|
+
let resolveFirstLogin;
|
|
115
|
+
const firstLoginPromise = new Promise((resolve) => {
|
|
116
|
+
resolveFirstLogin = resolve;
|
|
117
|
+
});
|
|
118
|
+
mockOnLogin.mockImplementation(async (id) => {
|
|
119
|
+
if (id === 'admin@test.com') {
|
|
120
|
+
return firstLoginPromise;
|
|
121
|
+
}
|
|
122
|
+
return Promise.resolve();
|
|
123
|
+
});
|
|
124
|
+
render(React.createElement(IdSelector, { onLogin: mockOnLogin, infos: defaultInfos }));
|
|
125
|
+
const adminButton = screen.getByRole('button', { name: '관리자' });
|
|
126
|
+
const userButton = screen.getByRole('button', { name: '일반 사용자' });
|
|
127
|
+
await user.click(adminButton);
|
|
128
|
+
await waitFor(() => {
|
|
129
|
+
expect(adminButton.disabled).toBe(true);
|
|
130
|
+
});
|
|
131
|
+
// 다른 버튼은 여전히 클릭 가능해야 함
|
|
132
|
+
expect(userButton.disabled).toBe(false);
|
|
133
|
+
await user.click(userButton);
|
|
134
|
+
await waitFor(() => {
|
|
135
|
+
expect(mockOnLogin).toHaveBeenCalledWith('user@test.com', 'user123');
|
|
136
|
+
});
|
|
137
|
+
resolveFirstLogin();
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
describe('호버 상태', () => {
|
|
141
|
+
it('카드에 마우스를 올리면 hover 상태가 적용된다', async () => {
|
|
142
|
+
const user = userEvent.setup();
|
|
143
|
+
render(React.createElement(IdSelector, { onLogin: mockOnLogin, infos: defaultInfos }));
|
|
144
|
+
const adminCard = screen.getByText('admin@test.com').closest('div[style*="border"]');
|
|
145
|
+
expect(adminCard).toBeTruthy();
|
|
146
|
+
// hover 이벤트는 CSS 스타일 변경이므로 스타일 속성을 직접 확인하기 어려움
|
|
147
|
+
// 대신 이벤트 핸들러가 정상 작동하는지 확인
|
|
148
|
+
const adminButton = screen.getByRole('button', { name: '관리자' });
|
|
149
|
+
await user.hover(adminButton);
|
|
150
|
+
// hover 이벤트가 발생했는지 확인 (에러가 없으면 성공)
|
|
151
|
+
expect(adminButton).toBeTruthy();
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
describe('에지 케이스', () => {
|
|
155
|
+
it('메모가 비어있는 경우에도 정상 동작한다', async () => {
|
|
156
|
+
const user = userEvent.setup();
|
|
157
|
+
mockOnLogin.mockResolvedValue(undefined);
|
|
158
|
+
const infosWithEmptyMemo = [
|
|
159
|
+
{ id: 'test@test.com', pw: 'test123', memo: '' },
|
|
160
|
+
];
|
|
161
|
+
render(React.createElement(IdSelector, { onLogin: mockOnLogin, infos: infosWithEmptyMemo }));
|
|
162
|
+
const button = screen.getByRole('button');
|
|
163
|
+
expect(button).toBeTruthy();
|
|
164
|
+
expect(button.textContent).toBe('');
|
|
165
|
+
await user.click(button);
|
|
166
|
+
await waitFor(() => {
|
|
167
|
+
expect(mockOnLogin).toHaveBeenCalledWith('test@test.com', 'test123');
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
it('동일한 ID가 여러 개 있어도 각각 독립적으로 동작한다', async () => {
|
|
171
|
+
const user = userEvent.setup();
|
|
172
|
+
mockOnLogin.mockResolvedValue(undefined);
|
|
173
|
+
const duplicateInfos = [
|
|
174
|
+
{ id: 'same@test.com', pw: 'pw1', memo: '첫 번째' },
|
|
175
|
+
{ id: 'same@test.com', pw: 'pw2', memo: '두 번째' },
|
|
176
|
+
];
|
|
177
|
+
render(React.createElement(IdSelector, { onLogin: mockOnLogin, infos: duplicateInfos }));
|
|
178
|
+
const firstButton = screen.getByRole('button', { name: '첫 번째' });
|
|
179
|
+
const secondButton = screen.getByRole('button', { name: '두 번째' });
|
|
180
|
+
await user.click(firstButton);
|
|
181
|
+
await waitFor(() => {
|
|
182
|
+
expect(mockOnLogin).toHaveBeenCalledWith('same@test.com', 'pw1');
|
|
183
|
+
});
|
|
184
|
+
await user.click(secondButton);
|
|
185
|
+
await waitFor(() => {
|
|
186
|
+
expect(mockOnLogin).toHaveBeenCalledWith('same@test.com', 'pw2');
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
it('매우 긴 텍스트가 있어도 정상 렌더링된다', () => {
|
|
190
|
+
const longTextInfos = [
|
|
191
|
+
{
|
|
192
|
+
id: 'verylongemailaddressthatmightoverflow@example.com',
|
|
193
|
+
pw: 'verylongpasswordthatexceedsnormallimits123456789',
|
|
194
|
+
memo: '매우 긴 메모 텍스트가 있는 계정입니다. 이 텍스트는 매우 길 수 있습니다.',
|
|
195
|
+
},
|
|
196
|
+
];
|
|
197
|
+
render(React.createElement(IdSelector, { onLogin: mockOnLogin, infos: longTextInfos }));
|
|
198
|
+
expect(screen.getByText(/매우 긴 메모/)).toBeTruthy();
|
|
199
|
+
expect(screen.getByText(/verylongemail/)).toBeTruthy();
|
|
200
|
+
expect(screen.getByText(/verylongpassword/)).toBeTruthy();
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { LoginInfo } from './IdSelector';
|
|
3
|
+
type LoginCardProps = {
|
|
4
|
+
info: LoginInfo;
|
|
5
|
+
index: number;
|
|
6
|
+
loading: number | null;
|
|
7
|
+
hoveredIndex: number | null;
|
|
8
|
+
hoveredButton: number | null;
|
|
9
|
+
onMouseEnter: () => void;
|
|
10
|
+
onMouseLeave: () => void;
|
|
11
|
+
onButtonMouseEnter: () => void;
|
|
12
|
+
onButtonMouseLeave: () => void;
|
|
13
|
+
onLogin: (info: LoginInfo, index: number) => Promise<void>;
|
|
14
|
+
};
|
|
15
|
+
export declare const LoginCard: React.FC<LoginCardProps>;
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=LoginCard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LoginCard.d.ts","sourceRoot":"","sources":["../../../../src/components/dev/IdSelector/LoginCard.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAUzC,KAAK,cAAc,GAAG;IACpB,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,OAAO,EAAE,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5D,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC,cAAc,CAyC9C,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { getCardStyle, getButtonStyle, infoContainerStyle, infoRowStyle, labelStyle, valueStyle, } from './styles';
|
|
3
|
+
export const LoginCard = ({ info, index, loading, hoveredIndex, hoveredButton, onMouseEnter, onMouseLeave, onButtonMouseEnter, onButtonMouseLeave, onLogin, }) => {
|
|
4
|
+
const handleClick = () => {
|
|
5
|
+
onLogin(info, index);
|
|
6
|
+
};
|
|
7
|
+
return (React.createElement("div", { style: getCardStyle(hoveredIndex, index), onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave },
|
|
8
|
+
React.createElement("button", { onClick: handleClick, disabled: loading === index, style: getButtonStyle(hoveredButton, loading, index), onMouseEnter: onButtonMouseEnter, onMouseLeave: onButtonMouseLeave }, loading === index ? '로그인 중...' : info.memo),
|
|
9
|
+
React.createElement("div", { style: infoContainerStyle },
|
|
10
|
+
React.createElement("div", { style: infoRowStyle },
|
|
11
|
+
React.createElement("span", { style: labelStyle }, "ID"),
|
|
12
|
+
React.createElement("span", { style: valueStyle }, info.id)),
|
|
13
|
+
React.createElement("div", { style: infoRowStyle },
|
|
14
|
+
React.createElement("span", { style: labelStyle }, "PW"),
|
|
15
|
+
React.createElement("span", { style: valueStyle }, info.pw)))));
|
|
16
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/dev/IdSelector/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,YAAY,EAAE,KAAK,IAAI,eAAe,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './IdSelector';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { CSSProperties } from 'react';
|
|
2
|
+
export type StyleProps = {
|
|
3
|
+
hoveredIndex: number | null;
|
|
4
|
+
hoveredButton: number | null;
|
|
5
|
+
loading: number | null;
|
|
6
|
+
index: number;
|
|
7
|
+
};
|
|
8
|
+
export declare const getContainerStyle: () => CSSProperties;
|
|
9
|
+
export declare const getHeaderStyle: () => CSSProperties;
|
|
10
|
+
export declare const getCardStyle: (hoveredIndex: number | null, index: number) => CSSProperties;
|
|
11
|
+
export declare const getButtonStyle: (hoveredButton: number | null, loading: number | null, index: number) => CSSProperties;
|
|
12
|
+
export declare const infoContainerStyle: CSSProperties;
|
|
13
|
+
export declare const infoRowStyle: CSSProperties;
|
|
14
|
+
export declare const labelStyle: CSSProperties;
|
|
15
|
+
export declare const valueStyle: CSSProperties;
|
|
16
|
+
//# sourceMappingURL=styles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../../../../src/components/dev/IdSelector/styles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAEtC,MAAM,MAAM,UAAU,GAAG;IACvB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,eAAO,MAAM,iBAAiB,QAAO,aAenC,CAAC;AAEH,eAAO,MAAM,cAAc,QAAO,aAMhC,CAAC;AAEH,eAAO,MAAM,YAAY,GAAI,cAAc,MAAM,GAAG,IAAI,EAAE,OAAO,MAAM,KAAG,aASxE,CAAC;AAEH,eAAO,MAAM,cAAc,GACzB,eAAe,MAAM,GAAG,IAAI,EAC5B,SAAS,MAAM,GAAG,IAAI,EACtB,OAAO,MAAM,KACZ,aAUD,CAAC;AAEH,eAAO,MAAM,kBAAkB,EAAE,aAQhC,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,aAI1B,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,aAGxB,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,aAGxB,CAAC"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
export const getContainerStyle = () => ({
|
|
2
|
+
position: 'fixed',
|
|
3
|
+
top: '50%',
|
|
4
|
+
right: '16px',
|
|
5
|
+
transform: 'translateY(-50%)',
|
|
6
|
+
display: 'flex',
|
|
7
|
+
flexDirection: 'column',
|
|
8
|
+
gap: '12px',
|
|
9
|
+
padding: '16px',
|
|
10
|
+
backgroundColor: '#ffffff',
|
|
11
|
+
borderRadius: '12px',
|
|
12
|
+
boxShadow: '0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)',
|
|
13
|
+
border: '1px solid #e5e7eb',
|
|
14
|
+
minWidth: '280px',
|
|
15
|
+
zIndex: 9999,
|
|
16
|
+
});
|
|
17
|
+
export const getHeaderStyle = () => ({
|
|
18
|
+
color: '#111827',
|
|
19
|
+
fontSize: '14px',
|
|
20
|
+
fontWeight: 'bold',
|
|
21
|
+
paddingBottom: '8px',
|
|
22
|
+
borderBottom: '1px solid #e5e7eb',
|
|
23
|
+
});
|
|
24
|
+
export const getCardStyle = (hoveredIndex, index) => ({
|
|
25
|
+
display: 'flex',
|
|
26
|
+
flexDirection: 'column',
|
|
27
|
+
gap: '8px',
|
|
28
|
+
padding: '12px',
|
|
29
|
+
backgroundColor: '#f9fafb',
|
|
30
|
+
borderRadius: '8px',
|
|
31
|
+
border: hoveredIndex === index ? '1px solid #60a5fa' : '1px solid #e5e7eb',
|
|
32
|
+
transition: 'all 0.2s',
|
|
33
|
+
});
|
|
34
|
+
export const getButtonStyle = (hoveredButton, loading, index) => ({
|
|
35
|
+
width: '100%',
|
|
36
|
+
padding: '8px 16px',
|
|
37
|
+
backgroundColor: loading === index ? '#9ca3af' : hoveredButton === index ? '#2563eb' : '#3b82f6',
|
|
38
|
+
color: 'white',
|
|
39
|
+
fontWeight: 600,
|
|
40
|
+
borderRadius: '8px',
|
|
41
|
+
border: 'none',
|
|
42
|
+
cursor: loading === index ? 'not-allowed' : 'pointer',
|
|
43
|
+
transition: 'background-color 0.2s',
|
|
44
|
+
});
|
|
45
|
+
export const infoContainerStyle = {
|
|
46
|
+
display: 'flex',
|
|
47
|
+
flexDirection: 'column',
|
|
48
|
+
gap: '4px',
|
|
49
|
+
fontSize: '12px',
|
|
50
|
+
color: '#6b7280',
|
|
51
|
+
paddingLeft: '4px',
|
|
52
|
+
paddingRight: '4px',
|
|
53
|
+
};
|
|
54
|
+
export const infoRowStyle = {
|
|
55
|
+
display: 'flex',
|
|
56
|
+
alignItems: 'center',
|
|
57
|
+
gap: '8px',
|
|
58
|
+
};
|
|
59
|
+
export const labelStyle = {
|
|
60
|
+
fontWeight: 600,
|
|
61
|
+
minWidth: '24px',
|
|
62
|
+
};
|
|
63
|
+
export const valueStyle = {
|
|
64
|
+
fontFamily: 'monospace',
|
|
65
|
+
color: '#374151',
|
|
66
|
+
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { useWindowSize } from '../../hooks
|
|
2
|
+
import { useWindowSize } from '../../hooks';
|
|
3
3
|
const positionStyles = {
|
|
4
4
|
'top-left': { top: 16, left: 16 },
|
|
5
5
|
'top-right': { top: 16, right: 16 },
|
|
@@ -13,7 +13,7 @@ const positionStyles = {
|
|
|
13
13
|
* @example
|
|
14
14
|
* ```tsx
|
|
15
15
|
* // Vite 프로젝트
|
|
16
|
-
* import { WindowSizeDisplay } from '
|
|
16
|
+
* import { WindowSizeDisplay } from '@blastlabs/utils/components/dev';
|
|
17
17
|
*
|
|
18
18
|
* function App() {
|
|
19
19
|
* return (
|
|
@@ -6,7 +6,7 @@ import React, { useState, useEffect } from 'react';
|
|
|
6
6
|
* @example
|
|
7
7
|
* ```tsx
|
|
8
8
|
* // Vite 프로젝트
|
|
9
|
-
* import { ZIndexDebugger } from '
|
|
9
|
+
* import { ZIndexDebugger } from '@blastlabs/utils/components/dev';
|
|
10
10
|
*
|
|
11
11
|
* function App() {
|
|
12
12
|
* return (
|
|
@@ -5,11 +5,12 @@
|
|
|
5
5
|
* production 환경에서는 제외하는 것을 권장합니다.
|
|
6
6
|
*/
|
|
7
7
|
export { default as IdSelector } from './IdSelector';
|
|
8
|
+
export type { IdSelectorProps, LoginInfo } from './IdSelector';
|
|
8
9
|
export { default as WindowSizeDisplay } from './WindowSizeDisplay';
|
|
9
10
|
export { default as DevPanel } from './DevPanel';
|
|
10
11
|
export { default as ZIndexDebugger } from './ZIndexDebugger';
|
|
11
12
|
export { default as ApiLogger, addApiLog, clearApiLogs } from './ApiLogger';
|
|
12
13
|
export { default as FormDevTools } from './FormDevTools';
|
|
13
|
-
export type { FormDevToolsProps
|
|
14
|
+
export type { FormDevToolsProps } from './FormDevTools';
|
|
14
15
|
export type { ApiLogEntry } from './ApiLogger';
|
|
15
16
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +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,
|
|
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,YAAY,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC/D,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,MAAM,gBAAgB,CAAC;AACxD,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/hooks/event/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useClickOutside.d.ts","sourceRoot":"","sources":["../../../src/hooks/event/useClickOutside.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,SAAS,EAAE,MAAM,OAAO,CAAC;AAE7C;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW,EACjE,GAAG,EAAE,SAAS,CAAC,CAAC,CAAC,EACjB,OAAO,EAAE,CAAC,KAAK,EAAE,UAAU,GAAG,UAAU,KAAK,IAAI,EACjD,OAAO,GAAE,OAAc,GACtB,IAAI,CA2BN;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,uBAAuB,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW,EACzE,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,EACpB,OAAO,EAAE,CAAC,KAAK,EAAE,UAAU,GAAG,UAAU,KAAK,IAAI,EACjD,OAAO,GAAE,OAAc,GACtB,IAAI,CA6BN"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useEventListener.d.ts","sourceRoot":"","sources":["../../../src/hooks/event/useEventListener.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,SAAS,EAAE,MAAM,OAAO,CAAC;AAErD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyEG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,MAAM,cAAc,EAC7D,SAAS,EAAE,CAAC,EACZ,OAAO,EAAE,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,KAAK,IAAI,EAC3C,OAAO,CAAC,EAAE,SAAS,EACnB,OAAO,CAAC,EAAE,OAAO,GAAG,uBAAuB,GAC1C,IAAI,CAAC;AAER,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,MAAM,mBAAmB,EAAE,CAAC,SAAS,WAAW,GAAG,cAAc,EAC1G,SAAS,EAAE,CAAC,EACZ,OAAO,EAAE,CAAC,KAAK,EAAE,mBAAmB,CAAC,CAAC,CAAC,KAAK,IAAI,EAChD,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,EACrB,OAAO,CAAC,EAAE,OAAO,GAAG,uBAAuB,GAC1C,IAAI,CAAC;AAER,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,MAAM,gBAAgB,EAC/D,SAAS,EAAE,CAAC,EACZ,OAAO,EAAE,CAAC,KAAK,EAAE,gBAAgB,CAAC,CAAC,CAAC,KAAK,IAAI,EAC7C,OAAO,EAAE,QAAQ,EACjB,OAAO,CAAC,EAAE,OAAO,GAAG,uBAAuB,GAC1C,IAAI,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useCRUDForm.test.d.ts","sourceRoot":"","sources":["../../../../src/hooks/form/__tests__/useCRUDForm.test.ts"],"names":[],"mappings":""}
|