@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.
Files changed (137) hide show
  1. package/README.md +267 -0
  2. package/dist/components/dev/ApiLogger.d.ts +136 -0
  3. package/dist/components/dev/ApiLogger.d.ts.map +1 -0
  4. package/dist/components/dev/ApiLogger.js +408 -0
  5. package/dist/components/dev/DevPanel.d.ts +32 -0
  6. package/dist/components/dev/DevPanel.d.ts.map +1 -0
  7. package/dist/components/dev/DevPanel.js +196 -0
  8. package/dist/components/dev/FormDevTools/FormDevTools.d.ts +136 -0
  9. package/dist/components/dev/FormDevTools/FormDevTools.d.ts.map +1 -0
  10. package/dist/components/dev/FormDevTools/FormDevTools.js +442 -0
  11. package/dist/components/dev/FormDevTools/index.d.ts +3 -0
  12. package/dist/components/dev/FormDevTools/index.d.ts.map +1 -0
  13. package/dist/components/dev/FormDevTools/index.js +1 -0
  14. package/dist/components/dev/FormDevTools/styles.d.ts +45 -0
  15. package/dist/components/dev/FormDevTools/styles.d.ts.map +1 -0
  16. package/dist/components/dev/FormDevTools/styles.js +197 -0
  17. package/dist/components/dev/IdSelector.d.ts +50 -0
  18. package/dist/components/dev/IdSelector.d.ts.map +1 -0
  19. package/dist/components/dev/IdSelector.js +129 -0
  20. package/dist/components/dev/WindowSizeDisplay.d.ts +44 -0
  21. package/dist/components/dev/WindowSizeDisplay.d.ts.map +1 -0
  22. package/dist/components/dev/WindowSizeDisplay.js +74 -0
  23. package/dist/components/dev/ZIndexDebugger.d.ts +32 -0
  24. package/dist/components/dev/ZIndexDebugger.d.ts.map +1 -0
  25. package/dist/components/dev/ZIndexDebugger.js +184 -0
  26. package/dist/components/dev/index.d.ts +15 -0
  27. package/dist/components/dev/index.d.ts.map +1 -0
  28. package/dist/components/dev/index.js +12 -0
  29. package/dist/components/index.d.ts +8 -0
  30. package/dist/components/index.d.ts.map +1 -0
  31. package/dist/components/index.js +7 -0
  32. package/dist/date/index.d.ts +64 -0
  33. package/dist/date/index.d.ts.map +1 -0
  34. package/dist/date/index.js +92 -0
  35. package/dist/date/index.test.d.ts +2 -0
  36. package/dist/date/index.test.d.ts.map +1 -0
  37. package/dist/date/index.test.js +166 -0
  38. package/dist/form/__tests__/formatter.test.d.ts +2 -0
  39. package/dist/form/__tests__/formatter.test.d.ts.map +1 -0
  40. package/dist/form/__tests__/formatter.test.js +74 -0
  41. package/dist/form/__tests__/helpers.test.d.ts +2 -0
  42. package/dist/form/__tests__/helpers.test.d.ts.map +1 -0
  43. package/dist/form/__tests__/helpers.test.js +42 -0
  44. package/dist/form/__tests__/validation.test.d.ts +2 -0
  45. package/dist/form/__tests__/validation.test.d.ts.map +1 -0
  46. package/dist/form/__tests__/validation.test.js +67 -0
  47. package/dist/form/formatter.d.ts +34 -0
  48. package/dist/form/formatter.d.ts.map +1 -0
  49. package/dist/form/formatter.js +76 -0
  50. package/dist/form/helpers.d.ts +16 -0
  51. package/dist/form/helpers.d.ts.map +1 -0
  52. package/dist/form/helpers.js +34 -0
  53. package/dist/form/index.d.ts +9 -0
  54. package/dist/form/index.d.ts.map +1 -0
  55. package/dist/form/index.js +11 -0
  56. package/dist/form/validation.d.ts +33 -0
  57. package/dist/form/validation.d.ts.map +1 -0
  58. package/dist/form/validation.js +56 -0
  59. package/dist/hooks/index.d.ts +19 -0
  60. package/dist/hooks/index.d.ts.map +1 -0
  61. package/dist/hooks/index.js +23 -0
  62. package/dist/hooks/useClickOutside.d.ts +49 -0
  63. package/dist/hooks/useClickOutside.d.ts.map +1 -0
  64. package/dist/hooks/useClickOutside.js +94 -0
  65. package/dist/hooks/useCopyToClipboard.d.ts +67 -0
  66. package/dist/hooks/useCopyToClipboard.d.ts.map +1 -0
  67. package/dist/hooks/useCopyToClipboard.js +79 -0
  68. package/dist/hooks/useDebounce.d.ts +47 -0
  69. package/dist/hooks/useDebounce.d.ts.map +1 -0
  70. package/dist/hooks/useDebounce.js +60 -0
  71. package/dist/hooks/useEventListener.d.ts +79 -0
  72. package/dist/hooks/useEventListener.d.ts.map +1 -0
  73. package/dist/hooks/useEventListener.js +33 -0
  74. package/dist/hooks/useIntersectionObserver.d.ts +109 -0
  75. package/dist/hooks/useIntersectionObserver.d.ts.map +1 -0
  76. package/dist/hooks/useIntersectionObserver.js +128 -0
  77. package/dist/hooks/useLocalStorage.d.ts +19 -0
  78. package/dist/hooks/useLocalStorage.d.ts.map +1 -0
  79. package/dist/hooks/useLocalStorage.js +91 -0
  80. package/dist/hooks/useMediaQuery.d.ts +56 -0
  81. package/dist/hooks/useMediaQuery.d.ts.map +1 -0
  82. package/dist/hooks/useMediaQuery.js +104 -0
  83. package/dist/hooks/usePrevious.d.ts +58 -0
  84. package/dist/hooks/usePrevious.d.ts.map +1 -0
  85. package/dist/hooks/usePrevious.js +67 -0
  86. package/dist/hooks/useSessionStorage.d.ts +19 -0
  87. package/dist/hooks/useSessionStorage.d.ts.map +1 -0
  88. package/dist/hooks/useSessionStorage.js +85 -0
  89. package/dist/hooks/useThrottle.d.ts +57 -0
  90. package/dist/hooks/useThrottle.d.ts.map +1 -0
  91. package/dist/hooks/useThrottle.js +80 -0
  92. package/dist/hooks/useToggle.d.ts +49 -0
  93. package/dist/hooks/useToggle.d.ts.map +1 -0
  94. package/dist/hooks/useToggle.js +56 -0
  95. package/dist/hooks/useWindowSize.d.ts +58 -0
  96. package/dist/hooks/useWindowSize.d.ts.map +1 -0
  97. package/dist/hooks/useWindowSize.js +79 -0
  98. package/dist/index.d.ts +6 -0
  99. package/dist/index.d.ts.map +1 -0
  100. package/dist/index.js +17 -0
  101. package/dist/mock/form.d.ts +41 -0
  102. package/dist/mock/form.d.ts.map +1 -0
  103. package/dist/mock/form.js +195 -0
  104. package/dist/mock/generators.d.ts +112 -0
  105. package/dist/mock/generators.d.ts.map +1 -0
  106. package/dist/mock/generators.js +195 -0
  107. package/dist/mock/index.d.ts +8 -0
  108. package/dist/mock/index.d.ts.map +1 -0
  109. package/dist/mock/index.js +9 -0
  110. package/dist/number/format.d.ts +116 -0
  111. package/dist/number/format.d.ts.map +1 -0
  112. package/dist/number/format.js +165 -0
  113. package/dist/number/index.d.ts +7 -0
  114. package/dist/number/index.d.ts.map +1 -0
  115. package/dist/number/index.js +7 -0
  116. package/dist/string/__tests__/case.test.d.ts +2 -0
  117. package/dist/string/__tests__/case.test.d.ts.map +1 -0
  118. package/dist/string/__tests__/case.test.js +61 -0
  119. package/dist/string/__tests__/manipulation.test.d.ts +2 -0
  120. package/dist/string/__tests__/manipulation.test.d.ts.map +1 -0
  121. package/dist/string/__tests__/manipulation.test.js +109 -0
  122. package/dist/string/__tests__/validation.test.d.ts +2 -0
  123. package/dist/string/__tests__/validation.test.d.ts.map +1 -0
  124. package/dist/string/__tests__/validation.test.js +101 -0
  125. package/dist/string/case.d.ts +42 -0
  126. package/dist/string/case.d.ts.map +1 -0
  127. package/dist/string/case.js +71 -0
  128. package/dist/string/index.d.ts +9 -0
  129. package/dist/string/index.d.ts.map +1 -0
  130. package/dist/string/index.js +11 -0
  131. package/dist/string/manipulation.d.ts +61 -0
  132. package/dist/string/manipulation.d.ts.map +1 -0
  133. package/dist/string/manipulation.js +106 -0
  134. package/dist/string/validation.d.ts +79 -0
  135. package/dist/string/validation.d.ts.map +1 -0
  136. package/dist/string/validation.js +115 -0
  137. package/package.json +86 -0
@@ -0,0 +1,42 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { hasFormErrors, getChangedFields, removeEmptyValues, } from '../helpers';
3
+ describe('Form State Helpers', () => {
4
+ describe('hasFormErrors', () => {
5
+ it('should detect errors', () => {
6
+ expect(hasFormErrors({ email: 'error' })).toBe(true);
7
+ expect(hasFormErrors({})).toBe(false);
8
+ });
9
+ });
10
+ describe('getChangedFields', () => {
11
+ it('should return only changed fields', () => {
12
+ const original = { name: 'John', email: 'john@example.com', age: 30 };
13
+ const current = { name: 'Jane', email: 'john@example.com', age: 31 };
14
+ const changed = getChangedFields(original, current);
15
+ expect(changed).toEqual({ name: 'Jane', age: 31 });
16
+ });
17
+ it('should return empty object when nothing changed', () => {
18
+ const original = { name: 'John' };
19
+ const current = { name: 'John' };
20
+ expect(getChangedFields(original, current)).toEqual({});
21
+ });
22
+ });
23
+ describe('removeEmptyValues', () => {
24
+ it('should remove null, undefined, and empty strings', () => {
25
+ const input = {
26
+ name: 'John',
27
+ email: '',
28
+ age: null,
29
+ phone: undefined,
30
+ address: 'Seoul',
31
+ };
32
+ expect(removeEmptyValues(input)).toEqual({
33
+ name: 'John',
34
+ address: 'Seoul',
35
+ });
36
+ });
37
+ it('should keep zero values', () => {
38
+ const input = { count: 0, active: false };
39
+ expect(removeEmptyValues(input)).toEqual({ count: 0, active: false });
40
+ });
41
+ });
42
+ });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=validation.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.test.d.ts","sourceRoot":"","sources":["../../../src/form/__tests__/validation.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,67 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { isEmail, isPhoneNumber, isUrl, isStrongPassword, isBusinessNumber, } from '../validation';
3
+ describe('Form Validation', () => {
4
+ describe('isEmail', () => {
5
+ it('should validate correct email formats', () => {
6
+ expect(isEmail('test@example.com')).toBe(true);
7
+ expect(isEmail('user.name@domain.co.kr')).toBe(true);
8
+ expect(isEmail('test+tag@example.com')).toBe(true);
9
+ });
10
+ it('should reject invalid email formats', () => {
11
+ expect(isEmail('invalid')).toBe(false);
12
+ expect(isEmail('test@')).toBe(false);
13
+ expect(isEmail('@example.com')).toBe(false);
14
+ expect(isEmail('test @example.com')).toBe(false);
15
+ });
16
+ });
17
+ describe('isPhoneNumber', () => {
18
+ it('should validate Korean phone numbers', () => {
19
+ expect(isPhoneNumber('010-1234-5678')).toBe(true);
20
+ expect(isPhoneNumber('01012345678')).toBe(true);
21
+ expect(isPhoneNumber('02-1234-5678')).toBe(true);
22
+ expect(isPhoneNumber('031-123-4567')).toBe(true);
23
+ });
24
+ it('should reject invalid phone numbers', () => {
25
+ expect(isPhoneNumber('123-456-7890')).toBe(false);
26
+ expect(isPhoneNumber('010-12-3456')).toBe(false);
27
+ });
28
+ });
29
+ describe('isUrl', () => {
30
+ it('should validate URLs', () => {
31
+ expect(isUrl('https://example.com')).toBe(true);
32
+ expect(isUrl('http://test.co.kr')).toBe(true);
33
+ expect(isUrl('https://example.com/path?query=1')).toBe(true);
34
+ });
35
+ it('should reject invalid URLs', () => {
36
+ expect(isUrl('not-a-url')).toBe(false);
37
+ expect(isUrl('example.com')).toBe(false);
38
+ });
39
+ });
40
+ describe('isStrongPassword', () => {
41
+ it('should validate strong passwords', () => {
42
+ expect(isStrongPassword('Password123!')).toBe(true);
43
+ expect(isStrongPassword('Str0ng#Pass')).toBe(true);
44
+ });
45
+ it('should reject weak passwords', () => {
46
+ expect(isStrongPassword('short')).toBe(false);
47
+ expect(isStrongPassword('NoNumbers!')).toBe(false);
48
+ expect(isStrongPassword('nouppercas3!')).toBe(false);
49
+ expect(isStrongPassword('NOLOWERCASE1!')).toBe(false);
50
+ expect(isStrongPassword('NoSpecialChar1')).toBe(false);
51
+ });
52
+ it('should respect custom options', () => {
53
+ expect(isStrongPassword('simple', { minLength: 6, requireUppercase: false, requireNumbers: false, requireSpecialChars: false })).toBe(true);
54
+ expect(isStrongPassword('PASSWORD', { requireLowercase: false, requireNumbers: false, requireSpecialChars: false })).toBe(true);
55
+ });
56
+ });
57
+ describe('isBusinessNumber', () => {
58
+ it('should validate 10-digit business numbers', () => {
59
+ expect(isBusinessNumber('1234567890')).toBe(true);
60
+ expect(isBusinessNumber('123-45-67890')).toBe(true);
61
+ });
62
+ it('should reject invalid business numbers', () => {
63
+ expect(isBusinessNumber('123456789')).toBe(false);
64
+ expect(isBusinessNumber('12345678901')).toBe(false);
65
+ });
66
+ });
67
+ });
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Form Formatter Utilities
3
+ */
4
+ /**
5
+ * 전화번호 포맷팅 (010-1234-5678)
6
+ */
7
+ export declare function formatPhoneNumber(value: string): string;
8
+ /**
9
+ * 사업자등록번호 포맷팅 (123-45-67890)
10
+ */
11
+ export declare function formatBusinessNumber(value: string): string;
12
+ /**
13
+ * 신용카드 번호 포맷팅 (1234-5678-9012-3456)
14
+ */
15
+ export declare function formatCreditCard(value: string): string;
16
+ /**
17
+ * 숫자만 추출
18
+ */
19
+ export declare function extractNumbers(value: string): string;
20
+ /**
21
+ * 통화 포맷팅 (천 단위 콤마)
22
+ * @param value - 숫자 값
23
+ * @param currency - 통화 기호 (기본값: '원')
24
+ */
25
+ export declare function formatCurrency(value: number | string, currency?: string): string;
26
+ /**
27
+ * 주민등록번호 앞자리만 표시 (123456-*******)
28
+ */
29
+ export declare function maskResidentNumber(value: string): string;
30
+ /**
31
+ * 카드번호 마스킹 (1234-****-****-5678)
32
+ */
33
+ export declare function maskCreditCard(value: string): string;
34
+ //# sourceMappingURL=formatter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatter.d.ts","sourceRoot":"","sources":["../../src/form/formatter.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAYvD;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAY1D;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAItD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,QAAQ,GAAE,MAAY,GAAG,MAAM,CAKrF;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKxD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKpD"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Form Formatter Utilities
3
+ */
4
+ /**
5
+ * 전화번호 포맷팅 (010-1234-5678)
6
+ */
7
+ export function formatPhoneNumber(value) {
8
+ const cleaned = value.replace(/[^0-9]/g, '');
9
+ if (cleaned.length <= 3)
10
+ return cleaned;
11
+ if (cleaned.length <= 7) {
12
+ return `${cleaned.slice(0, 3)}-${cleaned.slice(3)}`;
13
+ }
14
+ if (cleaned.length <= 11) {
15
+ return `${cleaned.slice(0, 3)}-${cleaned.slice(3, 7)}-${cleaned.slice(7)}`;
16
+ }
17
+ return `${cleaned.slice(0, 3)}-${cleaned.slice(3, 7)}-${cleaned.slice(7, 11)}`;
18
+ }
19
+ /**
20
+ * 사업자등록번호 포맷팅 (123-45-67890)
21
+ */
22
+ export function formatBusinessNumber(value) {
23
+ const cleaned = value.replace(/[^0-9]/g, '');
24
+ if (cleaned.length <= 3)
25
+ return cleaned;
26
+ if (cleaned.length <= 5) {
27
+ return `${cleaned.slice(0, 3)}-${cleaned.slice(3)}`;
28
+ }
29
+ if (cleaned.length <= 10) {
30
+ return `${cleaned.slice(0, 3)}-${cleaned.slice(3, 5)}-${cleaned.slice(5)}`;
31
+ }
32
+ return `${cleaned.slice(0, 3)}-${cleaned.slice(3, 5)}-${cleaned.slice(5, 10)}`;
33
+ }
34
+ /**
35
+ * 신용카드 번호 포맷팅 (1234-5678-9012-3456)
36
+ */
37
+ export function formatCreditCard(value) {
38
+ const cleaned = value.replace(/[^0-9]/g, '');
39
+ const groups = cleaned.match(/.{1,4}/g);
40
+ return groups ? groups.join('-') : cleaned;
41
+ }
42
+ /**
43
+ * 숫자만 추출
44
+ */
45
+ export function extractNumbers(value) {
46
+ return value.replace(/[^0-9]/g, '');
47
+ }
48
+ /**
49
+ * 통화 포맷팅 (천 단위 콤마)
50
+ * @param value - 숫자 값
51
+ * @param currency - 통화 기호 (기본값: '원')
52
+ */
53
+ export function formatCurrency(value, currency = '원') {
54
+ const num = typeof value === 'string' ? parseFloat(value) : value;
55
+ if (isNaN(num))
56
+ return '0' + currency;
57
+ return num.toLocaleString('ko-KR') + currency;
58
+ }
59
+ /**
60
+ * 주민등록번호 앞자리만 표시 (123456-*******)
61
+ */
62
+ export function maskResidentNumber(value) {
63
+ const cleaned = value.replace(/[^0-9]/g, '');
64
+ if (cleaned.length < 6)
65
+ return cleaned;
66
+ return `${cleaned.slice(0, 6)}-${'*'.repeat(7)}`;
67
+ }
68
+ /**
69
+ * 카드번호 마스킹 (1234-****-****-5678)
70
+ */
71
+ export function maskCreditCard(value) {
72
+ const cleaned = value.replace(/[^0-9]/g, '');
73
+ if (cleaned.length < 12)
74
+ return value;
75
+ return `${cleaned.slice(0, 4)}-****-****-${cleaned.slice(-4)}`;
76
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Form State Helpers
3
+ */
4
+ /**
5
+ * 폼 에러가 있는지 확인
6
+ */
7
+ export declare function hasFormErrors(errors: Record<string, any>): boolean;
8
+ /**
9
+ * 변경된 필드만 추출
10
+ */
11
+ export declare function getChangedFields<T extends Record<string, any>>(original: T, current: T): Partial<T>;
12
+ /**
13
+ * 빈 값 제거 (null, undefined, 빈 문자열)
14
+ */
15
+ export declare function removeEmptyValues<T extends Record<string, any>>(obj: T): Partial<T>;
16
+ //# sourceMappingURL=helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/form/helpers.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,OAAO,CAElE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC5D,QAAQ,EAAE,CAAC,EACX,OAAO,EAAE,CAAC,GACT,OAAO,CAAC,CAAC,CAAC,CAUZ;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAWnF"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Form State Helpers
3
+ */
4
+ /**
5
+ * 폼 에러가 있는지 확인
6
+ */
7
+ export function hasFormErrors(errors) {
8
+ return Object.keys(errors).length > 0;
9
+ }
10
+ /**
11
+ * 변경된 필드만 추출
12
+ */
13
+ export function getChangedFields(original, current) {
14
+ const changed = {};
15
+ for (const key in current) {
16
+ if (current[key] !== original[key]) {
17
+ changed[key] = current[key];
18
+ }
19
+ }
20
+ return changed;
21
+ }
22
+ /**
23
+ * 빈 값 제거 (null, undefined, 빈 문자열)
24
+ */
25
+ export function removeEmptyValues(obj) {
26
+ const result = {};
27
+ for (const key in obj) {
28
+ const value = obj[key];
29
+ if (value !== null && value !== undefined && value !== '') {
30
+ result[key] = value;
31
+ }
32
+ }
33
+ return result;
34
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Form Utilities
3
+ *
4
+ * This module provides utilities for form validation, formatting, and state management.
5
+ */
6
+ export * from './validation';
7
+ export * from './formatter';
8
+ export * from './helpers';
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/form/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,cAAc,cAAc,CAAC;AAG7B,cAAc,aAAa,CAAC;AAG5B,cAAc,WAAW,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Form Utilities
3
+ *
4
+ * This module provides utilities for form validation, formatting, and state management.
5
+ */
6
+ // Validation utilities
7
+ export * from './validation';
8
+ // Formatter utilities
9
+ export * from './formatter';
10
+ // Helper utilities
11
+ export * from './helpers';
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Form Validation Utilities
3
+ */
4
+ /**
5
+ * 이메일 형식 검증
6
+ */
7
+ export declare function isEmail(value: string): boolean;
8
+ /**
9
+ * 한국 전화번호 형식 검증
10
+ * 010-1234-5678, 01012345678, 02-1234-5678 등 허용
11
+ */
12
+ export declare function isPhoneNumber(value: string): boolean;
13
+ /**
14
+ * URL 형식 검증
15
+ */
16
+ export declare function isUrl(value: string): boolean;
17
+ /**
18
+ * 비밀번호 강도 검증
19
+ * @param value - 검증할 비밀번호
20
+ * @param options - 검증 옵션
21
+ */
22
+ export declare function isStrongPassword(value: string, options?: {
23
+ minLength?: number;
24
+ requireUppercase?: boolean;
25
+ requireLowercase?: boolean;
26
+ requireNumbers?: boolean;
27
+ requireSpecialChars?: boolean;
28
+ }): boolean;
29
+ /**
30
+ * 한국 사업자등록번호 형식 검증 (10자리)
31
+ */
32
+ export declare function isBusinessNumber(value: string): boolean;
33
+ //# sourceMappingURL=validation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/form/validation.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAG9C;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAGpD;AAED;;GAEG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAO5C;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,MAAM,EACb,OAAO,GAAE;IACP,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC1B,GACL,OAAO,CAgBT;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAGvD"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Form Validation Utilities
3
+ */
4
+ /**
5
+ * 이메일 형식 검증
6
+ */
7
+ export function isEmail(value) {
8
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
9
+ return emailRegex.test(value);
10
+ }
11
+ /**
12
+ * 한국 전화번호 형식 검증
13
+ * 010-1234-5678, 01012345678, 02-1234-5678 등 허용
14
+ */
15
+ export function isPhoneNumber(value) {
16
+ const phoneRegex = /^(01[016789]|02|0[3-9]{1}[0-9]{1})-?[0-9]{3,4}-?[0-9]{4}$/;
17
+ return phoneRegex.test(value.replace(/\s/g, ''));
18
+ }
19
+ /**
20
+ * URL 형식 검증
21
+ */
22
+ export function isUrl(value) {
23
+ try {
24
+ new URL(value);
25
+ return true;
26
+ }
27
+ catch {
28
+ return false;
29
+ }
30
+ }
31
+ /**
32
+ * 비밀번호 강도 검증
33
+ * @param value - 검증할 비밀번호
34
+ * @param options - 검증 옵션
35
+ */
36
+ export function isStrongPassword(value, options = {}) {
37
+ const { minLength = 8, requireUppercase = true, requireLowercase = true, requireNumbers = true, requireSpecialChars = true, } = options;
38
+ if (value.length < minLength)
39
+ return false;
40
+ if (requireUppercase && !/[A-Z]/.test(value))
41
+ return false;
42
+ if (requireLowercase && !/[a-z]/.test(value))
43
+ return false;
44
+ if (requireNumbers && !/[0-9]/.test(value))
45
+ return false;
46
+ if (requireSpecialChars && !/[!@#$%^&*(),.?":{}|<>]/.test(value))
47
+ return false;
48
+ return true;
49
+ }
50
+ /**
51
+ * 한국 사업자등록번호 형식 검증 (10자리)
52
+ */
53
+ export function isBusinessNumber(value) {
54
+ const cleaned = value.replace(/[^0-9]/g, '');
55
+ return cleaned.length === 10;
56
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * React Hooks
3
+ *
4
+ * This module provides React hooks for common use cases.
5
+ * Note: Requires React as a peer dependency.
6
+ */
7
+ export * from './useLocalStorage';
8
+ export * from './useSessionStorage';
9
+ export * from './useMediaQuery';
10
+ export * from './useClickOutside';
11
+ export * from './useDebounce';
12
+ export * from './useToggle';
13
+ export * from './useCopyToClipboard';
14
+ export * from './useWindowSize';
15
+ export * from './usePrevious';
16
+ export * from './useThrottle';
17
+ export * from './useIntersectionObserver';
18
+ export * from './useEventListener';
19
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AAGpC,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAGlC,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,sBAAsB,CAAC;AACrC,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAG9B,cAAc,eAAe,CAAC;AAC9B,cAAc,2BAA2B,CAAC;AAG1C,cAAc,oBAAoB,CAAC"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * React Hooks
3
+ *
4
+ * This module provides React hooks for common use cases.
5
+ * Note: Requires React as a peer dependency.
6
+ */
7
+ // Storage hooks
8
+ export * from './useLocalStorage';
9
+ export * from './useSessionStorage';
10
+ // UI/UX hooks
11
+ export * from './useMediaQuery';
12
+ export * from './useClickOutside';
13
+ // Utility hooks
14
+ export * from './useDebounce';
15
+ export * from './useToggle';
16
+ export * from './useCopyToClipboard';
17
+ export * from './useWindowSize';
18
+ export * from './usePrevious';
19
+ // Performance hooks
20
+ export * from './useThrottle';
21
+ export * from './useIntersectionObserver';
22
+ // Event hooks
23
+ export * from './useEventListener';
@@ -0,0 +1,49 @@
1
+ import { RefObject } from 'react';
2
+ /**
3
+ * 요소 외부 클릭을 감지하는 hook
4
+ *
5
+ * @param ref - 외부 클릭을 감지할 요소의 ref
6
+ * @param handler - 외부 클릭 시 실행할 콜백 함수
7
+ * @param enabled - hook 활성화 여부 (기본값: true)
8
+ *
9
+ * @example
10
+ * function Dropdown() {
11
+ * const [isOpen, setIsOpen] = useState(false);
12
+ * const dropdownRef = useRef<HTMLDivElement>(null);
13
+ *
14
+ * useClickOutside(dropdownRef, () => setIsOpen(false));
15
+ *
16
+ * return (
17
+ * <div ref={dropdownRef}>
18
+ * <button onClick={() => setIsOpen(!isOpen)}>Toggle</button>
19
+ * {isOpen && <div>Dropdown Content</div>}
20
+ * </div>
21
+ * );
22
+ * }
23
+ *
24
+ * @example
25
+ * // 조건부 활성화
26
+ * useClickOutside(modalRef, handleClose, isModalOpen);
27
+ */
28
+ export declare function useClickOutside<T extends HTMLElement = HTMLElement>(ref: RefObject<T>, handler: (event: MouseEvent | TouchEvent) => void, enabled?: boolean): void;
29
+ /**
30
+ * 여러 요소의 외부 클릭을 감지하는 hook
31
+ *
32
+ * @param refs - 외부 클릭을 감지할 요소들의 ref 배열
33
+ * @param handler - 외부 클릭 시 실행할 콜백 함수
34
+ * @param enabled - hook 활성화 여부 (기본값: true)
35
+ *
36
+ * @example
37
+ * function Modal() {
38
+ * const modalRef = useRef<HTMLDivElement>(null);
39
+ * const triggerRef = useRef<HTMLButtonElement>(null);
40
+ *
41
+ * // 모달과 트리거 버튼 외부 클릭 시 닫기
42
+ * useClickOutsideMultiple(
43
+ * [modalRef, triggerRef],
44
+ * () => setIsOpen(false)
45
+ * );
46
+ * }
47
+ */
48
+ export declare function useClickOutsideMultiple<T extends HTMLElement = HTMLElement>(refs: RefObject<T>[], handler: (event: MouseEvent | TouchEvent) => void, enabled?: boolean): void;
49
+ //# sourceMappingURL=useClickOutside.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useClickOutside.d.ts","sourceRoot":"","sources":["../../src/hooks/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,94 @@
1
+ import { useEffect } from 'react';
2
+ /**
3
+ * 요소 외부 클릭을 감지하는 hook
4
+ *
5
+ * @param ref - 외부 클릭을 감지할 요소의 ref
6
+ * @param handler - 외부 클릭 시 실행할 콜백 함수
7
+ * @param enabled - hook 활성화 여부 (기본값: true)
8
+ *
9
+ * @example
10
+ * function Dropdown() {
11
+ * const [isOpen, setIsOpen] = useState(false);
12
+ * const dropdownRef = useRef<HTMLDivElement>(null);
13
+ *
14
+ * useClickOutside(dropdownRef, () => setIsOpen(false));
15
+ *
16
+ * return (
17
+ * <div ref={dropdownRef}>
18
+ * <button onClick={() => setIsOpen(!isOpen)}>Toggle</button>
19
+ * {isOpen && <div>Dropdown Content</div>}
20
+ * </div>
21
+ * );
22
+ * }
23
+ *
24
+ * @example
25
+ * // 조건부 활성화
26
+ * useClickOutside(modalRef, handleClose, isModalOpen);
27
+ */
28
+ export function useClickOutside(ref, handler, enabled = true) {
29
+ useEffect(() => {
30
+ if (!enabled) {
31
+ return;
32
+ }
33
+ const listener = (event) => {
34
+ const element = ref.current;
35
+ // ref가 없거나, 클릭한 요소가 ref 내부인 경우 무시
36
+ if (!element || element.contains(event.target)) {
37
+ return;
38
+ }
39
+ // 외부 클릭 시 handler 실행
40
+ handler(event);
41
+ };
42
+ // mousedown과 touchstart 이벤트 모두 처리 (모바일 지원)
43
+ document.addEventListener('mousedown', listener);
44
+ document.addEventListener('touchstart', listener);
45
+ return () => {
46
+ document.removeEventListener('mousedown', listener);
47
+ document.removeEventListener('touchstart', listener);
48
+ };
49
+ }, [ref, handler, enabled]);
50
+ }
51
+ /**
52
+ * 여러 요소의 외부 클릭을 감지하는 hook
53
+ *
54
+ * @param refs - 외부 클릭을 감지할 요소들의 ref 배열
55
+ * @param handler - 외부 클릭 시 실행할 콜백 함수
56
+ * @param enabled - hook 활성화 여부 (기본값: true)
57
+ *
58
+ * @example
59
+ * function Modal() {
60
+ * const modalRef = useRef<HTMLDivElement>(null);
61
+ * const triggerRef = useRef<HTMLButtonElement>(null);
62
+ *
63
+ * // 모달과 트리거 버튼 외부 클릭 시 닫기
64
+ * useClickOutsideMultiple(
65
+ * [modalRef, triggerRef],
66
+ * () => setIsOpen(false)
67
+ * );
68
+ * }
69
+ */
70
+ export function useClickOutsideMultiple(refs, handler, enabled = true) {
71
+ useEffect(() => {
72
+ if (!enabled) {
73
+ return;
74
+ }
75
+ const listener = (event) => {
76
+ // 모든 ref를 확인하여 하나라도 내부 클릭이면 무시
77
+ const isInside = refs.some((ref) => {
78
+ const element = ref.current;
79
+ return element && element.contains(event.target);
80
+ });
81
+ if (isInside) {
82
+ return;
83
+ }
84
+ // 모든 요소 외부 클릭 시 handler 실행
85
+ handler(event);
86
+ };
87
+ document.addEventListener('mousedown', listener);
88
+ document.addEventListener('touchstart', listener);
89
+ return () => {
90
+ document.removeEventListener('mousedown', listener);
91
+ document.removeEventListener('touchstart', listener);
92
+ };
93
+ }, [refs, handler, enabled]);
94
+ }
@@ -0,0 +1,67 @@
1
+ /**
2
+ * useCopyToClipboard의 반환 타입
3
+ */
4
+ export interface CopyToClipboardResult {
5
+ /** 복사된 값 (null이면 아직 복사 안됨) */
6
+ copiedText: string | null;
7
+ /** 클립보드에 복사하는 함수 */
8
+ copy: (text: string) => Promise<boolean>;
9
+ /** 복사 상태를 초기화하는 함수 */
10
+ reset: () => void;
11
+ }
12
+ /**
13
+ * 클립보드에 텍스트를 복사하는 hook
14
+ *
15
+ * @returns {CopyToClipboardResult} 복사된 텍스트, 복사 함수, 리셋 함수
16
+ *
17
+ * @example
18
+ * // 기본 사용
19
+ * function CopyButton() {
20
+ * const { copiedText, copy } = useCopyToClipboard();
21
+ *
22
+ * const handleCopy = () => {
23
+ * copy('Hello, World!');
24
+ * };
25
+ *
26
+ * return (
27
+ * <button onClick={handleCopy}>
28
+ * {copiedText ? 'Copied!' : 'Copy'}
29
+ * </button>
30
+ * );
31
+ * }
32
+ *
33
+ * @example
34
+ * // 코드 블록 복사
35
+ * function CodeBlock({ code }: { code: string }) {
36
+ * const { copiedText, copy } = useCopyToClipboard();
37
+ * const isCopied = copiedText === code;
38
+ *
39
+ * return (
40
+ * <div>
41
+ * <pre>{code}</pre>
42
+ * <button onClick={() => copy(code)}>
43
+ * {isCopied ? '✓ Copied' : 'Copy Code'}
44
+ * </button>
45
+ * </div>
46
+ * );
47
+ * }
48
+ *
49
+ * @example
50
+ * // 에러 처리
51
+ * function ShareLink({ url }: { url: string }) {
52
+ * const { copy } = useCopyToClipboard();
53
+ *
54
+ * const handleShare = async () => {
55
+ * const success = await copy(url);
56
+ * if (success) {
57
+ * alert('Link copied!');
58
+ * } else {
59
+ * alert('Failed to copy');
60
+ * }
61
+ * };
62
+ *
63
+ * return <button onClick={handleShare}>Share</button>;
64
+ * }
65
+ */
66
+ export declare function useCopyToClipboard(): CopyToClipboardResult;
67
+ //# sourceMappingURL=useCopyToClipboard.d.ts.map