@blastlabs/utils 1.12.0 → 1.12.1
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 +20 -13
- package/dist/components/auth/AuthGuard.d.ts +95 -0
- package/dist/components/auth/AuthGuard.d.ts.map +1 -0
- package/dist/components/auth/AuthGuard.js +103 -0
- package/dist/components/auth/index.d.ts +5 -0
- package/dist/components/auth/index.d.ts.map +1 -0
- package/dist/components/auth/index.js +4 -0
- package/dist/components/dev/ApiLogger.d.ts +1 -1
- package/dist/components/dev/ApiLogger.js +1 -1
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +1 -0
- package/dist/hooks/auth/__tests__/useAuth.test.d.ts +2 -0
- package/dist/hooks/auth/__tests__/useAuth.test.d.ts.map +1 -0
- package/dist/hooks/auth/__tests__/useAuth.test.js +139 -0
- package/dist/hooks/auth/index.d.ts +5 -0
- package/dist/hooks/auth/index.d.ts.map +1 -0
- package/dist/hooks/auth/index.js +4 -0
- package/dist/hooks/auth/useAuth.d.ts +275 -0
- package/dist/hooks/auth/useAuth.d.ts.map +1 -0
- package/dist/hooks/auth/useAuth.js +384 -0
- package/dist/hooks/form/useCRUDForm.d.ts +7 -28
- package/dist/hooks/form/useCRUDForm.d.ts.map +1 -1
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +2 -0
- package/dist/hooks/ui/index.d.ts +1 -0
- package/dist/hooks/ui/index.d.ts.map +1 -1
- package/dist/hooks/ui/index.js +1 -0
- package/dist/hooks/ui/useTabs.d.ts +33 -0
- package/dist/hooks/ui/useTabs.d.ts.map +1 -0
- package/dist/hooks/ui/useTabs.js +117 -0
- package/dist/index.js +1 -1
- package/package.json +1 -1
|
@@ -1,37 +1,15 @@
|
|
|
1
|
-
import type { FieldValues } from 'react-hook-form';
|
|
1
|
+
import type { FieldValues, UseFormReturn } from 'react-hook-form';
|
|
2
2
|
/**
|
|
3
3
|
* CRUD Form Mode
|
|
4
4
|
*/
|
|
5
5
|
export type FormMode = 'create' | 'edit';
|
|
6
|
-
|
|
7
|
-
watch: (name?: any) => any;
|
|
8
|
-
getValues: (name?: any) => any;
|
|
9
|
-
setValue: (name: any, value: any, options?: {
|
|
10
|
-
shouldValidate?: boolean;
|
|
11
|
-
shouldDirty?: boolean;
|
|
12
|
-
shouldTouch?: boolean;
|
|
13
|
-
}) => void;
|
|
14
|
-
trigger?: (name?: any) => Promise<boolean>;
|
|
15
|
-
formState: {
|
|
16
|
-
errors?: Record<string, any>;
|
|
17
|
-
dirtyFields?: Record<string, any>;
|
|
18
|
-
touchedFields?: Record<string, any>;
|
|
19
|
-
isValid?: boolean;
|
|
20
|
-
isSubmitting?: boolean;
|
|
21
|
-
submitCount?: number;
|
|
22
|
-
defaultValues?: TFieldValues;
|
|
23
|
-
};
|
|
24
|
-
handleSubmit?: (...args: any[]) => any;
|
|
25
|
-
register?: (...args: any[]) => any;
|
|
26
|
-
reset?: (...args: any[]) => any;
|
|
27
|
-
[key: string]: any;
|
|
28
|
-
};
|
|
6
|
+
type TId = string | number | null;
|
|
29
7
|
/**
|
|
30
8
|
* useCRUDForm 옵션
|
|
31
9
|
*/
|
|
32
|
-
export interface UseCRUDFormOptions<TData extends FieldValues = FieldValues
|
|
10
|
+
export interface UseCRUDFormOptions<TData extends FieldValues = FieldValues> {
|
|
33
11
|
/** 편집 모드일 때의 ID (있으면 edit mode, 없으면 create mode) */
|
|
34
|
-
id?: TId
|
|
12
|
+
id?: TId;
|
|
35
13
|
/** react-hook-form instance */
|
|
36
14
|
form: UseFormReturn<TData>;
|
|
37
15
|
/** 편집 모드일 때 데이터를 fetch하는 함수 */
|
|
@@ -39,7 +17,7 @@ export interface UseCRUDFormOptions<TData extends FieldValues = FieldValues, TId
|
|
|
39
17
|
/** 생성 API 함수 */
|
|
40
18
|
createFn?: (data: TData) => Promise<any>;
|
|
41
19
|
/** 수정 API 함수 */
|
|
42
|
-
updateFn?: (id: TId, data: TData) => Promise<any>;
|
|
20
|
+
updateFn?: (id: Exclude<TId, null | undefined>, data: TData) => Promise<any>;
|
|
43
21
|
/** 삭제 API 함수 (옵션) */
|
|
44
22
|
deleteFn?: (id: TId) => Promise<any>;
|
|
45
23
|
/** 성공 시 콜백 */
|
|
@@ -228,5 +206,6 @@ export interface UseCRUDFormReturn<TData = any, TId = string | number> {
|
|
|
228
206
|
* }
|
|
229
207
|
* ```
|
|
230
208
|
*/
|
|
231
|
-
export declare function useCRUDForm<TData extends FieldValues = FieldValues
|
|
209
|
+
export declare function useCRUDForm<TData extends FieldValues = FieldValues>(options: UseCRUDFormOptions<TData>): UseCRUDFormReturn<TData>;
|
|
210
|
+
export {};
|
|
232
211
|
//# sourceMappingURL=useCRUDForm.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useCRUDForm.d.ts","sourceRoot":"","sources":["../../../src/hooks/form/useCRUDForm.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"useCRUDForm.d.ts","sourceRoot":"","sources":["../../../src/hooks/form/useCRUDForm.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAElE;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAAC;AAiCzC,KAAK,GAAG,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;AAClC;;GAEG;AACH,MAAM,WAAW,kBAAkB,CAAC,KAAK,SAAS,WAAW,GAAG,WAAW;IACzE,oDAAoD;IACpD,EAAE,CAAC,EAAE,GAAG,CAAC;IAET,+BAA+B;IAC/B,IAAI,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC;IAE3B,+BAA+B;IAC/B,OAAO,CAAC,EAAE,CAAC,EAAE,EAAE,GAAG,KAAK,OAAO,CAAC,KAAK,CAAC,CAAC;IAEtC,gBAAgB;IAChB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;IAEzC,gBAAgB;IAChB,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,OAAO,CAAC,GAAG,EAAE,IAAI,GAAG,SAAS,CAAC,EAAE,IAAI,EAAE,KAAK,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;IAE7E,qBAAqB;IACrB,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;IAErC,cAAc;IACd,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAElE,cAAc;IACd,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,KAAK,IAAI,CAAC;IAEjD,qCAAqC;IACrC,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,IAAI,CAAC;IAEvC,oCAAoC;IACpC,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,KAAK,GAAG,CAAC;IAErD,sCAAsC;IACtC,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB,CAAC,KAAK,GAAG,GAAG,EAAE,GAAG,GAAG,MAAM,GAAG,MAAM;IACnE,cAAc;IACd,IAAI,EAAE,QAAQ,CAAC;IAEf,eAAe;IACf,UAAU,EAAE,OAAO,CAAC;IAEpB,eAAe;IACf,YAAY,EAAE,OAAO,CAAC;IAEtB,uBAAuB;IACvB,SAAS,EAAE,OAAO,CAAC;IAEnB,+BAA+B;IAC/B,YAAY,EAAE,OAAO,CAAC;IAEtB,WAAW;IACX,UAAU,EAAE,OAAO,CAAC;IAEpB,SAAS;IACT,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IAEpB,4CAA4C;IAC5C,MAAM,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvC,aAAa;IACb,YAAY,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAElC,iBAAiB;IACjB,YAAY,EAAE,KAAK,GAAG,IAAI,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqJG;AACH,wBAAgB,WAAW,CAAC,KAAK,SAAS,WAAW,GAAG,WAAW,EACjE,OAAO,EAAE,kBAAkB,CAAC,KAAK,CAAC,GACjC,iBAAiB,CAAC,KAAK,CAAC,CAiI1B"}
|
package/dist/hooks/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,cAAc,SAAS,CAAC;AAGxB,cAAc,eAAe,CAAC;AAG9B,cAAc,SAAS,CAAC;AAGxB,cAAc,QAAQ,CAAC;AAGvB,cAAc,QAAQ,CAAC;AAGvB,cAAc,MAAM,CAAC;AAGrB,cAAc,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,cAAc,SAAS,CAAC;AAGxB,cAAc,eAAe,CAAC;AAG9B,cAAc,SAAS,CAAC;AAGxB,cAAc,QAAQ,CAAC;AAGvB,cAAc,QAAQ,CAAC;AAGvB,cAAc,MAAM,CAAC;AAGrB,cAAc,WAAW,CAAC;AAG1B,cAAc,QAAQ,CAAC"}
|
package/dist/hooks/index.js
CHANGED
package/dist/hooks/ui/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/hooks/ui/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/hooks/ui/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC"}
|
package/dist/hooks/ui/index.js
CHANGED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
type UseTabsOptions = {
|
|
2
|
+
items: Array<{
|
|
3
|
+
id: string;
|
|
4
|
+
}>;
|
|
5
|
+
defaultTab?: string;
|
|
6
|
+
syncWithUrl?: boolean;
|
|
7
|
+
urlParamName?: string;
|
|
8
|
+
};
|
|
9
|
+
type UseTabsReturn = {
|
|
10
|
+
selectedTab: string;
|
|
11
|
+
selectedIndex: number;
|
|
12
|
+
setSelectedTab: (tabId: string) => void;
|
|
13
|
+
setSelectedIndex: (index: number) => void;
|
|
14
|
+
getTabId: (index: number) => string | undefined;
|
|
15
|
+
getTabIndex: (tabId: string) => number;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* 탭 상태 관리 훅
|
|
19
|
+
* URL 동기화 및 상태 관리 로직을 제공
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```tsx
|
|
23
|
+
* const { selectedTab, setSelectedTab, selectedIndex } = useTabs({
|
|
24
|
+
* items: tabs,
|
|
25
|
+
* defaultTab: 'tab1',
|
|
26
|
+
* syncWithUrl: true,
|
|
27
|
+
* urlParamName: 'tab'
|
|
28
|
+
* });
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export declare function useTabs({ items, defaultTab, syncWithUrl, urlParamName, }: UseTabsOptions): UseTabsReturn;
|
|
32
|
+
export {};
|
|
33
|
+
//# sourceMappingURL=useTabs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useTabs.d.ts","sourceRoot":"","sources":["../../../src/hooks/ui/useTabs.ts"],"names":[],"mappings":"AAIA,KAAK,cAAc,GAAG;IACpB,KAAK,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,KAAK,aAAa,GAAG;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,gBAAgB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IAChD,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;CACxC,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,wBAAgB,OAAO,CAAC,EACtB,KAAK,EACL,UAAU,EACV,WAAmB,EACnB,YAAoB,GACrB,EAAE,cAAc,GAAG,aAAa,CA4GhC"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { useState, useEffect, useMemo, useCallback } from 'react';
|
|
3
|
+
/**
|
|
4
|
+
* 탭 상태 관리 훅
|
|
5
|
+
* URL 동기화 및 상태 관리 로직을 제공
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```tsx
|
|
9
|
+
* const { selectedTab, setSelectedTab, selectedIndex } = useTabs({
|
|
10
|
+
* items: tabs,
|
|
11
|
+
* defaultTab: 'tab1',
|
|
12
|
+
* syncWithUrl: true,
|
|
13
|
+
* urlParamName: 'tab'
|
|
14
|
+
* });
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export function useTabs({ items, defaultTab, syncWithUrl = false, urlParamName = 'tab', }) {
|
|
18
|
+
// URL에서 탭 ID 가져오기
|
|
19
|
+
const getTabFromUrl = useCallback(() => {
|
|
20
|
+
if (!syncWithUrl || typeof window === 'undefined') {
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
const params = new URLSearchParams(window.location.search);
|
|
24
|
+
return params.get(urlParamName) || undefined;
|
|
25
|
+
}, [syncWithUrl, urlParamName]);
|
|
26
|
+
// 초기 선택된 탭 결정 (우선순위: URL > defaultTab > 첫 번째)
|
|
27
|
+
const initialSelectedTab = useMemo(() => {
|
|
28
|
+
if (syncWithUrl) {
|
|
29
|
+
const urlTab = getTabFromUrl();
|
|
30
|
+
if (urlTab)
|
|
31
|
+
return urlTab;
|
|
32
|
+
}
|
|
33
|
+
return defaultTab || items[0]?.id || '';
|
|
34
|
+
}, [syncWithUrl, defaultTab, items, getTabFromUrl]);
|
|
35
|
+
const [selectedTab, setSelectedTabState] = useState(initialSelectedTab);
|
|
36
|
+
// 선택된 탭의 인덱스
|
|
37
|
+
const selectedIndex = useMemo(() => {
|
|
38
|
+
const index = items.findIndex((item) => item.id === selectedTab);
|
|
39
|
+
return index >= 0 ? index : 0;
|
|
40
|
+
}, [items, selectedTab]);
|
|
41
|
+
// URL 업데이트 함수
|
|
42
|
+
const updateUrl = (tabId) => {
|
|
43
|
+
if (!syncWithUrl || typeof window === 'undefined')
|
|
44
|
+
return;
|
|
45
|
+
const url = new URL(window.location.href);
|
|
46
|
+
if (tabId === defaultTab) {
|
|
47
|
+
// 기본 탭이면 URL에서 제거 (깔끔한 URL 유지)
|
|
48
|
+
url.searchParams.delete(urlParamName);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
url.searchParams.set(urlParamName, tabId);
|
|
52
|
+
}
|
|
53
|
+
window.history.pushState({}, '', url.toString());
|
|
54
|
+
};
|
|
55
|
+
// 탭 ID로 선택
|
|
56
|
+
const setSelectedTab = (tabId) => {
|
|
57
|
+
setSelectedTabState(tabId);
|
|
58
|
+
if (syncWithUrl) {
|
|
59
|
+
updateUrl(tabId);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
// 인덱스로 선택
|
|
63
|
+
const setSelectedIndex = (index) => {
|
|
64
|
+
const tabId = items[index]?.id;
|
|
65
|
+
if (tabId) {
|
|
66
|
+
setSelectedTab(tabId);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
// 인덱스로 탭 ID 가져오기
|
|
70
|
+
const getTabId = (index) => {
|
|
71
|
+
return items[index]?.id;
|
|
72
|
+
};
|
|
73
|
+
// 탭 ID로 인덱스 가져오기
|
|
74
|
+
const getTabIndex = (tabId) => {
|
|
75
|
+
return items.findIndex((item) => item.id === tabId);
|
|
76
|
+
};
|
|
77
|
+
// 브라우저 뒤로가기/앞으로가기 지원
|
|
78
|
+
useEffect(() => {
|
|
79
|
+
if (!syncWithUrl || typeof window === 'undefined')
|
|
80
|
+
return;
|
|
81
|
+
const handlePopState = () => {
|
|
82
|
+
const urlTab = getTabFromUrl();
|
|
83
|
+
if (urlTab) {
|
|
84
|
+
setSelectedTabState(urlTab);
|
|
85
|
+
}
|
|
86
|
+
else if (defaultTab) {
|
|
87
|
+
setSelectedTabState(defaultTab);
|
|
88
|
+
}
|
|
89
|
+
else if (items[0]?.id) {
|
|
90
|
+
setSelectedTabState(items[0].id);
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
window.addEventListener('popstate', handlePopState);
|
|
94
|
+
return () => {
|
|
95
|
+
window.removeEventListener('popstate', handlePopState);
|
|
96
|
+
};
|
|
97
|
+
}, [syncWithUrl, defaultTab, items, getTabFromUrl]);
|
|
98
|
+
// URL 초기 동기화
|
|
99
|
+
useEffect(() => {
|
|
100
|
+
if (!syncWithUrl || typeof window === 'undefined')
|
|
101
|
+
return;
|
|
102
|
+
const urlTab = getTabFromUrl();
|
|
103
|
+
if (urlTab && urlTab !== selectedTab) {
|
|
104
|
+
// URL과 상태가 다를 때만 업데이트 (초기 로드 시)
|
|
105
|
+
setSelectedTabState(urlTab);
|
|
106
|
+
}
|
|
107
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
108
|
+
}, [syncWithUrl, urlParamName]); // 초기 마운트 시에만 실행
|
|
109
|
+
return {
|
|
110
|
+
selectedTab,
|
|
111
|
+
selectedIndex,
|
|
112
|
+
setSelectedTab,
|
|
113
|
+
setSelectedIndex,
|
|
114
|
+
getTabId,
|
|
115
|
+
getTabIndex,
|
|
116
|
+
};
|
|
117
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -8,7 +8,7 @@ export * from './string';
|
|
|
8
8
|
export * from './number';
|
|
9
9
|
// Mock data utilities
|
|
10
10
|
export * from './mock';
|
|
11
|
-
// React Hooks (import separately: '
|
|
11
|
+
// React Hooks (import separately: '@blastlabs/utils/hooks')
|
|
12
12
|
// Note: Hooks are not exported from main entry to avoid React dependency for non-React users
|
|
13
13
|
// export * from './hooks';
|
|
14
14
|
// Array utilities (placeholder for future)
|