@basiln/utils 0.1.2 → 0.1.4

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/CHANGELOG.md CHANGED
@@ -1,5 +1,43 @@
1
1
  # Change Log
2
2
 
3
+ ## 0.1.4
4
+
5
+ ### Patch Changes
6
+
7
+ - [#42](https://github.com/seedn-corp/basiln-packages-fe/pull/42) [`65918fc`](https://github.com/seedn-corp/basiln-packages-fe/commit/65918fc799f709c78db70b1f1678d51162f1156c) Thanks [@sjgske](https://github.com/sjgske)! - 다양한 데이터를 원하는 형식으로 변환하는 포맷팅 유틸 추가
8
+
9
+ ```tsx
10
+ // 사용 방법
11
+ import { Format } from '@basiln/utils';
12
+
13
+ Format.phone('01012345678'); // '010-1234-5678'
14
+ Format.removeHyphen('010-1234-5678'); // '01012345678'
15
+ Format.commaize('123456'); // '123,456'
16
+ Format.padTime(1); // '01'
17
+ ```
18
+
19
+ - [#29](https://github.com/seedn-corp/basiln-packages-fe/pull/29) [`a96d3db`](https://github.com/seedn-corp/basiln-packages-fe/commit/a96d3dbd39f4740e62aec8acb12b0ddbcb387887) Thanks [@yoonhihi97](https://github.com/yoonhihi97)! - 제공된 함수를 호출하는 것을 지연시키는 debounce된 함수를 생성하는 유틸 추가
20
+
21
+ ```tsx
22
+ // 사용 방법
23
+
24
+ const debouncedFunction = debounce(() => {
25
+ console.log('Function executed');
26
+ }, 1000);
27
+
28
+ //flush - 즉시 요청
29
+ debouncedFunction.flush();
30
+
31
+ //cancel - 요청 취소
32
+ debouncedFunction.cancel();
33
+ ```
34
+
35
+ ## 0.1.3
36
+
37
+ ### Patch Changes
38
+
39
+ - [#30](https://github.com/seedn-corp/basiln-packages-fe/pull/30) [`817db3c`](https://github.com/seedn-corp/basiln-packages-fe/commit/817db3ca75bda217ee720e3406395b06e13427c4) Thanks [@im-binary](https://github.com/im-binary)! - direction 의 기본값 horizontal를 vertical 로 수정
40
+
3
41
  ## 0.1.2
4
42
 
5
43
  ### Patch Changes
package/README.md ADDED
@@ -0,0 +1,324 @@
1
+ # @basiln-utils
2
+
3
+ > 유용한 컴포넌트 및 유틸리티 모음
4
+
5
+ ## 설치
6
+
7
+ ```sh
8
+ yarn add @basiln/utils
9
+ ```
10
+
11
+ - [If](#if)
12
+ - [Choose](#choose)
13
+ - [Flex](#flex)
14
+ - [Validate](#validate)
15
+ - [queryString](#querystring)
16
+ - [hexToRgba](#hextorgba)
17
+ - [SafeArea](#safearea)
18
+ - [Spacing](#spacing)
19
+ - [ellipsis 및 multiLineEllipsis](#ellipsis-및-multilineellipsis)
20
+ - [Josa](#josa)
21
+ - [createContext](#createcontext)
22
+ - [debounce](#debounce)
23
+ - [composeEventHandlers](#composeeventhandlers)
24
+ - [getVar](#getvar)
25
+ - [Format](#format)
26
+
27
+ ### `If`
28
+
29
+ 조건에 따라 자식 요소를 렌더링하는 컴포넌트입니다. `condition` 속성이 `true`일 때만 자식 요소를 렌더링합니다.
30
+
31
+ ```tsx
32
+ import { If } from '@basiln/utils';
33
+
34
+ <If condition={true}>
35
+ <p>조건이 참일 때만 렌더링됩니다.</p>
36
+ </If>;
37
+ ```
38
+
39
+ `condition`이 `false`일 경우에도 자식 요소를 평가하지 않으려면 `render` 속성을 사용하세요.
40
+
41
+ ```tsx
42
+ <If condition={false} render={() => <p>이 내용은 조건에 따라 평가됩니다.</p>} />
43
+ ```
44
+
45
+ ---
46
+
47
+ ### `Choose`
48
+
49
+ `switch-case`와 유사하게 조건에 따라 자식 요소를 렌더링하는 컴포넌트입니다. `Choose`에는 두 가지 하위 컴포넌트가 있습니다:
50
+
51
+ - `Choose.When`: `condition`이 `true`일 때 자식 요소를 렌더링합니다.
52
+ - `Choose.Otherwise`: `Choose.When` 조건이 모두 `false`일 때 렌더링됩니다.
53
+
54
+ ```tsx
55
+ import { Choose } from '@basiln/utils';
56
+
57
+ <Choose>
58
+ <Choose.When condition={true}>
59
+ <p>첫 번째 조건이 참일 때 렌더링됩니다.</p>
60
+ </Choose.When>
61
+ <Choose.When condition={false}>
62
+ <p>이 내용은 렌더링되지 않습니다.</p>
63
+ </Choose.When>
64
+ <Choose.Otherwise>
65
+ <p>모든 조건이 거짓일 때 렌더링됩니다.</p>
66
+ </Choose.Otherwise>
67
+ </Choose>;
68
+ ```
69
+
70
+ ---
71
+
72
+ ### `Flex`
73
+
74
+ 선언적으로 `flex box` 스타일링을 할 수 있는 컴포넌트입니다.
75
+
76
+ ```tsx
77
+ import { Flex } from '@basiln/utils';
78
+
79
+ <Flex justify="space-between" align="center" gap={20}>
80
+ <div>Left</div>
81
+ <div>Right</div>
82
+ </Flex>
83
+ <Flex gap='10%'>
84
+ <div>Left</div>
85
+ <div>Right</div>
86
+ </Flex>
87
+ ```
88
+
89
+ ---
90
+
91
+ ### `Validate`
92
+
93
+ 정규식을 사용해 입력값을 검증할 수 있는 유틸리티입니다.
94
+
95
+ ```tsx
96
+ import { Validate } from '@basiln/utils';
97
+
98
+ Validate.email('example@domain.com'); // true
99
+ Validate.phoneNumber('010-1234-5678'); // true
100
+ ```
101
+
102
+ ---
103
+
104
+ ### `queryString`
105
+
106
+ URL의 쿼리 문자열을 생성, 파싱, 조회, 수정할 수 있는 유틸리티입니다.
107
+
108
+ ```ts
109
+ import { queryString } from '@basiln/utils';
110
+
111
+ // 쿼리 문자열 생성
112
+ queryString.create({ a: '1', b: '2' }); // ?a=1&b=2
113
+
114
+ // 쿼리 문자열 파싱
115
+ queryString.parse('?a=1&b=2'); // { a: '1', b: '2' }
116
+
117
+ // 특정 키의 값 조회
118
+ queryString.get('a'); // '1'
119
+
120
+ // 특정 키의 값 수정
121
+ queryString.set({ qs: '?a=1', key: 'b', value: '2' }); // '?a=1&b=2'
122
+ ```
123
+
124
+ ---
125
+
126
+ ### `hexToRgba`
127
+
128
+ 16진수 컬러 코드를 `rgba()` 표기로 변환하는 유틸리티입니다.
129
+
130
+ ```tsx
131
+ import { hexToRgba } from '@basiln/utils';
132
+
133
+ hexToRgba({ hex: '#000000', alpha: 0.5 }); // 'rgba(0, 0, 0, 0.5)'
134
+ ```
135
+
136
+ ---
137
+
138
+ ### `SafeArea`
139
+
140
+ 웹뷰 환경에서 안전 영역(Safe Area)을 선언적으로 사용할 수 있는 컴포넌트입니다.
141
+
142
+ ```tsx
143
+ import { SafeArea, useSafeArea } from '@basiln/utils';
144
+
145
+ // 컴포넌트로 사용
146
+ <SafeArea>
147
+ <p>안녕하세요</p>
148
+ </SafeArea>;
149
+
150
+ // 유틸리티로 사용
151
+ const { top, bottom } = useSafeArea();
152
+ ```
153
+
154
+ ---
155
+
156
+ ### `Spacing`
157
+
158
+ 요소 간 간격을 선언적으로 설정할 수 있는 컴포넌트입니다.
159
+
160
+ ```tsx
161
+ import { Spacing } from '@basiln/utils';
162
+
163
+ <Spacing size={30} />;
164
+ <Spacing size="2rem" direction="horizontal" />;
165
+ ```
166
+
167
+ ---
168
+
169
+ ### `ellipsis` 및 `multiLineEllipsis`
170
+
171
+ 텍스트가 일정한 길이를 초과할 경우 생략 표시를 적용하는 유틸리티입니다.
172
+
173
+ ```tsx
174
+ import { ellipsis, multiLineEllipsis } from '@basiln/utils';
175
+
176
+ // 단일 줄 텍스트 생략
177
+ <p css={ellipsis}>긴 텍스트</p>;
178
+
179
+ // 다중 줄 텍스트 생략
180
+ <p css={multiLineEllipsis({ line: 3 })}>긴 텍스트</p>;
181
+ ```
182
+
183
+ ---
184
+
185
+ ### `Josa`
186
+
187
+ 한국어 문장에서 적절한 조사를 반환하는 유틸리티입니다.
188
+
189
+ ```tsx
190
+ import { josa } from '@basiln/utils';
191
+
192
+ josa({ josa: '을/를', word: '망곰이' }); // 망곰이를
193
+ josa.pick({ josa: '은/는', word: '하츄핑' }); // 은
194
+ ```
195
+
196
+ ---
197
+
198
+ ### `createContext`
199
+
200
+ React의 `Context`를 보다 선언적으로 생성하고 사용할 수 있는 유틸리티입니다.
201
+
202
+ #### 사용법
203
+
204
+ ```tsx
205
+ import { createContext } from '@basiln/utils';
206
+
207
+ const [MyProvider, useMyContext] = createContext<{ value: string }>(
208
+ 'MyComponent'
209
+ );
210
+
211
+ function App() {
212
+ return (
213
+ <MyProvider value="Hello World">
214
+ <Child />
215
+ </MyProvider>
216
+ );
217
+ }
218
+
219
+ function Child() {
220
+ const context = useMyContext('Child');
221
+ return <div>{context.value}</div>;
222
+ }
223
+ ```
224
+
225
+ ---
226
+
227
+ ### `debounce`
228
+
229
+ 지정된 시간(ms) 동안 연속적으로 호출된 함수 실행을 지연시키는 유틸리티입니다.
230
+
231
+ 일반적으로 연속된 사용자 입력 처리 시 사용됩니다.
232
+
233
+ #### 사용법
234
+
235
+ ```tsx
236
+ import { debounce } from '@basiln/utils';
237
+
238
+ const debouncedLog = debounce(() => {
239
+ console.log('Debounced Function Called');
240
+ }, 1000);
241
+
242
+ function App() {
243
+ const handleClick = () => {
244
+ debouncedLog();
245
+ };
246
+
247
+ return <button onClick={handleClick}>Click me</button>;
248
+ }
249
+
250
+ // 추가 메서드
251
+ debouncedLog.cancel(); // 예약된 호출 취소
252
+ debouncedLog.flush(); // 예약된 호출 즉시 실행
253
+ ```
254
+
255
+ ---
256
+
257
+ ### `composeEventHandlers`
258
+
259
+ 두 개의 이벤트 핸들러를 결합하여 하나의 핸들러로 만드는 유틸리티입니다.
260
+
261
+ 첫 번째 핸들러가 `defaultPrevented`를 호출하면 두 번째 핸들러는 실행되지 않습니다.
262
+
263
+ #### 사용법
264
+
265
+ ```tsx
266
+ import { composeEventHandlers } from '@basiln/utils';
267
+
268
+ function App() {
269
+ const onClickFirst = (event: React.MouseEvent) => {
270
+ console.log('First Handler');
271
+ };
272
+
273
+ const onClickSecond = (event: React.MouseEvent) => {
274
+ console.log('Second Handler');
275
+ };
276
+
277
+ const combinedHandler = composeEventHandlers(onClickFirst, onClickSecond);
278
+
279
+ return <button onClick={combinedHandler}>Click Me</button>;
280
+ }
281
+ ```
282
+
283
+ ---
284
+
285
+ ### `getVar`
286
+
287
+ CSS 변수(`--var`)를 읽거나, 기본값을 지정하여 읽는 유틸리티입니다.
288
+
289
+ #### 사용법
290
+
291
+ ```tsx
292
+ import { getVar } from '@basiln/utils';
293
+
294
+ const primaryColor = getVar('--primary-color', '#000');
295
+
296
+ function App() {
297
+ return <div style={{ color: primaryColor }}>Hello</div>;
298
+ }
299
+ ```
300
+
301
+ - `getVar('--variable')`: 지정된 변수 값을 읽습니다.
302
+ - `getVar('--variable', 'default')`: 변수가 정의되지 않았을 경우 기본값을 반환합니다.
303
+
304
+ ```css
305
+ :root {
306
+ --primary-color: #ff5722;
307
+ }
308
+ ```
309
+
310
+ ---
311
+
312
+ ### `Format`
313
+
314
+ 다양한 데이터를 원하는 형식으로 변환하는 포맷팅 유틸리티입니다.
315
+
316
+ #### 사용법
317
+
318
+ ```tsx
319
+ import { Format } from '@basiln/utils';
320
+
321
+ Format.phone('01012345678'); // '010-1234-5678'
322
+ Format.commaize('123456'); // '123,456'
323
+ Format.padTime(1); // '01'
324
+ ```
package/dist/Format.js ADDED
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/Format.ts
21
+ var Format_exports = {};
22
+ __export(Format_exports, {
23
+ Format: () => Format
24
+ });
25
+ module.exports = __toCommonJS(Format_exports);
26
+ var Format = {
27
+ phone: formatPhoneNumber,
28
+ removeHyphen,
29
+ commaize: formatCommaizeNumber,
30
+ padTime
31
+ };
32
+ function formatPhoneNumber(phoneNumber) {
33
+ return phoneNumber.replace(/[^0-9]/g, "").replace(/^(\d{0,3})(\d{0,4})(\d{0,4})$/g, "$1-$2-$3").replace(/(-{1,2})$/g, "");
34
+ }
35
+ function removeHyphen(value) {
36
+ return value.replaceAll("-", "");
37
+ }
38
+ function formatCommaizeNumber(value) {
39
+ const numStr = String(value);
40
+ const decimalPointIndex = numStr.indexOf(".");
41
+ const commaizeRegExp = /(\d)(?=(\d\d\d)+(?!\d))/g;
42
+ return decimalPointIndex > -1 ? numStr.slice(0, decimalPointIndex).replace(commaizeRegExp, "$1,") + numStr.slice(decimalPointIndex) : numStr.replace(commaizeRegExp, "$1,");
43
+ }
44
+ function padTime(value) {
45
+ return String(value).padStart(2, "0");
46
+ }
47
+ // Annotate the CommonJS export names for ESM import in node:
48
+ 0 && (module.exports = {
49
+ Format
50
+ });
51
+ //# sourceMappingURL=Format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/Format.ts"],"sourcesContent":["type Value = number | string;\n\nexport const Format = {\n phone: formatPhoneNumber,\n removeHyphen,\n commaize: formatCommaizeNumber,\n padTime,\n};\n\n/**\n * 숫자를 전화번호 형식으로 변환합니다.\n * @example Format.phone('01012345678') // '010-1234-5678'\n */\nfunction formatPhoneNumber(phoneNumber: string) {\n return phoneNumber\n .replace(/[^0-9]/g, '')\n .replace(/^(\\d{0,3})(\\d{0,4})(\\d{0,4})$/g, '$1-$2-$3')\n .replace(/(-{1,2})$/g, '');\n}\n\n/**\n * 하이픈을 제거합니다.\n * @example Format.removeHyphen('01012345678') // '01012345678'\n */\nfunction removeHyphen(value: string) {\n return value.replaceAll('-', '');\n}\n\n/**\n * 숫자를 콤마로 구분합니다.\n * https://www.slash.page/ko/libraries/common/utils/src/Numbers_commaizeNumber.i18n\n *\n * @example\n * Format.commaize('123456') // '123,456'\n * Format.commaize(123456) // '123,456'\n */\nfunction formatCommaizeNumber(value: Value) {\n const numStr = String(value);\n const decimalPointIndex = numStr.indexOf('.');\n const commaizeRegExp = /(\\d)(?=(\\d\\d\\d)+(?!\\d))/g;\n\n return decimalPointIndex > -1\n ? numStr.slice(0, decimalPointIndex).replace(commaizeRegExp, '$1,') +\n numStr.slice(decimalPointIndex)\n : numStr.replace(commaizeRegExp, '$1,');\n}\n\n/**\n * 숫자를 2자리 수 형태로 변환합니다.\n * @example Format.padTime(9) // '09'\n */\nfunction padTime(value: Value) {\n return String(value).padStart(2, '0');\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAEO,IAAM,SAAS;AAAA,EACpB,OAAO;AAAA,EACP;AAAA,EACA,UAAU;AAAA,EACV;AACF;AAMA,SAAS,kBAAkB,aAAqB;AAC9C,SAAO,YACJ,QAAQ,WAAW,EAAE,EACrB,QAAQ,kCAAkC,UAAU,EACpD,QAAQ,cAAc,EAAE;AAC7B;AAMA,SAAS,aAAa,OAAe;AACnC,SAAO,MAAM,WAAW,KAAK,EAAE;AACjC;AAUA,SAAS,qBAAqB,OAAc;AAC1C,QAAM,SAAS,OAAO,KAAK;AAC3B,QAAM,oBAAoB,OAAO,QAAQ,GAAG;AAC5C,QAAM,iBAAiB;AAEvB,SAAO,oBAAoB,KACvB,OAAO,MAAM,GAAG,iBAAiB,EAAE,QAAQ,gBAAgB,KAAK,IAC9D,OAAO,MAAM,iBAAiB,IAChC,OAAO,QAAQ,gBAAgB,KAAK;AAC1C;AAMA,SAAS,QAAQ,OAAc;AAC7B,SAAO,OAAO,KAAK,EAAE,SAAS,GAAG,GAAG;AACtC;","names":[]}
@@ -0,0 +1,26 @@
1
+ // src/Format.ts
2
+ var Format = {
3
+ phone: formatPhoneNumber,
4
+ removeHyphen,
5
+ commaize: formatCommaizeNumber,
6
+ padTime
7
+ };
8
+ function formatPhoneNumber(phoneNumber) {
9
+ return phoneNumber.replace(/[^0-9]/g, "").replace(/^(\d{0,3})(\d{0,4})(\d{0,4})$/g, "$1-$2-$3").replace(/(-{1,2})$/g, "");
10
+ }
11
+ function removeHyphen(value) {
12
+ return value.replaceAll("-", "");
13
+ }
14
+ function formatCommaizeNumber(value) {
15
+ const numStr = String(value);
16
+ const decimalPointIndex = numStr.indexOf(".");
17
+ const commaizeRegExp = /(\d)(?=(\d\d\d)+(?!\d))/g;
18
+ return decimalPointIndex > -1 ? numStr.slice(0, decimalPointIndex).replace(commaizeRegExp, "$1,") + numStr.slice(decimalPointIndex) : numStr.replace(commaizeRegExp, "$1,");
19
+ }
20
+ function padTime(value) {
21
+ return String(value).padStart(2, "0");
22
+ }
23
+ export {
24
+ Format
25
+ };
26
+ //# sourceMappingURL=Format.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/Format.ts"],"sourcesContent":["type Value = number | string;\n\nexport const Format = {\n phone: formatPhoneNumber,\n removeHyphen,\n commaize: formatCommaizeNumber,\n padTime,\n};\n\n/**\n * 숫자를 전화번호 형식으로 변환합니다.\n * @example Format.phone('01012345678') // '010-1234-5678'\n */\nfunction formatPhoneNumber(phoneNumber: string) {\n return phoneNumber\n .replace(/[^0-9]/g, '')\n .replace(/^(\\d{0,3})(\\d{0,4})(\\d{0,4})$/g, '$1-$2-$3')\n .replace(/(-{1,2})$/g, '');\n}\n\n/**\n * 하이픈을 제거합니다.\n * @example Format.removeHyphen('01012345678') // '01012345678'\n */\nfunction removeHyphen(value: string) {\n return value.replaceAll('-', '');\n}\n\n/**\n * 숫자를 콤마로 구분합니다.\n * https://www.slash.page/ko/libraries/common/utils/src/Numbers_commaizeNumber.i18n\n *\n * @example\n * Format.commaize('123456') // '123,456'\n * Format.commaize(123456) // '123,456'\n */\nfunction formatCommaizeNumber(value: Value) {\n const numStr = String(value);\n const decimalPointIndex = numStr.indexOf('.');\n const commaizeRegExp = /(\\d)(?=(\\d\\d\\d)+(?!\\d))/g;\n\n return decimalPointIndex > -1\n ? numStr.slice(0, decimalPointIndex).replace(commaizeRegExp, '$1,') +\n numStr.slice(decimalPointIndex)\n : numStr.replace(commaizeRegExp, '$1,');\n}\n\n/**\n * 숫자를 2자리 수 형태로 변환합니다.\n * @example Format.padTime(9) // '09'\n */\nfunction padTime(value: Value) {\n return String(value).padStart(2, '0');\n}\n"],"mappings":";AAEO,IAAM,SAAS;AAAA,EACpB,OAAO;AAAA,EACP;AAAA,EACA,UAAU;AAAA,EACV;AACF;AAMA,SAAS,kBAAkB,aAAqB;AAC9C,SAAO,YACJ,QAAQ,WAAW,EAAE,EACrB,QAAQ,kCAAkC,UAAU,EACpD,QAAQ,cAAc,EAAE;AAC7B;AAMA,SAAS,aAAa,OAAe;AACnC,SAAO,MAAM,WAAW,KAAK,EAAE;AACjC;AAUA,SAAS,qBAAqB,OAAc;AAC1C,QAAM,SAAS,OAAO,KAAK;AAC3B,QAAM,oBAAoB,OAAO,QAAQ,GAAG;AAC5C,QAAM,iBAAiB;AAEvB,SAAO,oBAAoB,KACvB,OAAO,MAAM,GAAG,iBAAiB,EAAE,QAAQ,gBAAgB,KAAK,IAC9D,OAAO,MAAM,iBAAiB,IAChC,OAAO,QAAQ,gBAAgB,KAAK;AAC1C;AAMA,SAAS,QAAQ,OAAc;AAC7B,SAAO,OAAO,KAAK,EAAE,SAAS,GAAG,GAAG;AACtC;","names":[]}
package/dist/SafeArea.js CHANGED
@@ -37,7 +37,7 @@ function coerceCssPixelValue(value) {
37
37
  // src/Spacing.tsx
38
38
  var import_jsx_runtime = require("react/jsx-runtime");
39
39
  var Spacing = (0, import_react.memo)(function Spacing2(props) {
40
- const { direction = "horizontal", size, ...restProps } = props;
40
+ const { direction = "vertical", size, ...restProps } = props;
41
41
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SpacingContainer, { $direction: direction, $size: size, ...restProps });
42
42
  });
43
43
  var SpacingContainer = import_styled_components.styled.div`
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/SafeArea.tsx","../src/Spacing.tsx","../src/coerceCssPixelValue.ts","../src/useSafeArea.ts"],"sourcesContent":["import React, {\n memo,\n type ComponentPropsWithoutRef,\n type ReactNode,\n} from 'react';\n\nimport { Spacing } from './Spacing';\nimport { useSafeArea } from './useSafeArea';\n\nexport type SafeAreaProps<T extends React.ElementType = 'div'> = {\n as?: T;\n children: ReactNode;\n} & ComponentPropsWithoutRef<T>;\n\nexport const SafeArea = <T extends React.ElementType = 'div'>({\n as,\n children,\n ...props\n}: SafeAreaProps<T>) => {\n const Component = as || 'div';\n\n return (\n <Component {...props}>\n <SafeAreaTop />\n {children}\n <SafeAreaBottom />\n </Component>\n );\n};\n\nconst SafeAreaTop = memo(function SafeAreaTop(\n props: Omit<ComponentPropsWithoutRef<typeof Spacing>, 'size'>\n) {\n const { top } = useSafeArea();\n return <Spacing {...props} size={top} />;\n});\n\nconst SafeAreaBottom = memo(function SafeAreaBottom(\n props: Omit<ComponentPropsWithoutRef<typeof Spacing>, 'size'>\n) {\n const { bottom } = useSafeArea();\n return <Spacing {...props} size={bottom} />;\n});\n\nSafeArea.Top = SafeAreaTop;\nSafeArea.Bottom = SafeAreaBottom;\n","import { memo, type HTMLAttributes } from 'react';\nimport { styled } from 'styled-components';\n\nimport { coerceCssPixelValue, type CSSPixelValue } from './coerceCssPixelValue';\n\ntype AxisDirection = 'vertical' | 'horizontal';\n\nexport type SpacingProps = Omit<HTMLAttributes<HTMLDivElement>, 'children'> & {\n direction?: AxisDirection;\n size: CSSPixelValue;\n};\n\nexport const Spacing = memo(function Spacing(props: SpacingProps) {\n const { direction = 'horizontal', size, ...restProps } = props;\n\n return (\n <SpacingContainer $direction={direction} $size={size} {...restProps} />\n );\n});\n\nconst SpacingContainer = styled.div<{\n $direction: SpacingProps['direction'];\n $size: SpacingProps['size'];\n}>`\n flex: none;\n width: ${({ $direction, $size }) =>\n $direction === 'horizontal' ? coerceCssPixelValue($size) : undefined};\n height: ${({ $direction, $size }) =>\n $direction === 'vertical' ? coerceCssPixelValue($size) : undefined};\n`;\n","export type CSSPixelValue = string | number;\n\nexport function coerceCssPixelValue(value: CSSPixelValue): string {\n return typeof value === 'string' ? value : `${value}px`;\n}\n","import { coerceCssPixelValue, type CSSPixelValue } from './coerceCssPixelValue';\n\nexport type SafeAreaCssValueProps = {\n top?: CSSPixelValue;\n bottom?: CSSPixelValue;\n left?: CSSPixelValue;\n right?: CSSPixelValue;\n};\n\nconst useSafeArea = ({\n top: T = 0,\n bottom: B = 0,\n left: L = 0,\n right: R = 0,\n}: SafeAreaCssValueProps = {}) => {\n const top = `max(${coerceCssPixelValue(T)}, env(safe-area-inset-top))`;\n const bottom = `max(${coerceCssPixelValue(B)}, env(safe-area-inset-bottom))`;\n const left = `max(${coerceCssPixelValue(L)}, env(safe-area-inset-left))`;\n const right = `max(${coerceCssPixelValue(R)}, env(safe-area-inset-right))`;\n\n return { top, bottom, left, right };\n};\n\nexport { useSafeArea };\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAAA,gBAIO;;;ACJP,mBAA0C;AAC1C,+BAAuB;;;ACChB,SAAS,oBAAoB,OAA8B;AAChE,SAAO,OAAO,UAAU,WAAW,QAAQ,GAAG;AAChD;;;ADYI;AAJG,IAAM,cAAU,mBAAK,SAASC,SAAQ,OAAqB;AAChE,QAAM,EAAE,YAAY,cAAc,MAAM,GAAG,UAAU,IAAI;AAEzD,SACE,4CAAC,oBAAiB,YAAY,WAAW,OAAO,MAAO,GAAG,WAAW;AAEzE,CAAC;AAED,IAAM,mBAAmB,gCAAO;AAAA;AAAA,WAKrB,CAAC,EAAE,YAAY,MAAM,MAC5B,eAAe,eAAe,oBAAoB,KAAK,IAAI;AAAA,YACnD,CAAC,EAAE,YAAY,MAAM,MAC7B,eAAe,aAAa,oBAAoB,KAAK,IAAI;AAAA;;;AEnB7D,IAAM,cAAc,CAAC;AAAA,EACnB,KAAK,IAAI;AAAA,EACT,QAAQ,IAAI;AAAA,EACZ,MAAM,IAAI;AAAA,EACV,OAAO,IAAI;AACb,IAA2B,CAAC,MAAM;AAChC,QAAM,MAAM,OAAO,oBAAoB,CAAC;AACxC,QAAM,SAAS,OAAO,oBAAoB,CAAC;AAC3C,QAAM,OAAO,OAAO,oBAAoB,CAAC;AACzC,QAAM,QAAQ,OAAO,oBAAoB,CAAC;AAE1C,SAAO,EAAE,KAAK,QAAQ,MAAM,MAAM;AACpC;;;AHCI,IAAAC,sBAAA;AARG,IAAM,WAAW,CAAsC;AAAA,EAC5D;AAAA,EACA;AAAA,EACA,GAAG;AACL,MAAwB;AACtB,QAAM,YAAY,MAAM;AAExB,SACE,8CAAC,aAAW,GAAG,OACb;AAAA,iDAAC,eAAY;AAAA,IACZ;AAAA,IACD,6CAAC,kBAAe;AAAA,KAClB;AAEJ;AAEA,IAAM,kBAAc,oBAAK,SAASC,aAChC,OACA;AACA,QAAM,EAAE,IAAI,IAAI,YAAY;AAC5B,SAAO,6CAAC,WAAS,GAAG,OAAO,MAAM,KAAK;AACxC,CAAC;AAED,IAAM,qBAAiB,oBAAK,SAASC,gBACnC,OACA;AACA,QAAM,EAAE,OAAO,IAAI,YAAY;AAC/B,SAAO,6CAAC,WAAS,GAAG,OAAO,MAAM,QAAQ;AAC3C,CAAC;AAED,SAAS,MAAM;AACf,SAAS,SAAS;","names":["import_react","Spacing","import_jsx_runtime","SafeAreaTop","SafeAreaBottom"]}
1
+ {"version":3,"sources":["../src/SafeArea.tsx","../src/Spacing.tsx","../src/coerceCssPixelValue.ts","../src/useSafeArea.ts"],"sourcesContent":["import React, {\n memo,\n type ComponentPropsWithoutRef,\n type ReactNode,\n} from 'react';\n\nimport { Spacing } from './Spacing';\nimport { useSafeArea } from './useSafeArea';\n\nexport type SafeAreaProps<T extends React.ElementType = 'div'> = {\n as?: T;\n children: ReactNode;\n} & ComponentPropsWithoutRef<T>;\n\nexport const SafeArea = <T extends React.ElementType = 'div'>({\n as,\n children,\n ...props\n}: SafeAreaProps<T>) => {\n const Component = as || 'div';\n\n return (\n <Component {...props}>\n <SafeAreaTop />\n {children}\n <SafeAreaBottom />\n </Component>\n );\n};\n\nconst SafeAreaTop = memo(function SafeAreaTop(\n props: Omit<ComponentPropsWithoutRef<typeof Spacing>, 'size'>\n) {\n const { top } = useSafeArea();\n return <Spacing {...props} size={top} />;\n});\n\nconst SafeAreaBottom = memo(function SafeAreaBottom(\n props: Omit<ComponentPropsWithoutRef<typeof Spacing>, 'size'>\n) {\n const { bottom } = useSafeArea();\n return <Spacing {...props} size={bottom} />;\n});\n\nSafeArea.Top = SafeAreaTop;\nSafeArea.Bottom = SafeAreaBottom;\n","import { memo, type HTMLAttributes } from 'react';\nimport { styled } from 'styled-components';\n\nimport { coerceCssPixelValue, type CSSPixelValue } from './coerceCssPixelValue';\n\ntype AxisDirection = 'vertical' | 'horizontal';\n\nexport type SpacingProps = Omit<HTMLAttributes<HTMLDivElement>, 'children'> & {\n direction?: AxisDirection;\n size: CSSPixelValue;\n};\n\nexport const Spacing = memo(function Spacing(props: SpacingProps) {\n const { direction = 'vertical', size, ...restProps } = props;\n\n return (\n <SpacingContainer $direction={direction} $size={size} {...restProps} />\n );\n});\n\nconst SpacingContainer = styled.div<{\n $direction: SpacingProps['direction'];\n $size: SpacingProps['size'];\n}>`\n flex: none;\n width: ${({ $direction, $size }) =>\n $direction === 'horizontal' ? coerceCssPixelValue($size) : undefined};\n height: ${({ $direction, $size }) =>\n $direction === 'vertical' ? coerceCssPixelValue($size) : undefined};\n`;\n","export type CSSPixelValue = string | number;\n\nexport function coerceCssPixelValue(value: CSSPixelValue): string {\n return typeof value === 'string' ? value : `${value}px`;\n}\n","import { coerceCssPixelValue, type CSSPixelValue } from './coerceCssPixelValue';\n\nexport type SafeAreaCssValueProps = {\n top?: CSSPixelValue;\n bottom?: CSSPixelValue;\n left?: CSSPixelValue;\n right?: CSSPixelValue;\n};\n\nconst useSafeArea = ({\n top: T = 0,\n bottom: B = 0,\n left: L = 0,\n right: R = 0,\n}: SafeAreaCssValueProps = {}) => {\n const top = `max(${coerceCssPixelValue(T)}, env(safe-area-inset-top))`;\n const bottom = `max(${coerceCssPixelValue(B)}, env(safe-area-inset-bottom))`;\n const left = `max(${coerceCssPixelValue(L)}, env(safe-area-inset-left))`;\n const right = `max(${coerceCssPixelValue(R)}, env(safe-area-inset-right))`;\n\n return { top, bottom, left, right };\n};\n\nexport { useSafeArea };\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAAA,gBAIO;;;ACJP,mBAA0C;AAC1C,+BAAuB;;;ACChB,SAAS,oBAAoB,OAA8B;AAChE,SAAO,OAAO,UAAU,WAAW,QAAQ,GAAG;AAChD;;;ADYI;AAJG,IAAM,cAAU,mBAAK,SAASC,SAAQ,OAAqB;AAChE,QAAM,EAAE,YAAY,YAAY,MAAM,GAAG,UAAU,IAAI;AAEvD,SACE,4CAAC,oBAAiB,YAAY,WAAW,OAAO,MAAO,GAAG,WAAW;AAEzE,CAAC;AAED,IAAM,mBAAmB,gCAAO;AAAA;AAAA,WAKrB,CAAC,EAAE,YAAY,MAAM,MAC5B,eAAe,eAAe,oBAAoB,KAAK,IAAI;AAAA,YACnD,CAAC,EAAE,YAAY,MAAM,MAC7B,eAAe,aAAa,oBAAoB,KAAK,IAAI;AAAA;;;AEnB7D,IAAM,cAAc,CAAC;AAAA,EACnB,KAAK,IAAI;AAAA,EACT,QAAQ,IAAI;AAAA,EACZ,MAAM,IAAI;AAAA,EACV,OAAO,IAAI;AACb,IAA2B,CAAC,MAAM;AAChC,QAAM,MAAM,OAAO,oBAAoB,CAAC;AACxC,QAAM,SAAS,OAAO,oBAAoB,CAAC;AAC3C,QAAM,OAAO,OAAO,oBAAoB,CAAC;AACzC,QAAM,QAAQ,OAAO,oBAAoB,CAAC;AAE1C,SAAO,EAAE,KAAK,QAAQ,MAAM,MAAM;AACpC;;;AHCI,IAAAC,sBAAA;AARG,IAAM,WAAW,CAAsC;AAAA,EAC5D;AAAA,EACA;AAAA,EACA,GAAG;AACL,MAAwB;AACtB,QAAM,YAAY,MAAM;AAExB,SACE,8CAAC,aAAW,GAAG,OACb;AAAA,iDAAC,eAAY;AAAA,IACZ;AAAA,IACD,6CAAC,kBAAe;AAAA,KAClB;AAEJ;AAEA,IAAM,kBAAc,oBAAK,SAASC,aAChC,OACA;AACA,QAAM,EAAE,IAAI,IAAI,YAAY;AAC5B,SAAO,6CAAC,WAAS,GAAG,OAAO,MAAM,KAAK;AACxC,CAAC;AAED,IAAM,qBAAiB,oBAAK,SAASC,gBACnC,OACA;AACA,QAAM,EAAE,OAAO,IAAI,YAAY;AAC/B,SAAO,6CAAC,WAAS,GAAG,OAAO,MAAM,QAAQ;AAC3C,CAAC;AAED,SAAS,MAAM;AACf,SAAS,SAAS;","names":["import_react","Spacing","import_jsx_runtime","SafeAreaTop","SafeAreaBottom"]}
package/dist/SafeArea.mjs CHANGED
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  SafeArea
3
- } from "./chunk-WOYL5AA5.mjs";
3
+ } from "./chunk-HLTXXENG.mjs";
4
4
  import "./chunk-FUGA35PJ.mjs";
5
- import "./chunk-LKUAG7PE.mjs";
5
+ import "./chunk-DD3KGUQX.mjs";
6
6
  import "./chunk-T7K7QYTL.mjs";
7
7
  export {
8
8
  SafeArea
package/dist/Spacing.js CHANGED
@@ -34,7 +34,7 @@ function coerceCssPixelValue(value) {
34
34
  // src/Spacing.tsx
35
35
  var import_jsx_runtime = require("react/jsx-runtime");
36
36
  var Spacing = (0, import_react.memo)(function Spacing2(props) {
37
- const { direction = "horizontal", size, ...restProps } = props;
37
+ const { direction = "vertical", size, ...restProps } = props;
38
38
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SpacingContainer, { $direction: direction, $size: size, ...restProps });
39
39
  });
40
40
  var SpacingContainer = import_styled_components.styled.div`
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/Spacing.tsx","../src/coerceCssPixelValue.ts"],"sourcesContent":["import { memo, type HTMLAttributes } from 'react';\nimport { styled } from 'styled-components';\n\nimport { coerceCssPixelValue, type CSSPixelValue } from './coerceCssPixelValue';\n\ntype AxisDirection = 'vertical' | 'horizontal';\n\nexport type SpacingProps = Omit<HTMLAttributes<HTMLDivElement>, 'children'> & {\n direction?: AxisDirection;\n size: CSSPixelValue;\n};\n\nexport const Spacing = memo(function Spacing(props: SpacingProps) {\n const { direction = 'horizontal', size, ...restProps } = props;\n\n return (\n <SpacingContainer $direction={direction} $size={size} {...restProps} />\n );\n});\n\nconst SpacingContainer = styled.div<{\n $direction: SpacingProps['direction'];\n $size: SpacingProps['size'];\n}>`\n flex: none;\n width: ${({ $direction, $size }) =>\n $direction === 'horizontal' ? coerceCssPixelValue($size) : undefined};\n height: ${({ $direction, $size }) =>\n $direction === 'vertical' ? coerceCssPixelValue($size) : undefined};\n`;\n","export type CSSPixelValue = string | number;\n\nexport function coerceCssPixelValue(value: CSSPixelValue): string {\n return typeof value === 'string' ? value : `${value}px`;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAA0C;AAC1C,+BAAuB;;;ACChB,SAAS,oBAAoB,OAA8B;AAChE,SAAO,OAAO,UAAU,WAAW,QAAQ,GAAG;AAChD;;;ADYI;AAJG,IAAM,cAAU,mBAAK,SAASA,SAAQ,OAAqB;AAChE,QAAM,EAAE,YAAY,cAAc,MAAM,GAAG,UAAU,IAAI;AAEzD,SACE,4CAAC,oBAAiB,YAAY,WAAW,OAAO,MAAO,GAAG,WAAW;AAEzE,CAAC;AAED,IAAM,mBAAmB,gCAAO;AAAA;AAAA,WAKrB,CAAC,EAAE,YAAY,MAAM,MAC5B,eAAe,eAAe,oBAAoB,KAAK,IAAI;AAAA,YACnD,CAAC,EAAE,YAAY,MAAM,MAC7B,eAAe,aAAa,oBAAoB,KAAK,IAAI;AAAA;","names":["Spacing"]}
1
+ {"version":3,"sources":["../src/Spacing.tsx","../src/coerceCssPixelValue.ts"],"sourcesContent":["import { memo, type HTMLAttributes } from 'react';\nimport { styled } from 'styled-components';\n\nimport { coerceCssPixelValue, type CSSPixelValue } from './coerceCssPixelValue';\n\ntype AxisDirection = 'vertical' | 'horizontal';\n\nexport type SpacingProps = Omit<HTMLAttributes<HTMLDivElement>, 'children'> & {\n direction?: AxisDirection;\n size: CSSPixelValue;\n};\n\nexport const Spacing = memo(function Spacing(props: SpacingProps) {\n const { direction = 'vertical', size, ...restProps } = props;\n\n return (\n <SpacingContainer $direction={direction} $size={size} {...restProps} />\n );\n});\n\nconst SpacingContainer = styled.div<{\n $direction: SpacingProps['direction'];\n $size: SpacingProps['size'];\n}>`\n flex: none;\n width: ${({ $direction, $size }) =>\n $direction === 'horizontal' ? coerceCssPixelValue($size) : undefined};\n height: ${({ $direction, $size }) =>\n $direction === 'vertical' ? coerceCssPixelValue($size) : undefined};\n`;\n","export type CSSPixelValue = string | number;\n\nexport function coerceCssPixelValue(value: CSSPixelValue): string {\n return typeof value === 'string' ? value : `${value}px`;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAA0C;AAC1C,+BAAuB;;;ACChB,SAAS,oBAAoB,OAA8B;AAChE,SAAO,OAAO,UAAU,WAAW,QAAQ,GAAG;AAChD;;;ADYI;AAJG,IAAM,cAAU,mBAAK,SAASA,SAAQ,OAAqB;AAChE,QAAM,EAAE,YAAY,YAAY,MAAM,GAAG,UAAU,IAAI;AAEvD,SACE,4CAAC,oBAAiB,YAAY,WAAW,OAAO,MAAO,GAAG,WAAW;AAEzE,CAAC;AAED,IAAM,mBAAmB,gCAAO;AAAA;AAAA,WAKrB,CAAC,EAAE,YAAY,MAAM,MAC5B,eAAe,eAAe,oBAAoB,KAAK,IAAI;AAAA,YACnD,CAAC,EAAE,YAAY,MAAM,MAC7B,eAAe,aAAa,oBAAoB,KAAK,IAAI;AAAA;","names":["Spacing"]}
package/dist/Spacing.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  Spacing
3
- } from "./chunk-LKUAG7PE.mjs";
3
+ } from "./chunk-DD3KGUQX.mjs";
4
4
  import "./chunk-T7K7QYTL.mjs";
5
5
  export {
6
6
  Spacing
@@ -7,7 +7,7 @@ import { memo } from "react";
7
7
  import { styled } from "styled-components";
8
8
  import { jsx } from "react/jsx-runtime";
9
9
  var Spacing = memo(function Spacing2(props) {
10
- const { direction = "horizontal", size, ...restProps } = props;
10
+ const { direction = "vertical", size, ...restProps } = props;
11
11
  return /* @__PURE__ */ jsx(SpacingContainer, { $direction: direction, $size: size, ...restProps });
12
12
  });
13
13
  var SpacingContainer = styled.div`
@@ -19,4 +19,4 @@ var SpacingContainer = styled.div`
19
19
  export {
20
20
  Spacing
21
21
  };
22
- //# sourceMappingURL=chunk-LKUAG7PE.mjs.map
22
+ //# sourceMappingURL=chunk-DD3KGUQX.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/Spacing.tsx"],"sourcesContent":["import { memo, type HTMLAttributes } from 'react';\nimport { styled } from 'styled-components';\n\nimport { coerceCssPixelValue, type CSSPixelValue } from './coerceCssPixelValue';\n\ntype AxisDirection = 'vertical' | 'horizontal';\n\nexport type SpacingProps = Omit<HTMLAttributes<HTMLDivElement>, 'children'> & {\n direction?: AxisDirection;\n size: CSSPixelValue;\n};\n\nexport const Spacing = memo(function Spacing(props: SpacingProps) {\n const { direction = 'vertical', size, ...restProps } = props;\n\n return (\n <SpacingContainer $direction={direction} $size={size} {...restProps} />\n );\n});\n\nconst SpacingContainer = styled.div<{\n $direction: SpacingProps['direction'];\n $size: SpacingProps['size'];\n}>`\n flex: none;\n width: ${({ $direction, $size }) =>\n $direction === 'horizontal' ? coerceCssPixelValue($size) : undefined};\n height: ${({ $direction, $size }) =>\n $direction === 'vertical' ? coerceCssPixelValue($size) : undefined};\n`;\n"],"mappings":";;;;;AAAA,SAAS,YAAiC;AAC1C,SAAS,cAAc;AAenB;AAJG,IAAM,UAAU,KAAK,SAASA,SAAQ,OAAqB;AAChE,QAAM,EAAE,YAAY,YAAY,MAAM,GAAG,UAAU,IAAI;AAEvD,SACE,oBAAC,oBAAiB,YAAY,WAAW,OAAO,MAAO,GAAG,WAAW;AAEzE,CAAC;AAED,IAAM,mBAAmB,OAAO;AAAA;AAAA,WAKrB,CAAC,EAAE,YAAY,MAAM,MAC5B,eAAe,eAAe,oBAAoB,KAAK,IAAI;AAAA,YACnD,CAAC,EAAE,YAAY,MAAM,MAC7B,eAAe,aAAa,oBAAoB,KAAK,IAAI;AAAA;","names":["Spacing"]}
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-FUGA35PJ.mjs";
4
4
  import {
5
5
  Spacing
6
- } from "./chunk-LKUAG7PE.mjs";
6
+ } from "./chunk-DD3KGUQX.mjs";
7
7
 
8
8
  // src/SafeArea.tsx
9
9
  import {
@@ -36,4 +36,4 @@ SafeArea.Bottom = SafeAreaBottom;
36
36
  export {
37
37
  SafeArea
38
38
  };
39
- //# sourceMappingURL=chunk-WOYL5AA5.mjs.map
39
+ //# sourceMappingURL=chunk-HLTXXENG.mjs.map
@@ -0,0 +1,51 @@
1
+ // src/debounce.ts
2
+ function debounce(func, debounceMs) {
3
+ let pendingCall = null;
4
+ const invoke = () => {
5
+ if (pendingCall !== null) {
6
+ const { thisArg, args } = pendingCall;
7
+ func.apply(thisArg, args);
8
+ pendingCall = null;
9
+ }
10
+ };
11
+ const onTimerEnd = () => {
12
+ invoke();
13
+ cancel();
14
+ };
15
+ let timeoutId = null;
16
+ const schedule = () => {
17
+ if (timeoutId != null) {
18
+ clearTimeout(timeoutId);
19
+ }
20
+ timeoutId = setTimeout(() => {
21
+ timeoutId = null;
22
+ onTimerEnd();
23
+ }, debounceMs);
24
+ };
25
+ const cancelTimer = () => {
26
+ if (timeoutId !== null) {
27
+ clearTimeout(timeoutId);
28
+ timeoutId = null;
29
+ }
30
+ };
31
+ const cancel = () => {
32
+ cancelTimer();
33
+ pendingCall = null;
34
+ };
35
+ const flush = () => {
36
+ cancelTimer();
37
+ invoke();
38
+ };
39
+ const debounced = function(...args) {
40
+ pendingCall = { thisArg: this, args };
41
+ schedule();
42
+ };
43
+ debounced.cancel = cancel;
44
+ debounced.flush = flush;
45
+ return debounced;
46
+ }
47
+
48
+ export {
49
+ debounce
50
+ };
51
+ //# sourceMappingURL=chunk-RWZLYDXE.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/debounce.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\n\nexport type DebouncedFunction<F extends (...args: any[]) => void> = {\n (...args: Parameters<F>): void;\n\n /**\n * 디바운스된 함수의 모든 예약된 실행을 취소합니다.\n * 이 메서드는 활성 타이머를 제거하고 저장된 컨텍스트나 인수를 재설정합니다.\n */\n cancel: () => void;\n\n /**\n * 예약된 실행이 있는 경우 디바운스된 함수를 즉시 호출합니다.\n * 이 메서드는 현재 타이머를 취소하여 함수가 즉시 실행되도록 합니다.\n */\n flush: () => void;\n};\n\n/**\n * @example\n * const debouncedFunction = debounce(() => {\n * console.log('Function executed');\n * }, 1000);\n *\n */\nexport function debounce<F extends (...args: any[]) => void>(\n func: F,\n debounceMs: number\n): DebouncedFunction<F> {\n let pendingCall: { thisArg: any; args: Parameters<F> } | null = null;\n\n const invoke = () => {\n if (pendingCall !== null) {\n const { thisArg, args } = pendingCall;\n func.apply(thisArg, args);\n pendingCall = null;\n }\n };\n\n const onTimerEnd = () => {\n invoke();\n cancel();\n };\n\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\n\n const schedule = () => {\n if (timeoutId != null) {\n clearTimeout(timeoutId);\n }\n\n timeoutId = setTimeout(() => {\n timeoutId = null;\n onTimerEnd();\n }, debounceMs);\n };\n\n const cancelTimer = () => {\n if (timeoutId !== null) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n };\n\n const cancel = () => {\n cancelTimer();\n pendingCall = null;\n };\n\n const flush = () => {\n cancelTimer();\n invoke();\n };\n\n const debounced = function (this: any, ...args: Parameters<F>) {\n pendingCall = { thisArg: this, args };\n schedule();\n };\n\n debounced.cancel = cancel;\n debounced.flush = flush;\n\n return debounced;\n}\n"],"mappings":";AAyBO,SAAS,SACd,MACA,YACsB;AACtB,MAAI,cAA4D;AAEhE,QAAM,SAAS,MAAM;AACnB,QAAI,gBAAgB,MAAM;AACxB,YAAM,EAAE,SAAS,KAAK,IAAI;AAC1B,WAAK,MAAM,SAAS,IAAI;AACxB,oBAAc;AAAA,IAChB;AAAA,EACF;AAEA,QAAM,aAAa,MAAM;AACvB,WAAO;AACP,WAAO;AAAA,EACT;AAEA,MAAI,YAAkD;AAEtD,QAAM,WAAW,MAAM;AACrB,QAAI,aAAa,MAAM;AACrB,mBAAa,SAAS;AAAA,IACxB;AAEA,gBAAY,WAAW,MAAM;AAC3B,kBAAY;AACZ,iBAAW;AAAA,IACb,GAAG,UAAU;AAAA,EACf;AAEA,QAAM,cAAc,MAAM;AACxB,QAAI,cAAc,MAAM;AACtB,mBAAa,SAAS;AACtB,kBAAY;AAAA,IACd;AAAA,EACF;AAEA,QAAM,SAAS,MAAM;AACnB,gBAAY;AACZ,kBAAc;AAAA,EAChB;AAEA,QAAM,QAAQ,MAAM;AAClB,gBAAY;AACZ,WAAO;AAAA,EACT;AAEA,QAAM,YAAY,YAAwB,MAAqB;AAC7D,kBAAc,EAAE,SAAS,MAAM,KAAK;AACpC,aAAS;AAAA,EACX;AAEA,YAAU,SAAS;AACnB,YAAU,QAAQ;AAElB,SAAO;AACT;","names":[]}
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/debounce.ts
21
+ var debounce_exports = {};
22
+ __export(debounce_exports, {
23
+ debounce: () => debounce
24
+ });
25
+ module.exports = __toCommonJS(debounce_exports);
26
+ function debounce(func, debounceMs) {
27
+ let pendingCall = null;
28
+ const invoke = () => {
29
+ if (pendingCall !== null) {
30
+ const { thisArg, args } = pendingCall;
31
+ func.apply(thisArg, args);
32
+ pendingCall = null;
33
+ }
34
+ };
35
+ const onTimerEnd = () => {
36
+ invoke();
37
+ cancel();
38
+ };
39
+ let timeoutId = null;
40
+ const schedule = () => {
41
+ if (timeoutId != null) {
42
+ clearTimeout(timeoutId);
43
+ }
44
+ timeoutId = setTimeout(() => {
45
+ timeoutId = null;
46
+ onTimerEnd();
47
+ }, debounceMs);
48
+ };
49
+ const cancelTimer = () => {
50
+ if (timeoutId !== null) {
51
+ clearTimeout(timeoutId);
52
+ timeoutId = null;
53
+ }
54
+ };
55
+ const cancel = () => {
56
+ cancelTimer();
57
+ pendingCall = null;
58
+ };
59
+ const flush = () => {
60
+ cancelTimer();
61
+ invoke();
62
+ };
63
+ const debounced = function(...args) {
64
+ pendingCall = { thisArg: this, args };
65
+ schedule();
66
+ };
67
+ debounced.cancel = cancel;
68
+ debounced.flush = flush;
69
+ return debounced;
70
+ }
71
+ // Annotate the CommonJS export names for ESM import in node:
72
+ 0 && (module.exports = {
73
+ debounce
74
+ });
75
+ //# sourceMappingURL=debounce.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/debounce.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\n\nexport type DebouncedFunction<F extends (...args: any[]) => void> = {\n (...args: Parameters<F>): void;\n\n /**\n * 디바운스된 함수의 모든 예약된 실행을 취소합니다.\n * 이 메서드는 활성 타이머를 제거하고 저장된 컨텍스트나 인수를 재설정합니다.\n */\n cancel: () => void;\n\n /**\n * 예약된 실행이 있는 경우 디바운스된 함수를 즉시 호출합니다.\n * 이 메서드는 현재 타이머를 취소하여 함수가 즉시 실행되도록 합니다.\n */\n flush: () => void;\n};\n\n/**\n * @example\n * const debouncedFunction = debounce(() => {\n * console.log('Function executed');\n * }, 1000);\n *\n */\nexport function debounce<F extends (...args: any[]) => void>(\n func: F,\n debounceMs: number\n): DebouncedFunction<F> {\n let pendingCall: { thisArg: any; args: Parameters<F> } | null = null;\n\n const invoke = () => {\n if (pendingCall !== null) {\n const { thisArg, args } = pendingCall;\n func.apply(thisArg, args);\n pendingCall = null;\n }\n };\n\n const onTimerEnd = () => {\n invoke();\n cancel();\n };\n\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\n\n const schedule = () => {\n if (timeoutId != null) {\n clearTimeout(timeoutId);\n }\n\n timeoutId = setTimeout(() => {\n timeoutId = null;\n onTimerEnd();\n }, debounceMs);\n };\n\n const cancelTimer = () => {\n if (timeoutId !== null) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n };\n\n const cancel = () => {\n cancelTimer();\n pendingCall = null;\n };\n\n const flush = () => {\n cancelTimer();\n invoke();\n };\n\n const debounced = function (this: any, ...args: Parameters<F>) {\n pendingCall = { thisArg: this, args };\n schedule();\n };\n\n debounced.cancel = cancel;\n debounced.flush = flush;\n\n return debounced;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAyBO,SAAS,SACd,MACA,YACsB;AACtB,MAAI,cAA4D;AAEhE,QAAM,SAAS,MAAM;AACnB,QAAI,gBAAgB,MAAM;AACxB,YAAM,EAAE,SAAS,KAAK,IAAI;AAC1B,WAAK,MAAM,SAAS,IAAI;AACxB,oBAAc;AAAA,IAChB;AAAA,EACF;AAEA,QAAM,aAAa,MAAM;AACvB,WAAO;AACP,WAAO;AAAA,EACT;AAEA,MAAI,YAAkD;AAEtD,QAAM,WAAW,MAAM;AACrB,QAAI,aAAa,MAAM;AACrB,mBAAa,SAAS;AAAA,IACxB;AAEA,gBAAY,WAAW,MAAM;AAC3B,kBAAY;AACZ,iBAAW;AAAA,IACb,GAAG,UAAU;AAAA,EACf;AAEA,QAAM,cAAc,MAAM;AACxB,QAAI,cAAc,MAAM;AACtB,mBAAa,SAAS;AACtB,kBAAY;AAAA,IACd;AAAA,EACF;AAEA,QAAM,SAAS,MAAM;AACnB,gBAAY;AACZ,kBAAc;AAAA,EAChB;AAEA,QAAM,QAAQ,MAAM;AAClB,gBAAY;AACZ,WAAO;AAAA,EACT;AAEA,QAAM,YAAY,YAAwB,MAAqB;AAC7D,kBAAc,EAAE,SAAS,MAAM,KAAK;AACpC,aAAS;AAAA,EACX;AAEA,YAAU,SAAS;AACnB,YAAU,QAAQ;AAElB,SAAO;AACT;","names":[]}
@@ -0,0 +1,7 @@
1
+ import {
2
+ debounce
3
+ } from "./chunk-RWZLYDXE.mjs";
4
+ export {
5
+ debounce
6
+ };
7
+ //# sourceMappingURL=debounce.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
package/dist/index.d.ts CHANGED
@@ -171,4 +171,26 @@ declare const queryString: {
171
171
  set: typeof setQueryString;
172
172
  };
173
173
 
174
- export { Choose, ChooseOtherwiseProps, ChooseProps, ChooseWhenProps, Flex, FlexProps, HexToRgbaProps, If, IfProps, JosaProps, MultiLineEllipsisProps, SafeArea, SafeAreaCssValueProps, SafeAreaProps, Spacing, SpacingProps, Validate, VariableType, composeEventHandlers, createContext, ellipsis, getVar, hexToRgba, josa, multiLineEllipsis, queryString, useSafeArea };
174
+ type DebouncedFunction<F extends (...args: any[]) => void> = {
175
+ (...args: Parameters<F>): void;
176
+ /**
177
+ * 디바운스된 함수의 모든 예약된 실행을 취소합니다.
178
+ * 이 메서드는 활성 타이머를 제거하고 저장된 컨텍스트나 인수를 재설정합니다.
179
+ */
180
+ cancel: () => void;
181
+ /**
182
+ * 예약된 실행이 있는 경우 디바운스된 함수를 즉시 호출합니다.
183
+ * 이 메서드는 현재 타이머를 취소하여 함수가 즉시 실행되도록 합니다.
184
+ */
185
+ flush: () => void;
186
+ };
187
+ /**
188
+ * @example
189
+ * const debouncedFunction = debounce(() => {
190
+ * console.log('Function executed');
191
+ * }, 1000);
192
+ *
193
+ */
194
+ declare function debounce<F extends (...args: any[]) => void>(func: F, debounceMs: number): DebouncedFunction<F>;
195
+
196
+ export { Choose, ChooseOtherwiseProps, ChooseProps, ChooseWhenProps, DebouncedFunction, Flex, FlexProps, HexToRgbaProps, If, IfProps, JosaProps, MultiLineEllipsisProps, SafeArea, SafeAreaCssValueProps, SafeAreaProps, Spacing, SpacingProps, Validate, VariableType, composeEventHandlers, createContext, debounce, ellipsis, getVar, hexToRgba, josa, multiLineEllipsis, queryString, useSafeArea };
package/dist/index.js CHANGED
@@ -28,6 +28,7 @@ __export(src_exports, {
28
28
  Validate: () => Validate,
29
29
  composeEventHandlers: () => composeEventHandlers,
30
30
  createContext: () => createContext,
31
+ debounce: () => debounce,
31
32
  ellipsis: () => ellipsis,
32
33
  getVar: () => getVar,
33
34
  hexToRgba: () => hexToRgba,
@@ -324,7 +325,7 @@ var import_react4 = require("react");
324
325
  var import_styled_components3 = require("styled-components");
325
326
  var import_jsx_runtime5 = require("react/jsx-runtime");
326
327
  var Spacing = (0, import_react4.memo)(function Spacing2(props) {
327
- const { direction = "horizontal", size, ...restProps } = props;
328
+ const { direction = "vertical", size, ...restProps } = props;
328
329
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(SpacingContainer, { $direction: direction, $size: size, ...restProps });
329
330
  });
330
331
  var SpacingContainer = import_styled_components3.styled.div`
@@ -435,6 +436,53 @@ var queryString = {
435
436
  get: getQueryString,
436
437
  set: setQueryString
437
438
  };
439
+
440
+ // src/debounce.ts
441
+ function debounce(func, debounceMs) {
442
+ let pendingCall = null;
443
+ const invoke = () => {
444
+ if (pendingCall !== null) {
445
+ const { thisArg, args } = pendingCall;
446
+ func.apply(thisArg, args);
447
+ pendingCall = null;
448
+ }
449
+ };
450
+ const onTimerEnd = () => {
451
+ invoke();
452
+ cancel();
453
+ };
454
+ let timeoutId = null;
455
+ const schedule = () => {
456
+ if (timeoutId != null) {
457
+ clearTimeout(timeoutId);
458
+ }
459
+ timeoutId = setTimeout(() => {
460
+ timeoutId = null;
461
+ onTimerEnd();
462
+ }, debounceMs);
463
+ };
464
+ const cancelTimer = () => {
465
+ if (timeoutId !== null) {
466
+ clearTimeout(timeoutId);
467
+ timeoutId = null;
468
+ }
469
+ };
470
+ const cancel = () => {
471
+ cancelTimer();
472
+ pendingCall = null;
473
+ };
474
+ const flush = () => {
475
+ cancelTimer();
476
+ invoke();
477
+ };
478
+ const debounced = function(...args) {
479
+ pendingCall = { thisArg: this, args };
480
+ schedule();
481
+ };
482
+ debounced.cancel = cancel;
483
+ debounced.flush = flush;
484
+ return debounced;
485
+ }
438
486
  // Annotate the CommonJS export names for ESM import in node:
439
487
  0 && (module.exports = {
440
488
  Choose,
@@ -445,6 +493,7 @@ var queryString = {
445
493
  Validate,
446
494
  composeEventHandlers,
447
495
  createContext,
496
+ debounce,
448
497
  ellipsis,
449
498
  getVar,
450
499
  hexToRgba,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/Choose.tsx","../src/composeEventHandlers.ts","../src/createContext.tsx","../src/getVar.ts","../src/If.tsx","../src/Flex.tsx","../src/coerceCssPixelValue.ts","../src/ellipsis.ts","../src/hexToRgba.ts","../src/constants/josa.ts","../src/hasBatchim.ts","../src/josa.ts","../src/Validate.ts","../src/Spacing.tsx","../src/useSafeArea.ts","../src/SafeArea.tsx","../src/queryString.ts"],"sourcesContent":["export {\n Choose,\n type ChooseWhenProps,\n type ChooseProps,\n type ChooseOtherwiseProps,\n} from './Choose';\n\nexport { composeEventHandlers } from './composeEventHandlers';\n\nexport { createContext } from './createContext';\n\nexport { getVar, type VariableType } from './getVar';\n\nexport { If, type IfProps } from './If';\n\nexport { Flex, type FlexProps } from './Flex';\n\nexport {\n ellipsis,\n multiLineEllipsis,\n type MultiLineEllipsisProps,\n} from './ellipsis';\n\nexport { hexToRgba, type HexToRgbaProps } from './hexToRgba';\n\nexport { josa, type JosaProps } from './josa';\n\nexport { Validate } from './Validate';\n\nexport { Spacing, type SpacingProps } from './Spacing';\n\nexport { useSafeArea, type SafeAreaCssValueProps } from './useSafeArea';\n\nexport { SafeArea, type SafeAreaProps } from './SafeArea';\n\nexport { queryString } from './queryString';\n","import { isValidElement, type ReactNode, type FC, Children } from 'react';\n\nexport type ChooseWhenProps = {\n condition: boolean;\n children: ReactNode;\n};\n\nexport type ChooseProps = {\n children: ReactNode;\n};\n\nexport type ChooseOtherwiseProps = {\n children: ReactNode;\n};\n\nexport function Choose({ children }: ChooseProps) {\n const validChildren = Children.toArray(children);\n\n const matchingChild = validChildren.find(\n (child) =>\n isValidElement<ChooseWhenProps>(child) &&\n child.type === Choose.When &&\n child.props.condition\n );\n\n if (matchingChild) {\n return matchingChild;\n }\n\n const otherwiseChild = validChildren.find(\n (child) => isValidElement(child) && child.type === Choose.Otherwise\n );\n\n return otherwiseChild || <></>;\n}\n\nconst ChooseWhen: FC<ChooseWhenProps> = ({ children }) => <>{children}</>;\nChooseWhen.displayName = 'Choose.When';\n\nconst ChooseOtherwise: FC<ChooseOtherwiseProps> = ({ children }) => (\n <>{children}</>\n);\n\nChoose.When = ChooseWhen;\nChoose.Otherwise = ChooseOtherwise;\n","// @see https://github.com/radix-ui/primitives/blob/main/packages/core/primitive/src/primitive.tsx\n\nexport function composeEventHandlers<E>(\n originalEventHandler?: (event: E) => void,\n ourEventHandler?: (event: E) => void,\n { checkForDefaultPrevented = true } = {}\n) {\n return function handleEvent(event: E) {\n originalEventHandler?.(event);\n\n if (\n checkForDefaultPrevented === false ||\n !(event as unknown as Event).defaultPrevented\n ) {\n return ourEventHandler?.(event);\n }\n };\n}\n","import {\n useMemo,\n createContext as createContextRaw,\n useContext as useContextRaw,\n type PropsWithChildren,\n} from 'react';\n\nexport function createContext<ContextValueType extends object | null>(\n rootComponentName: string,\n defaultContext?: ContextValueType\n) {\n const Context = createContextRaw<ContextValueType | undefined>(\n defaultContext\n );\n\n function Provider(props: PropsWithChildren<ContextValueType>) {\n const { children, ...contextValues } = props;\n\n const value = useMemo(\n () => contextValues,\n [contextValues]\n ) as ContextValueType;\n\n return <Context.Provider value={value}>{children}</Context.Provider>;\n }\n\n function useContext(consumerName: string) {\n const context = useContextRaw(Context);\n if (context == null) {\n throw new Error(\n `${consumerName}은 ${rootComponentName}하위에서 사용해야 합니다.`\n );\n }\n\n return context;\n }\n\n Provider.displayName = `${rootComponentName}Provider`;\n return [Provider, useContext] as const;\n}\n","export type VariableType = `--${string}`;\n\nexport function getVar(variable: VariableType, defaultValue?: string) {\n if (defaultValue) {\n return `var(${variable}, ${defaultValue})`;\n }\n\n return `var(${variable})`;\n}\n","import { type ReactNode } from 'react';\n\nexport type IfProps = {\n condition: boolean;\n children: ReactNode;\n};\n\nexport function If(props: IfProps) {\n const { condition, children } = props;\n\n return condition ? <>{children}</> : null;\n}\n","import { memo, type CSSProperties, type HTMLAttributes } from 'react';\nimport { styled } from 'styled-components';\n\nimport { coerceCssPixelValue, type CSSPixelValue } from './coerceCssPixelValue';\n\ntype Justify = CSSProperties['justifyContent'];\ntype Align = CSSProperties['alignItems'];\ntype Direction = CSSProperties['flexDirection'];\n\nexport type FlexProps = HTMLAttributes<HTMLDivElement> & {\n gap?: CSSPixelValue;\n justify?: Justify;\n align?: Align;\n direction?: Direction;\n};\n\nexport const Flex = memo(function Flex(props: FlexProps) {\n const {\n gap = 0,\n justify = 'center',\n align = 'center',\n direction = 'row',\n children,\n ...restProps\n } = props;\n\n return (\n <Container\n $gap={gap}\n $justify={justify}\n $align={align}\n $direction={direction}\n {...restProps}\n >\n {children}\n </Container>\n );\n});\n\nexport const Container = styled.div<{\n $gap: CSSPixelValue;\n $justify: Justify;\n $align: Align;\n $direction: Direction;\n}>`\n display: flex;\n flex-direction: ${({ $direction }) => $direction};\n gap: ${({ $gap }) => coerceCssPixelValue($gap)};\n align-items: ${({ $align }) => $align};\n justify-content: ${({ $justify }) => $justify};\n`;\n","export type CSSPixelValue = string | number;\n\nexport function coerceCssPixelValue(value: CSSPixelValue): string {\n return typeof value === 'string' ? value : `${value}px`;\n}\n","import { css } from 'styled-components';\n\nexport type MultiLineEllipsisProps = {\n line: number;\n};\n\nexport const ellipsis = css`\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n`;\n\nexport const multiLineEllipsis = ({ line }: MultiLineEllipsisProps) => css`\n display: -webkit-box;\n overflow: hidden;\n text-overflow: ellipsis;\n -webkit-line-clamp: ${line};\n -webkit-box-orient: vertical;\n`;\n","export type HexToRgbaProps = { hex: string; alpha?: number };\n\nfunction parseHexToDecimal(hex: string): number {\n return parseInt(hex, 16);\n}\n\nfunction validateHex(hex: string): string {\n const match = /^#?([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/.exec(hex);\n if (!match) {\n throw new Error(\n `Invalid hex value: \"${hex}\". Expected formats: \"#RGB\", \"RGB\", \"#RRGGBB\", or \"RRGGBB\".`\n );\n }\n return match[1];\n}\n\nfunction expandHex(hex: string): string {\n return hex.length === 3\n ? hex\n .split('')\n .map((char) => char + char)\n .join('')\n : hex;\n}\n\nfunction isValidAlpha(alpha: number): boolean {\n return alpha >= 0 && alpha <= 1;\n}\n\nexport function hexToRgba({ hex, alpha = 1 }: HexToRgbaProps): string {\n if (!isValidAlpha(alpha)) {\n throw new Error(\n `Invalid alpha value. Must be between 0 and 1, received: ${alpha}`\n );\n }\n\n const validatedHex = validateHex(hex);\n const expandedHex = expandHex(validatedHex);\n\n const r = parseHexToDecimal(expandedHex.slice(0, 2));\n const g = parseHexToDecimal(expandedHex.slice(2, 4));\n const b = parseHexToDecimal(expandedHex.slice(4, 6));\n\n return `rgba(${r},${g},${b},${alpha})`;\n}\n","export const COMPLETE_HANGUL_START_CHARCODE = '가'.charCodeAt(0);\nexport const COMPLETE_HANGUL_END_CHARCODE = '힣'.charCodeAt(0);\n\nexport const NUMBER_OF_JONGSEONG = 28;\nexport const NUMBER_OF_JUNGSEONG = 21;\n\nconst DISASSEMBLED_CONSONANTS_BY_CONSONANT = {\n '': '',\n ㄱ: 'ㄱ',\n ㄲ: 'ㄲ',\n ㄳ: 'ㄱㅅ',\n ㄴ: 'ㄴ',\n ㄵ: 'ㄴㅈ',\n ㄶ: 'ㄴㅎ',\n ㄷ: 'ㄷ',\n ㄸ: 'ㄸ',\n ㄹ: 'ㄹ',\n ㄺ: 'ㄹㄱ',\n ㄻ: 'ㄹㅁ',\n ㄼ: 'ㄹㅂ',\n ㄽ: 'ㄹㅅ',\n ㄾ: 'ㄹㅌ',\n ㄿ: 'ㄹㅍ',\n ㅀ: 'ㄹㅎ',\n ㅁ: 'ㅁ',\n ㅂ: 'ㅂ',\n ㅃ: 'ㅃ',\n ㅄ: 'ㅂㅅ',\n ㅅ: 'ㅅ',\n ㅆ: 'ㅆ',\n ㅇ: 'ㅇ',\n ㅈ: 'ㅈ',\n ㅉ: 'ㅉ',\n ㅊ: 'ㅊ',\n ㅋ: 'ㅋ',\n ㅌ: 'ㅌ',\n ㅍ: 'ㅍ',\n ㅎ: 'ㅎ',\n} as const;\n\nexport const JONGSEONGS = (\n [\n '',\n 'ㄱ',\n 'ㄲ',\n 'ㄳ',\n 'ㄴ',\n 'ㄵ',\n 'ㄶ',\n 'ㄷ',\n 'ㄹ',\n 'ㄺ',\n 'ㄻ',\n 'ㄼ',\n 'ㄽ',\n 'ㄾ',\n 'ㄿ',\n 'ㅀ',\n 'ㅁ',\n 'ㅂ',\n 'ㅄ',\n 'ㅅ',\n 'ㅆ',\n 'ㅇ',\n 'ㅈ',\n 'ㅊ',\n 'ㅋ',\n 'ㅌ',\n 'ㅍ',\n 'ㅎ',\n ] as const\n).map((consonant) => DISASSEMBLED_CONSONANTS_BY_CONSONANT[consonant]);\n","import {\n COMPLETE_HANGUL_END_CHARCODE,\n COMPLETE_HANGUL_START_CHARCODE,\n NUMBER_OF_JONGSEONG,\n} from './constants/josa';\n\n/**\n * 한글 음절의 받침 유무를 확인합니다.\n * @param str - 검사할 문자열\n * @returns 받침이 있으면 true, 없으면 false\n */\nexport function hasBatchim(str: string): boolean {\n const lastChar = str[str.length - 1];\n if (!lastChar) return false;\n\n const charCode = lastChar.charCodeAt(0);\n\n // 한글 완성형 문자인지 확인\n if (\n charCode < COMPLETE_HANGUL_START_CHARCODE ||\n charCode > COMPLETE_HANGUL_END_CHARCODE\n ) {\n return false;\n }\n\n // 받침 코드 계산\n const batchimCode =\n (charCode - COMPLETE_HANGUL_START_CHARCODE) % NUMBER_OF_JONGSEONG;\n\n return batchimCode > 0; // 받침이 있으면 true\n}\n","import { hasBatchim } from './hasBatchim';\n\ntype JosaOption = '이/가' | '을/를' | '은/는';\n\ntype ExtractJosaOption<T> = T extends `${infer A}/${infer B}` ? A | B : never;\n\nexport type JosaProps<U extends JosaOption> = {\n word: string;\n josa: U;\n};\n\n/**\n * 주어진 단어와 조사 옵션을 기반으로 올바른 조사를 반환합니다.\n * @returns 단어와 올바른 조사가 결합된 문자열\n */\nexport function josa<U extends JosaOption>(\n props: JosaProps<U>\n): `${JosaProps<U>['word']}${ExtractJosaOption<U>}` {\n const { word, josa } = props;\n\n if (!word) {\n return word as `${JosaProps<U>['word']}${ExtractJosaOption<U>}`;\n }\n\n return `${word}${josaPicker({\n word,\n josa,\n })}` as `${JosaProps<U>['word']}${ExtractJosaOption<U>}`;\n}\n\n/**\n * 주어진 단어와 조사 옵션을 기반으로 올바른 조사를 선택합니다.\n * @returns 올바른 조사\n */\nfunction josaPicker<U extends JosaOption>(\n props: JosaProps<U>\n): ExtractJosaOption<U> {\n const { word, josa } = props;\n\n if (!word) {\n return josa.split('/')[0] as ExtractJosaOption<U>;\n }\n\n const has받침 = hasBatchim(word);\n const index = has받침 ? 0 : 1;\n\n return josa.split('/')[index] as ExtractJosaOption<U>;\n}\n\njosa.pick = josaPicker;\n","/**\n *\n * @see 이메일 주소가 RFC 5322 표준을 따르는지 검사합니다. {@link https://emailregex.com/}\n */\nfunction isEmail(email: string) {\n const regExp =\n /^(([^<>()\\[\\]\\\\.,;:\\s@\"]+(\\.[^<>()\\[\\]\\\\.,;:\\s@\"]+)*)|(\".+\"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}])|(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,}))$/;\n return regExp.test(email);\n}\n\nfunction isPhoneNumber(phoneNumber: string) {\n // 하이픈 있는 형식\n const regExpWithHyphen = /^01([0|1|6|7|8|9])-([0-9]{3,4})-([0-9]{4})$/;\n // 하이픈 없는 형식\n const regExpWithoutHyphen = /^01([0|1|6|7|8|9])([0-9]{3,4})([0-9]{4})$/;\n\n return (\n regExpWithHyphen.test(phoneNumber) || regExpWithoutHyphen.test(phoneNumber)\n );\n}\n\nexport const Validate = {\n email: isEmail,\n phoneNumber: isPhoneNumber,\n};\n","import { memo, type HTMLAttributes } from 'react';\nimport { styled } from 'styled-components';\n\nimport { coerceCssPixelValue, type CSSPixelValue } from './coerceCssPixelValue';\n\ntype AxisDirection = 'vertical' | 'horizontal';\n\nexport type SpacingProps = Omit<HTMLAttributes<HTMLDivElement>, 'children'> & {\n direction?: AxisDirection;\n size: CSSPixelValue;\n};\n\nexport const Spacing = memo(function Spacing(props: SpacingProps) {\n const { direction = 'horizontal', size, ...restProps } = props;\n\n return (\n <SpacingContainer $direction={direction} $size={size} {...restProps} />\n );\n});\n\nconst SpacingContainer = styled.div<{\n $direction: SpacingProps['direction'];\n $size: SpacingProps['size'];\n}>`\n flex: none;\n width: ${({ $direction, $size }) =>\n $direction === 'horizontal' ? coerceCssPixelValue($size) : undefined};\n height: ${({ $direction, $size }) =>\n $direction === 'vertical' ? coerceCssPixelValue($size) : undefined};\n`;\n","import { coerceCssPixelValue, type CSSPixelValue } from './coerceCssPixelValue';\n\nexport type SafeAreaCssValueProps = {\n top?: CSSPixelValue;\n bottom?: CSSPixelValue;\n left?: CSSPixelValue;\n right?: CSSPixelValue;\n};\n\nconst useSafeArea = ({\n top: T = 0,\n bottom: B = 0,\n left: L = 0,\n right: R = 0,\n}: SafeAreaCssValueProps = {}) => {\n const top = `max(${coerceCssPixelValue(T)}, env(safe-area-inset-top))`;\n const bottom = `max(${coerceCssPixelValue(B)}, env(safe-area-inset-bottom))`;\n const left = `max(${coerceCssPixelValue(L)}, env(safe-area-inset-left))`;\n const right = `max(${coerceCssPixelValue(R)}, env(safe-area-inset-right))`;\n\n return { top, bottom, left, right };\n};\n\nexport { useSafeArea };\n","import React, {\n memo,\n type ComponentPropsWithoutRef,\n type ReactNode,\n} from 'react';\n\nimport { Spacing } from './Spacing';\nimport { useSafeArea } from './useSafeArea';\n\nexport type SafeAreaProps<T extends React.ElementType = 'div'> = {\n as?: T;\n children: ReactNode;\n} & ComponentPropsWithoutRef<T>;\n\nexport const SafeArea = <T extends React.ElementType = 'div'>({\n as,\n children,\n ...props\n}: SafeAreaProps<T>) => {\n const Component = as || 'div';\n\n return (\n <Component {...props}>\n <SafeAreaTop />\n {children}\n <SafeAreaBottom />\n </Component>\n );\n};\n\nconst SafeAreaTop = memo(function SafeAreaTop(\n props: Omit<ComponentPropsWithoutRef<typeof Spacing>, 'size'>\n) {\n const { top } = useSafeArea();\n return <Spacing {...props} size={top} />;\n});\n\nconst SafeAreaBottom = memo(function SafeAreaBottom(\n props: Omit<ComponentPropsWithoutRef<typeof Spacing>, 'size'>\n) {\n const { bottom } = useSafeArea();\n return <Spacing {...props} size={bottom} />;\n});\n\nSafeArea.Top = SafeAreaTop;\nSafeArea.Bottom = SafeAreaBottom;\n","/**\n * @description 쿼리 스트링을 생성합니다.\n * @example createSearchParamString({ a: 1, b: 2, c: 3 }) // 'a=1&b=2&c=3'\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction createSearchParamString(params: Record<string, any>) {\n return (\n new URLSearchParams(\n Object.entries(params)\n .filter(([, value]) => value != null)\n .map(([key, value]) => {\n if (Array.isArray(value)) {\n return value.map((x) => [key, x]);\n }\n return [[key, value]];\n })\n .flat()\n )\n .toString()\n // Convert space characters to '%20' according to RFC3986 spec, from RFC1738.\n .replace(/\\+/g, '%20')\n );\n}\n\n/**\n * @description 물음표를 포함한 쿼리 스트링을 생성합니다.\n * @example createQueryString({ a: 1, b: 2, c: 3 }) // '?a=1&b=2&c=3'\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction createQueryString(params: Record<string, any>) {\n const queryString = createSearchParamString(params);\n\n if (queryString === '') {\n return '';\n }\n\n return `?${queryString}`;\n}\n\n/**\n * @description 이터러블에서 키와 값을 가진 객체로 변환합니다.\n * @example fromEntries([['a', 1], ['b', 2], ['c', 3]]) // { a: 1, b: 2, c: 3 }\n */\nfunction fromEntries<T extends readonly [string | number, unknown]>(\n iterable: Iterable<T>\n) {\n const result: Record<string | number | symbol, T[1]> = {};\n\n for (const [key, value] of Array.from(iterable)) {\n if (result[key]) {\n if (Array.isArray(result[key])) {\n (result[key] as Array<string | number>).push(value as string | number);\n } else {\n result[key] = [result[key], value];\n }\n } else {\n result[key] = value;\n }\n }\n\n return result;\n}\n\n/**\n * @description 쿼리 스트링을 객체로 변환합니다.\n * @example parseQueryString('?a=1&b=2&c=3') // { a: '1', b: '2', c: '3' }\n */\nfunction parseQueryString<Result = Record<string, string>>(\n queryString: string = typeof location !== 'undefined' ? location.search : ''\n): Result {\n const query = queryString.trim().replace(/^[?#&]/, '');\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return fromEntries(new URLSearchParams(query)) as any;\n}\n\n/**\n * @description 쿼리 스트링에서 특정 키의 값을 가져옵니다.\n *\n * @param name 가져올 쿼리 스트링의 키\n * @param parser 가져온 값을 파싱할 함수\n * @returns 파싱된 값\n *\n * @example\n * url: 'http://example.com/?a=1'\n * getQueryString('a') // '1'\n * getQueryString('a', parseInt) // 1\n * getQueryString('b') // undefined\n * getQueryString('b', parseInt) // undefined\n */\nfunction getQueryString(name: string): string | undefined;\nfunction getQueryString<T>(\n name: string,\n parser: (val: string) => T\n): T | undefined;\nfunction getQueryString<T = string>(name: string, parser?: (val: string) => T) {\n const value = queryString.parse<{ [name: string]: string | undefined }>()[\n name\n ];\n\n if (parser == null || value == null) {\n return value;\n } else {\n return parser(value);\n }\n}\n\n/**\n * @description 기존 쿼리 스트링에 새로운 쿼리 스트링을 추가합니다.\n * @example setQueryString({ qs: '?a=1', key: 'b', value: '2' }) // '?a=1&b=2'\n */\nfunction setQueryString({\n qs,\n key,\n value,\n}: {\n qs: string;\n key: string;\n value: string;\n}) {\n const parsed = parseQueryString(qs);\n\n return createQueryString({\n ...parsed,\n [key]: value,\n });\n}\n\nexport const queryString = {\n create: createQueryString,\n parse: parseQueryString,\n get: getQueryString,\n set: setQueryString,\n};\n"],"mappings":"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","names":["import_react","import_jsx_runtime","createContextRaw","useContextRaw","import_jsx_runtime","import_react","import_jsx_runtime","Flex","import_styled_components","josa","import_react","import_styled_components","import_jsx_runtime","Spacing","import_react","import_jsx_runtime","SafeAreaTop","SafeAreaBottom","queryString"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/Choose.tsx","../src/composeEventHandlers.ts","../src/createContext.tsx","../src/getVar.ts","../src/If.tsx","../src/Flex.tsx","../src/coerceCssPixelValue.ts","../src/ellipsis.ts","../src/hexToRgba.ts","../src/constants/josa.ts","../src/hasBatchim.ts","../src/josa.ts","../src/Validate.ts","../src/Spacing.tsx","../src/useSafeArea.ts","../src/SafeArea.tsx","../src/queryString.ts","../src/debounce.ts"],"sourcesContent":["export {\n Choose,\n type ChooseWhenProps,\n type ChooseProps,\n type ChooseOtherwiseProps,\n} from './Choose';\n\nexport { composeEventHandlers } from './composeEventHandlers';\n\nexport { createContext } from './createContext';\n\nexport { getVar, type VariableType } from './getVar';\n\nexport { If, type IfProps } from './If';\n\nexport { Flex, type FlexProps } from './Flex';\n\nexport {\n ellipsis,\n multiLineEllipsis,\n type MultiLineEllipsisProps,\n} from './ellipsis';\n\nexport { hexToRgba, type HexToRgbaProps } from './hexToRgba';\n\nexport { josa, type JosaProps } from './josa';\n\nexport { Validate } from './Validate';\n\nexport { Spacing, type SpacingProps } from './Spacing';\n\nexport { useSafeArea, type SafeAreaCssValueProps } from './useSafeArea';\n\nexport { SafeArea, type SafeAreaProps } from './SafeArea';\n\nexport { queryString } from './queryString';\n\nexport { debounce, type DebouncedFunction } from './debounce';\n","import { isValidElement, type ReactNode, type FC, Children } from 'react';\n\nexport type ChooseWhenProps = {\n condition: boolean;\n children: ReactNode;\n};\n\nexport type ChooseProps = {\n children: ReactNode;\n};\n\nexport type ChooseOtherwiseProps = {\n children: ReactNode;\n};\n\nexport function Choose({ children }: ChooseProps) {\n const validChildren = Children.toArray(children);\n\n const matchingChild = validChildren.find(\n (child) =>\n isValidElement<ChooseWhenProps>(child) &&\n child.type === Choose.When &&\n child.props.condition\n );\n\n if (matchingChild) {\n return matchingChild;\n }\n\n const otherwiseChild = validChildren.find(\n (child) => isValidElement(child) && child.type === Choose.Otherwise\n );\n\n return otherwiseChild || <></>;\n}\n\nconst ChooseWhen: FC<ChooseWhenProps> = ({ children }) => <>{children}</>;\nChooseWhen.displayName = 'Choose.When';\n\nconst ChooseOtherwise: FC<ChooseOtherwiseProps> = ({ children }) => (\n <>{children}</>\n);\n\nChoose.When = ChooseWhen;\nChoose.Otherwise = ChooseOtherwise;\n","// @see https://github.com/radix-ui/primitives/blob/main/packages/core/primitive/src/primitive.tsx\n\nexport function composeEventHandlers<E>(\n originalEventHandler?: (event: E) => void,\n ourEventHandler?: (event: E) => void,\n { checkForDefaultPrevented = true } = {}\n) {\n return function handleEvent(event: E) {\n originalEventHandler?.(event);\n\n if (\n checkForDefaultPrevented === false ||\n !(event as unknown as Event).defaultPrevented\n ) {\n return ourEventHandler?.(event);\n }\n };\n}\n","import {\n useMemo,\n createContext as createContextRaw,\n useContext as useContextRaw,\n type PropsWithChildren,\n} from 'react';\n\nexport function createContext<ContextValueType extends object | null>(\n rootComponentName: string,\n defaultContext?: ContextValueType\n) {\n const Context = createContextRaw<ContextValueType | undefined>(\n defaultContext\n );\n\n function Provider(props: PropsWithChildren<ContextValueType>) {\n const { children, ...contextValues } = props;\n\n const value = useMemo(\n () => contextValues,\n [contextValues]\n ) as ContextValueType;\n\n return <Context.Provider value={value}>{children}</Context.Provider>;\n }\n\n function useContext(consumerName: string) {\n const context = useContextRaw(Context);\n if (context == null) {\n throw new Error(\n `${consumerName}은 ${rootComponentName}하위에서 사용해야 합니다.`\n );\n }\n\n return context;\n }\n\n Provider.displayName = `${rootComponentName}Provider`;\n return [Provider, useContext] as const;\n}\n","export type VariableType = `--${string}`;\n\nexport function getVar(variable: VariableType, defaultValue?: string) {\n if (defaultValue) {\n return `var(${variable}, ${defaultValue})`;\n }\n\n return `var(${variable})`;\n}\n","import { type ReactNode } from 'react';\n\nexport type IfProps = {\n condition: boolean;\n children: ReactNode;\n};\n\nexport function If(props: IfProps) {\n const { condition, children } = props;\n\n return condition ? <>{children}</> : null;\n}\n","import { memo, type CSSProperties, type HTMLAttributes } from 'react';\nimport { styled } from 'styled-components';\n\nimport { coerceCssPixelValue, type CSSPixelValue } from './coerceCssPixelValue';\n\ntype Justify = CSSProperties['justifyContent'];\ntype Align = CSSProperties['alignItems'];\ntype Direction = CSSProperties['flexDirection'];\n\nexport type FlexProps = HTMLAttributes<HTMLDivElement> & {\n gap?: CSSPixelValue;\n justify?: Justify;\n align?: Align;\n direction?: Direction;\n};\n\nexport const Flex = memo(function Flex(props: FlexProps) {\n const {\n gap = 0,\n justify = 'center',\n align = 'center',\n direction = 'row',\n children,\n ...restProps\n } = props;\n\n return (\n <Container\n $gap={gap}\n $justify={justify}\n $align={align}\n $direction={direction}\n {...restProps}\n >\n {children}\n </Container>\n );\n});\n\nexport const Container = styled.div<{\n $gap: CSSPixelValue;\n $justify: Justify;\n $align: Align;\n $direction: Direction;\n}>`\n display: flex;\n flex-direction: ${({ $direction }) => $direction};\n gap: ${({ $gap }) => coerceCssPixelValue($gap)};\n align-items: ${({ $align }) => $align};\n justify-content: ${({ $justify }) => $justify};\n`;\n","export type CSSPixelValue = string | number;\n\nexport function coerceCssPixelValue(value: CSSPixelValue): string {\n return typeof value === 'string' ? value : `${value}px`;\n}\n","import { css } from 'styled-components';\n\nexport type MultiLineEllipsisProps = {\n line: number;\n};\n\nexport const ellipsis = css`\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n`;\n\nexport const multiLineEllipsis = ({ line }: MultiLineEllipsisProps) => css`\n display: -webkit-box;\n overflow: hidden;\n text-overflow: ellipsis;\n -webkit-line-clamp: ${line};\n -webkit-box-orient: vertical;\n`;\n","export type HexToRgbaProps = { hex: string; alpha?: number };\n\nfunction parseHexToDecimal(hex: string): number {\n return parseInt(hex, 16);\n}\n\nfunction validateHex(hex: string): string {\n const match = /^#?([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/.exec(hex);\n if (!match) {\n throw new Error(\n `Invalid hex value: \"${hex}\". Expected formats: \"#RGB\", \"RGB\", \"#RRGGBB\", or \"RRGGBB\".`\n );\n }\n return match[1];\n}\n\nfunction expandHex(hex: string): string {\n return hex.length === 3\n ? hex\n .split('')\n .map((char) => char + char)\n .join('')\n : hex;\n}\n\nfunction isValidAlpha(alpha: number): boolean {\n return alpha >= 0 && alpha <= 1;\n}\n\nexport function hexToRgba({ hex, alpha = 1 }: HexToRgbaProps): string {\n if (!isValidAlpha(alpha)) {\n throw new Error(\n `Invalid alpha value. Must be between 0 and 1, received: ${alpha}`\n );\n }\n\n const validatedHex = validateHex(hex);\n const expandedHex = expandHex(validatedHex);\n\n const r = parseHexToDecimal(expandedHex.slice(0, 2));\n const g = parseHexToDecimal(expandedHex.slice(2, 4));\n const b = parseHexToDecimal(expandedHex.slice(4, 6));\n\n return `rgba(${r},${g},${b},${alpha})`;\n}\n","export const COMPLETE_HANGUL_START_CHARCODE = '가'.charCodeAt(0);\nexport const COMPLETE_HANGUL_END_CHARCODE = '힣'.charCodeAt(0);\n\nexport const NUMBER_OF_JONGSEONG = 28;\nexport const NUMBER_OF_JUNGSEONG = 21;\n\nconst DISASSEMBLED_CONSONANTS_BY_CONSONANT = {\n '': '',\n ㄱ: 'ㄱ',\n ㄲ: 'ㄲ',\n ㄳ: 'ㄱㅅ',\n ㄴ: 'ㄴ',\n ㄵ: 'ㄴㅈ',\n ㄶ: 'ㄴㅎ',\n ㄷ: 'ㄷ',\n ㄸ: 'ㄸ',\n ㄹ: 'ㄹ',\n ㄺ: 'ㄹㄱ',\n ㄻ: 'ㄹㅁ',\n ㄼ: 'ㄹㅂ',\n ㄽ: 'ㄹㅅ',\n ㄾ: 'ㄹㅌ',\n ㄿ: 'ㄹㅍ',\n ㅀ: 'ㄹㅎ',\n ㅁ: 'ㅁ',\n ㅂ: 'ㅂ',\n ㅃ: 'ㅃ',\n ㅄ: 'ㅂㅅ',\n ㅅ: 'ㅅ',\n ㅆ: 'ㅆ',\n ㅇ: 'ㅇ',\n ㅈ: 'ㅈ',\n ㅉ: 'ㅉ',\n ㅊ: 'ㅊ',\n ㅋ: 'ㅋ',\n ㅌ: 'ㅌ',\n ㅍ: 'ㅍ',\n ㅎ: 'ㅎ',\n} as const;\n\nexport const JONGSEONGS = (\n [\n '',\n 'ㄱ',\n 'ㄲ',\n 'ㄳ',\n 'ㄴ',\n 'ㄵ',\n 'ㄶ',\n 'ㄷ',\n 'ㄹ',\n 'ㄺ',\n 'ㄻ',\n 'ㄼ',\n 'ㄽ',\n 'ㄾ',\n 'ㄿ',\n 'ㅀ',\n 'ㅁ',\n 'ㅂ',\n 'ㅄ',\n 'ㅅ',\n 'ㅆ',\n 'ㅇ',\n 'ㅈ',\n 'ㅊ',\n 'ㅋ',\n 'ㅌ',\n 'ㅍ',\n 'ㅎ',\n ] as const\n).map((consonant) => DISASSEMBLED_CONSONANTS_BY_CONSONANT[consonant]);\n","import {\n COMPLETE_HANGUL_END_CHARCODE,\n COMPLETE_HANGUL_START_CHARCODE,\n NUMBER_OF_JONGSEONG,\n} from './constants/josa';\n\n/**\n * 한글 음절의 받침 유무를 확인합니다.\n * @param str - 검사할 문자열\n * @returns 받침이 있으면 true, 없으면 false\n */\nexport function hasBatchim(str: string): boolean {\n const lastChar = str[str.length - 1];\n if (!lastChar) return false;\n\n const charCode = lastChar.charCodeAt(0);\n\n // 한글 완성형 문자인지 확인\n if (\n charCode < COMPLETE_HANGUL_START_CHARCODE ||\n charCode > COMPLETE_HANGUL_END_CHARCODE\n ) {\n return false;\n }\n\n // 받침 코드 계산\n const batchimCode =\n (charCode - COMPLETE_HANGUL_START_CHARCODE) % NUMBER_OF_JONGSEONG;\n\n return batchimCode > 0; // 받침이 있으면 true\n}\n","import { hasBatchim } from './hasBatchim';\n\ntype JosaOption = '이/가' | '을/를' | '은/는';\n\ntype ExtractJosaOption<T> = T extends `${infer A}/${infer B}` ? A | B : never;\n\nexport type JosaProps<U extends JosaOption> = {\n word: string;\n josa: U;\n};\n\n/**\n * 주어진 단어와 조사 옵션을 기반으로 올바른 조사를 반환합니다.\n * @returns 단어와 올바른 조사가 결합된 문자열\n */\nexport function josa<U extends JosaOption>(\n props: JosaProps<U>\n): `${JosaProps<U>['word']}${ExtractJosaOption<U>}` {\n const { word, josa } = props;\n\n if (!word) {\n return word as `${JosaProps<U>['word']}${ExtractJosaOption<U>}`;\n }\n\n return `${word}${josaPicker({\n word,\n josa,\n })}` as `${JosaProps<U>['word']}${ExtractJosaOption<U>}`;\n}\n\n/**\n * 주어진 단어와 조사 옵션을 기반으로 올바른 조사를 선택합니다.\n * @returns 올바른 조사\n */\nfunction josaPicker<U extends JosaOption>(\n props: JosaProps<U>\n): ExtractJosaOption<U> {\n const { word, josa } = props;\n\n if (!word) {\n return josa.split('/')[0] as ExtractJosaOption<U>;\n }\n\n const has받침 = hasBatchim(word);\n const index = has받침 ? 0 : 1;\n\n return josa.split('/')[index] as ExtractJosaOption<U>;\n}\n\njosa.pick = josaPicker;\n","/**\n *\n * @see 이메일 주소가 RFC 5322 표준을 따르는지 검사합니다. {@link https://emailregex.com/}\n */\nfunction isEmail(email: string) {\n const regExp =\n /^(([^<>()\\[\\]\\\\.,;:\\s@\"]+(\\.[^<>()\\[\\]\\\\.,;:\\s@\"]+)*)|(\".+\"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}])|(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,}))$/;\n return regExp.test(email);\n}\n\nfunction isPhoneNumber(phoneNumber: string) {\n // 하이픈 있는 형식\n const regExpWithHyphen = /^01([0|1|6|7|8|9])-([0-9]{3,4})-([0-9]{4})$/;\n // 하이픈 없는 형식\n const regExpWithoutHyphen = /^01([0|1|6|7|8|9])([0-9]{3,4})([0-9]{4})$/;\n\n return (\n regExpWithHyphen.test(phoneNumber) || regExpWithoutHyphen.test(phoneNumber)\n );\n}\n\nexport const Validate = {\n email: isEmail,\n phoneNumber: isPhoneNumber,\n};\n","import { memo, type HTMLAttributes } from 'react';\nimport { styled } from 'styled-components';\n\nimport { coerceCssPixelValue, type CSSPixelValue } from './coerceCssPixelValue';\n\ntype AxisDirection = 'vertical' | 'horizontal';\n\nexport type SpacingProps = Omit<HTMLAttributes<HTMLDivElement>, 'children'> & {\n direction?: AxisDirection;\n size: CSSPixelValue;\n};\n\nexport const Spacing = memo(function Spacing(props: SpacingProps) {\n const { direction = 'vertical', size, ...restProps } = props;\n\n return (\n <SpacingContainer $direction={direction} $size={size} {...restProps} />\n );\n});\n\nconst SpacingContainer = styled.div<{\n $direction: SpacingProps['direction'];\n $size: SpacingProps['size'];\n}>`\n flex: none;\n width: ${({ $direction, $size }) =>\n $direction === 'horizontal' ? coerceCssPixelValue($size) : undefined};\n height: ${({ $direction, $size }) =>\n $direction === 'vertical' ? coerceCssPixelValue($size) : undefined};\n`;\n","import { coerceCssPixelValue, type CSSPixelValue } from './coerceCssPixelValue';\n\nexport type SafeAreaCssValueProps = {\n top?: CSSPixelValue;\n bottom?: CSSPixelValue;\n left?: CSSPixelValue;\n right?: CSSPixelValue;\n};\n\nconst useSafeArea = ({\n top: T = 0,\n bottom: B = 0,\n left: L = 0,\n right: R = 0,\n}: SafeAreaCssValueProps = {}) => {\n const top = `max(${coerceCssPixelValue(T)}, env(safe-area-inset-top))`;\n const bottom = `max(${coerceCssPixelValue(B)}, env(safe-area-inset-bottom))`;\n const left = `max(${coerceCssPixelValue(L)}, env(safe-area-inset-left))`;\n const right = `max(${coerceCssPixelValue(R)}, env(safe-area-inset-right))`;\n\n return { top, bottom, left, right };\n};\n\nexport { useSafeArea };\n","import React, {\n memo,\n type ComponentPropsWithoutRef,\n type ReactNode,\n} from 'react';\n\nimport { Spacing } from './Spacing';\nimport { useSafeArea } from './useSafeArea';\n\nexport type SafeAreaProps<T extends React.ElementType = 'div'> = {\n as?: T;\n children: ReactNode;\n} & ComponentPropsWithoutRef<T>;\n\nexport const SafeArea = <T extends React.ElementType = 'div'>({\n as,\n children,\n ...props\n}: SafeAreaProps<T>) => {\n const Component = as || 'div';\n\n return (\n <Component {...props}>\n <SafeAreaTop />\n {children}\n <SafeAreaBottom />\n </Component>\n );\n};\n\nconst SafeAreaTop = memo(function SafeAreaTop(\n props: Omit<ComponentPropsWithoutRef<typeof Spacing>, 'size'>\n) {\n const { top } = useSafeArea();\n return <Spacing {...props} size={top} />;\n});\n\nconst SafeAreaBottom = memo(function SafeAreaBottom(\n props: Omit<ComponentPropsWithoutRef<typeof Spacing>, 'size'>\n) {\n const { bottom } = useSafeArea();\n return <Spacing {...props} size={bottom} />;\n});\n\nSafeArea.Top = SafeAreaTop;\nSafeArea.Bottom = SafeAreaBottom;\n","/**\n * @description 쿼리 스트링을 생성합니다.\n * @example createSearchParamString({ a: 1, b: 2, c: 3 }) // 'a=1&b=2&c=3'\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction createSearchParamString(params: Record<string, any>) {\n return (\n new URLSearchParams(\n Object.entries(params)\n .filter(([, value]) => value != null)\n .map(([key, value]) => {\n if (Array.isArray(value)) {\n return value.map((x) => [key, x]);\n }\n return [[key, value]];\n })\n .flat()\n )\n .toString()\n // Convert space characters to '%20' according to RFC3986 spec, from RFC1738.\n .replace(/\\+/g, '%20')\n );\n}\n\n/**\n * @description 물음표를 포함한 쿼리 스트링을 생성합니다.\n * @example createQueryString({ a: 1, b: 2, c: 3 }) // '?a=1&b=2&c=3'\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction createQueryString(params: Record<string, any>) {\n const queryString = createSearchParamString(params);\n\n if (queryString === '') {\n return '';\n }\n\n return `?${queryString}`;\n}\n\n/**\n * @description 이터러블에서 키와 값을 가진 객체로 변환합니다.\n * @example fromEntries([['a', 1], ['b', 2], ['c', 3]]) // { a: 1, b: 2, c: 3 }\n */\nfunction fromEntries<T extends readonly [string | number, unknown]>(\n iterable: Iterable<T>\n) {\n const result: Record<string | number | symbol, T[1]> = {};\n\n for (const [key, value] of Array.from(iterable)) {\n if (result[key]) {\n if (Array.isArray(result[key])) {\n (result[key] as Array<string | number>).push(value as string | number);\n } else {\n result[key] = [result[key], value];\n }\n } else {\n result[key] = value;\n }\n }\n\n return result;\n}\n\n/**\n * @description 쿼리 스트링을 객체로 변환합니다.\n * @example parseQueryString('?a=1&b=2&c=3') // { a: '1', b: '2', c: '3' }\n */\nfunction parseQueryString<Result = Record<string, string>>(\n queryString: string = typeof location !== 'undefined' ? location.search : ''\n): Result {\n const query = queryString.trim().replace(/^[?#&]/, '');\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return fromEntries(new URLSearchParams(query)) as any;\n}\n\n/**\n * @description 쿼리 스트링에서 특정 키의 값을 가져옵니다.\n *\n * @param name 가져올 쿼리 스트링의 키\n * @param parser 가져온 값을 파싱할 함수\n * @returns 파싱된 값\n *\n * @example\n * url: 'http://example.com/?a=1'\n * getQueryString('a') // '1'\n * getQueryString('a', parseInt) // 1\n * getQueryString('b') // undefined\n * getQueryString('b', parseInt) // undefined\n */\nfunction getQueryString(name: string): string | undefined;\nfunction getQueryString<T>(\n name: string,\n parser: (val: string) => T\n): T | undefined;\nfunction getQueryString<T = string>(name: string, parser?: (val: string) => T) {\n const value = queryString.parse<{ [name: string]: string | undefined }>()[\n name\n ];\n\n if (parser == null || value == null) {\n return value;\n } else {\n return parser(value);\n }\n}\n\n/**\n * @description 기존 쿼리 스트링에 새로운 쿼리 스트링을 추가합니다.\n * @example setQueryString({ qs: '?a=1', key: 'b', value: '2' }) // '?a=1&b=2'\n */\nfunction setQueryString({\n qs,\n key,\n value,\n}: {\n qs: string;\n key: string;\n value: string;\n}) {\n const parsed = parseQueryString(qs);\n\n return createQueryString({\n ...parsed,\n [key]: value,\n });\n}\n\nexport const queryString = {\n create: createQueryString,\n parse: parseQueryString,\n get: getQueryString,\n set: setQueryString,\n};\n","/* eslint-disable @typescript-eslint/no-explicit-any */\n\nexport type DebouncedFunction<F extends (...args: any[]) => void> = {\n (...args: Parameters<F>): void;\n\n /**\n * 디바운스된 함수의 모든 예약된 실행을 취소합니다.\n * 이 메서드는 활성 타이머를 제거하고 저장된 컨텍스트나 인수를 재설정합니다.\n */\n cancel: () => void;\n\n /**\n * 예약된 실행이 있는 경우 디바운스된 함수를 즉시 호출합니다.\n * 이 메서드는 현재 타이머를 취소하여 함수가 즉시 실행되도록 합니다.\n */\n flush: () => void;\n};\n\n/**\n * @example\n * const debouncedFunction = debounce(() => {\n * console.log('Function executed');\n * }, 1000);\n *\n */\nexport function debounce<F extends (...args: any[]) => void>(\n func: F,\n debounceMs: number\n): DebouncedFunction<F> {\n let pendingCall: { thisArg: any; args: Parameters<F> } | null = null;\n\n const invoke = () => {\n if (pendingCall !== null) {\n const { thisArg, args } = pendingCall;\n func.apply(thisArg, args);\n pendingCall = null;\n }\n };\n\n const onTimerEnd = () => {\n invoke();\n cancel();\n };\n\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\n\n const schedule = () => {\n if (timeoutId != null) {\n clearTimeout(timeoutId);\n }\n\n timeoutId = setTimeout(() => {\n timeoutId = null;\n onTimerEnd();\n }, debounceMs);\n };\n\n const cancelTimer = () => {\n if (timeoutId !== null) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n };\n\n const cancel = () => {\n cancelTimer();\n pendingCall = null;\n };\n\n const flush = () => {\n cancelTimer();\n invoke();\n };\n\n const debounced = function (this: any, ...args: Parameters<F>) {\n pendingCall = { thisArg: this, args };\n schedule();\n };\n\n debounced.cancel = cancel;\n debounced.flush = flush;\n\n return debounced;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,mBAAkE;AAiCvC;AAlBpB,SAAS,OAAO,EAAE,SAAS,GAAgB;AAChD,QAAM,gBAAgB,sBAAS,QAAQ,QAAQ;AAE/C,QAAM,gBAAgB,cAAc;AAAA,IAClC,CAAC,cACC,6BAAgC,KAAK,KACrC,MAAM,SAAS,OAAO,QACtB,MAAM,MAAM;AAAA,EAChB;AAEA,MAAI,eAAe;AACjB,WAAO;AAAA,EACT;AAEA,QAAM,iBAAiB,cAAc;AAAA,IACnC,CAAC,cAAU,6BAAe,KAAK,KAAK,MAAM,SAAS,OAAO;AAAA,EAC5D;AAEA,SAAO,kBAAkB,2EAAE;AAC7B;AAEA,IAAM,aAAkC,CAAC,EAAE,SAAS,MAAM,2EAAG,UAAS;AACtE,WAAW,cAAc;AAEzB,IAAM,kBAA4C,CAAC,EAAE,SAAS,MAC5D,2EAAG,UAAS;AAGd,OAAO,OAAO;AACd,OAAO,YAAY;;;AC1CZ,SAAS,qBACd,sBACA,iBACA,EAAE,2BAA2B,KAAK,IAAI,CAAC,GACvC;AACA,SAAO,SAAS,YAAY,OAAU;AACpC,2BAAuB,KAAK;AAE5B,QACE,6BAA6B,SAC7B,CAAE,MAA2B,kBAC7B;AACA,aAAO,kBAAkB,KAAK;AAAA,IAChC;AAAA,EACF;AACF;;;ACjBA,IAAAA,gBAKO;AAkBI,IAAAC,sBAAA;AAhBJ,SAAS,cACd,mBACA,gBACA;AACA,QAAM,cAAU,cAAAC;AAAA,IACd;AAAA,EACF;AAEA,WAAS,SAAS,OAA4C;AAC5D,UAAM,EAAE,UAAU,GAAG,cAAc,IAAI;AAEvC,UAAM,YAAQ;AAAA,MACZ,MAAM;AAAA,MACN,CAAC,aAAa;AAAA,IAChB;AAEA,WAAO,6CAAC,QAAQ,UAAR,EAAiB,OAAe,UAAS;AAAA,EACnD;AAEA,WAAS,WAAW,cAAsB;AACxC,UAAM,cAAU,cAAAC,YAAc,OAAO;AACrC,QAAI,WAAW,MAAM;AACnB,YAAM,IAAI;AAAA,QACR,GAAG,sBAAiB;AAAA,MACtB;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAEA,WAAS,cAAc,GAAG;AAC1B,SAAO,CAAC,UAAU,UAAU;AAC9B;;;ACrCO,SAAS,OAAO,UAAwB,cAAuB;AACpE,MAAI,cAAc;AAChB,WAAO,OAAO,aAAa;AAAA,EAC7B;AAEA,SAAO,OAAO;AAChB;;;ACEqB,IAAAC,sBAAA;AAHd,SAAS,GAAG,OAAgB;AACjC,QAAM,EAAE,WAAW,SAAS,IAAI;AAEhC,SAAO,YAAY,6EAAG,UAAS,IAAM;AACvC;;;ACXA,IAAAC,gBAA8D;AAC9D,+BAAuB;;;ACChB,SAAS,oBAAoB,OAA8B;AAChE,SAAO,OAAO,UAAU,WAAW,QAAQ,GAAG;AAChD;;;ADuBI,IAAAC,sBAAA;AAXG,IAAM,WAAO,oBAAK,SAASC,MAAK,OAAkB;AACvD,QAAM;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ;AAAA,IACA,GAAG;AAAA,EACL,IAAI;AAEJ,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAM;AAAA,MACN,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,YAAY;AAAA,MACX,GAAG;AAAA,MAEH;AAAA;AAAA,EACH;AAEJ,CAAC;AAEM,IAAM,YAAY,gCAAO;AAAA;AAAA,oBAOZ,CAAC,EAAE,WAAW,MAAM;AAAA,SAC/B,CAAC,EAAE,KAAK,MAAM,oBAAoB,IAAI;AAAA,iBAC9B,CAAC,EAAE,OAAO,MAAM;AAAA,qBACZ,CAAC,EAAE,SAAS,MAAM;AAAA;;;AEjDvC,IAAAC,4BAAoB;AAMb,IAAM,WAAW;AAAA;AAAA;AAAA;AAAA;AAMjB,IAAM,oBAAoB,CAAC,EAAE,KAAK,MAA8B;AAAA;AAAA;AAAA;AAAA,wBAI/C;AAAA;AAAA;;;ACdxB,SAAS,kBAAkB,KAAqB;AAC9C,SAAO,SAAS,KAAK,EAAE;AACzB;AAEA,SAAS,YAAY,KAAqB;AACxC,QAAM,QAAQ,sCAAsC,KAAK,GAAG;AAC5D,MAAI,CAAC,OAAO;AACV,UAAM,IAAI;AAAA,MACR,uBAAuB;AAAA,IACzB;AAAA,EACF;AACA,SAAO,MAAM,CAAC;AAChB;AAEA,SAAS,UAAU,KAAqB;AACtC,SAAO,IAAI,WAAW,IAClB,IACG,MAAM,EAAE,EACR,IAAI,CAAC,SAAS,OAAO,IAAI,EACzB,KAAK,EAAE,IACV;AACN;AAEA,SAAS,aAAa,OAAwB;AAC5C,SAAO,SAAS,KAAK,SAAS;AAChC;AAEO,SAAS,UAAU,EAAE,KAAK,QAAQ,EAAE,GAA2B;AACpE,MAAI,CAAC,aAAa,KAAK,GAAG;AACxB,UAAM,IAAI;AAAA,MACR,2DAA2D;AAAA,IAC7D;AAAA,EACF;AAEA,QAAM,eAAe,YAAY,GAAG;AACpC,QAAM,cAAc,UAAU,YAAY;AAE1C,QAAM,IAAI,kBAAkB,YAAY,MAAM,GAAG,CAAC,CAAC;AACnD,QAAM,IAAI,kBAAkB,YAAY,MAAM,GAAG,CAAC,CAAC;AACnD,QAAM,IAAI,kBAAkB,YAAY,MAAM,GAAG,CAAC,CAAC;AAEnD,SAAO,QAAQ,KAAK,KAAK,KAAK;AAChC;;;AC5CO,IAAM,iCAAiC,SAAI,WAAW,CAAC;AACvD,IAAM,+BAA+B,SAAI,WAAW,CAAC;AAErD,IAAM,sBAAsB;AAGnC,IAAM,uCAAuC;AAAA,EAC3C,IAAI;AAAA,EACJ,QAAG;AAAA,EACH,QAAG;AAAA,EACH,QAAG;AAAA,EACH,QAAG;AAAA,EACH,QAAG;AAAA,EACH,QAAG;AAAA,EACH,QAAG;AAAA,EACH,QAAG;AAAA,EACH,QAAG;AAAA,EACH,QAAG;AAAA,EACH,QAAG;AAAA,EACH,QAAG;AAAA,EACH,QAAG;AAAA,EACH,QAAG;AAAA,EACH,QAAG;AAAA,EACH,QAAG;AAAA,EACH,QAAG;AAAA,EACH,QAAG;AAAA,EACH,QAAG;AAAA,EACH,QAAG;AAAA,EACH,QAAG;AAAA,EACH,QAAG;AAAA,EACH,QAAG;AAAA,EACH,QAAG;AAAA,EACH,QAAG;AAAA,EACH,QAAG;AAAA,EACH,QAAG;AAAA,EACH,QAAG;AAAA,EACH,QAAG;AAAA,EACH,QAAG;AACL;AAEO,IAAM,aACX;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,EACA,IAAI,CAAC,cAAc,qCAAqC,SAAS,CAAC;;;AC5D7D,SAAS,WAAW,KAAsB;AAC/C,QAAM,WAAW,IAAI,IAAI,SAAS,CAAC;AACnC,MAAI,CAAC;AAAU,WAAO;AAEtB,QAAM,WAAW,SAAS,WAAW,CAAC;AAGtC,MACE,WAAW,kCACX,WAAW,8BACX;AACA,WAAO;AAAA,EACT;AAGA,QAAM,eACH,WAAW,kCAAkC;AAEhD,SAAO,cAAc;AACvB;;;ACfO,SAAS,KACd,OACkD;AAClD,QAAM,EAAE,MAAM,MAAAC,MAAK,IAAI;AAEvB,MAAI,CAAC,MAAM;AACT,WAAO;AAAA,EACT;AAEA,SAAO,GAAG,OAAO,WAAW;AAAA,IAC1B;AAAA,IACA,MAAAA;AAAA,EACF,CAAC;AACH;AAMA,SAAS,WACP,OACsB;AACtB,QAAM,EAAE,MAAM,MAAAA,MAAK,IAAI;AAEvB,MAAI,CAAC,MAAM;AACT,WAAOA,MAAK,MAAM,GAAG,EAAE,CAAC;AAAA,EAC1B;AAEA,QAAM,kBAAQ,WAAW,IAAI;AAC7B,QAAM,QAAQ,kBAAQ,IAAI;AAE1B,SAAOA,MAAK,MAAM,GAAG,EAAE,KAAK;AAC9B;AAEA,KAAK,OAAO;;;AC7CZ,SAAS,QAAQ,OAAe;AAC9B,QAAM,SACJ;AACF,SAAO,OAAO,KAAK,KAAK;AAC1B;AAEA,SAAS,cAAc,aAAqB;AAE1C,QAAM,mBAAmB;AAEzB,QAAM,sBAAsB;AAE5B,SACE,iBAAiB,KAAK,WAAW,KAAK,oBAAoB,KAAK,WAAW;AAE9E;AAEO,IAAM,WAAW;AAAA,EACtB,OAAO;AAAA,EACP,aAAa;AACf;;;ACxBA,IAAAC,gBAA0C;AAC1C,IAAAC,4BAAuB;AAenB,IAAAC,sBAAA;AAJG,IAAM,cAAU,oBAAK,SAASC,SAAQ,OAAqB;AAChE,QAAM,EAAE,YAAY,YAAY,MAAM,GAAG,UAAU,IAAI;AAEvD,SACE,6CAAC,oBAAiB,YAAY,WAAW,OAAO,MAAO,GAAG,WAAW;AAEzE,CAAC;AAED,IAAM,mBAAmB,iCAAO;AAAA;AAAA,WAKrB,CAAC,EAAE,YAAY,MAAM,MAC5B,eAAe,eAAe,oBAAoB,KAAK,IAAI;AAAA,YACnD,CAAC,EAAE,YAAY,MAAM,MAC7B,eAAe,aAAa,oBAAoB,KAAK,IAAI;AAAA;;;ACnB7D,IAAM,cAAc,CAAC;AAAA,EACnB,KAAK,IAAI;AAAA,EACT,QAAQ,IAAI;AAAA,EACZ,MAAM,IAAI;AAAA,EACV,OAAO,IAAI;AACb,IAA2B,CAAC,MAAM;AAChC,QAAM,MAAM,OAAO,oBAAoB,CAAC;AACxC,QAAM,SAAS,OAAO,oBAAoB,CAAC;AAC3C,QAAM,OAAO,OAAO,oBAAoB,CAAC;AACzC,QAAM,QAAQ,OAAO,oBAAoB,CAAC;AAE1C,SAAO,EAAE,KAAK,QAAQ,MAAM,MAAM;AACpC;;;ACrBA,IAAAC,gBAIO;AAkBH,IAAAC,sBAAA;AARG,IAAM,WAAW,CAAsC;AAAA,EAC5D;AAAA,EACA;AAAA,EACA,GAAG;AACL,MAAwB;AACtB,QAAM,YAAY,MAAM;AAExB,SACE,8CAAC,aAAW,GAAG,OACb;AAAA,iDAAC,eAAY;AAAA,IACZ;AAAA,IACD,6CAAC,kBAAe;AAAA,KAClB;AAEJ;AAEA,IAAM,kBAAc,oBAAK,SAASC,aAChC,OACA;AACA,QAAM,EAAE,IAAI,IAAI,YAAY;AAC5B,SAAO,6CAAC,WAAS,GAAG,OAAO,MAAM,KAAK;AACxC,CAAC;AAED,IAAM,qBAAiB,oBAAK,SAASC,gBACnC,OACA;AACA,QAAM,EAAE,OAAO,IAAI,YAAY;AAC/B,SAAO,6CAAC,WAAS,GAAG,OAAO,MAAM,QAAQ;AAC3C,CAAC;AAED,SAAS,MAAM;AACf,SAAS,SAAS;;;ACxClB,SAAS,wBAAwB,QAA6B;AAC5D,SACE,IAAI;AAAA,IACF,OAAO,QAAQ,MAAM,EAClB,OAAO,CAAC,CAAC,EAAE,KAAK,MAAM,SAAS,IAAI,EACnC,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM;AACrB,UAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,eAAO,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAAA,MAClC;AACA,aAAO,CAAC,CAAC,KAAK,KAAK,CAAC;AAAA,IACtB,CAAC,EACA,KAAK;AAAA,EACV,EACG,SAAS,EAET,QAAQ,OAAO,KAAK;AAE3B;AAOA,SAAS,kBAAkB,QAA6B;AACtD,QAAMC,eAAc,wBAAwB,MAAM;AAElD,MAAIA,iBAAgB,IAAI;AACtB,WAAO;AAAA,EACT;AAEA,SAAO,IAAIA;AACb;AAMA,SAAS,YACP,UACA;AACA,QAAM,SAAiD,CAAC;AAExD,aAAW,CAAC,KAAK,KAAK,KAAK,MAAM,KAAK,QAAQ,GAAG;AAC/C,QAAI,OAAO,GAAG,GAAG;AACf,UAAI,MAAM,QAAQ,OAAO,GAAG,CAAC,GAAG;AAC9B,QAAC,OAAO,GAAG,EAA6B,KAAK,KAAwB;AAAA,MACvE,OAAO;AACL,eAAO,GAAG,IAAI,CAAC,OAAO,GAAG,GAAG,KAAK;AAAA,MACnC;AAAA,IACF,OAAO;AACL,aAAO,GAAG,IAAI;AAAA,IAChB;AAAA,EACF;AAEA,SAAO;AACT;AAMA,SAAS,iBACPA,eAAsB,OAAO,aAAa,cAAc,SAAS,SAAS,IAClE;AACR,QAAM,QAAQA,aAAY,KAAK,EAAE,QAAQ,UAAU,EAAE;AAGrD,SAAO,YAAY,IAAI,gBAAgB,KAAK,CAAC;AAC/C;AAqBA,SAAS,eAA2B,MAAc,QAA6B;AAC7E,QAAM,QAAQ,YAAY,MAA8C,EACtE,IACF;AAEA,MAAI,UAAU,QAAQ,SAAS,MAAM;AACnC,WAAO;AAAA,EACT,OAAO;AACL,WAAO,OAAO,KAAK;AAAA,EACrB;AACF;AAMA,SAAS,eAAe;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,QAAM,SAAS,iBAAiB,EAAE;AAElC,SAAO,kBAAkB;AAAA,IACvB,GAAG;AAAA,IACH,CAAC,GAAG,GAAG;AAAA,EACT,CAAC;AACH;AAEO,IAAM,cAAc;AAAA,EACzB,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,KAAK;AAAA,EACL,KAAK;AACP;;;AC5GO,SAAS,SACd,MACA,YACsB;AACtB,MAAI,cAA4D;AAEhE,QAAM,SAAS,MAAM;AACnB,QAAI,gBAAgB,MAAM;AACxB,YAAM,EAAE,SAAS,KAAK,IAAI;AAC1B,WAAK,MAAM,SAAS,IAAI;AACxB,oBAAc;AAAA,IAChB;AAAA,EACF;AAEA,QAAM,aAAa,MAAM;AACvB,WAAO;AACP,WAAO;AAAA,EACT;AAEA,MAAI,YAAkD;AAEtD,QAAM,WAAW,MAAM;AACrB,QAAI,aAAa,MAAM;AACrB,mBAAa,SAAS;AAAA,IACxB;AAEA,gBAAY,WAAW,MAAM;AAC3B,kBAAY;AACZ,iBAAW;AAAA,IACb,GAAG,UAAU;AAAA,EACf;AAEA,QAAM,cAAc,MAAM;AACxB,QAAI,cAAc,MAAM;AACtB,mBAAa,SAAS;AACtB,kBAAY;AAAA,IACd;AAAA,EACF;AAEA,QAAM,SAAS,MAAM;AACnB,gBAAY;AACZ,kBAAc;AAAA,EAChB;AAEA,QAAM,QAAQ,MAAM;AAClB,gBAAY;AACZ,WAAO;AAAA,EACT;AAEA,QAAM,YAAY,YAAwB,MAAqB;AAC7D,kBAAc,EAAE,SAAS,MAAM,KAAK;AACpC,aAAS;AAAA,EACX;AAEA,YAAU,SAAS;AACnB,YAAU,QAAQ;AAElB,SAAO;AACT;","names":["import_react","import_jsx_runtime","createContextRaw","useContextRaw","import_jsx_runtime","import_react","import_jsx_runtime","Flex","import_styled_components","josa","import_react","import_styled_components","import_jsx_runtime","Spacing","import_react","import_jsx_runtime","SafeAreaTop","SafeAreaBottom","queryString"]}
package/dist/index.mjs CHANGED
@@ -1,6 +1,18 @@
1
+ import {
2
+ josa
3
+ } from "./chunk-SJJHTYZC.mjs";
4
+ import {
5
+ queryString
6
+ } from "./chunk-U4T3KW7L.mjs";
7
+ import {
8
+ composeEventHandlers
9
+ } from "./chunk-QD5QDTUG.mjs";
1
10
  import {
2
11
  createContext
3
12
  } from "./chunk-Z4QPISK7.mjs";
13
+ import {
14
+ debounce
15
+ } from "./chunk-RWZLYDXE.mjs";
4
16
  import {
5
17
  ellipsis,
6
18
  multiLineEllipsis
@@ -8,17 +20,11 @@ import {
8
20
  import {
9
21
  getVar
10
22
  } from "./chunk-WHYNBO2G.mjs";
11
- import {
12
- hexToRgba
13
- } from "./chunk-OIJ4AVT7.mjs";
14
- import {
15
- josa
16
- } from "./chunk-SJJHTYZC.mjs";
17
23
  import "./chunk-C7VOPXT2.mjs";
18
24
  import "./chunk-GQPOYY4X.mjs";
19
25
  import {
20
- queryString
21
- } from "./chunk-U4T3KW7L.mjs";
26
+ hexToRgba
27
+ } from "./chunk-OIJ4AVT7.mjs";
22
28
  import {
23
29
  Choose
24
30
  } from "./chunk-7WNTKDNW.mjs";
@@ -30,20 +36,17 @@ import {
30
36
  } from "./chunk-UFRXNT2I.mjs";
31
37
  import {
32
38
  SafeArea
33
- } from "./chunk-WOYL5AA5.mjs";
39
+ } from "./chunk-HLTXXENG.mjs";
34
40
  import {
35
41
  useSafeArea
36
42
  } from "./chunk-FUGA35PJ.mjs";
37
43
  import {
38
44
  Spacing
39
- } from "./chunk-LKUAG7PE.mjs";
45
+ } from "./chunk-DD3KGUQX.mjs";
40
46
  import {
41
47
  Validate
42
48
  } from "./chunk-R23KSR7N.mjs";
43
49
  import "./chunk-T7K7QYTL.mjs";
44
- import {
45
- composeEventHandlers
46
- } from "./chunk-QD5QDTUG.mjs";
47
50
  export {
48
51
  Choose,
49
52
  Flex,
@@ -53,6 +56,7 @@ export {
53
56
  Validate,
54
57
  composeEventHandlers,
55
58
  createContext,
59
+ debounce,
56
60
  ellipsis,
57
61
  getVar,
58
62
  hexToRgba,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@basiln/utils",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "exports": {
5
5
  ".": "./src/index.ts",
6
6
  "./package.json": "./package.json"
@@ -47,5 +47,6 @@
47
47
  "react": "^18",
48
48
  "react-dom": "^18",
49
49
  "styled-components": "^6"
50
- }
50
+ },
51
+ "dependencies": {}
51
52
  }
package/src/Format.ts ADDED
@@ -0,0 +1,54 @@
1
+ type Value = number | string;
2
+
3
+ export const Format = {
4
+ phone: formatPhoneNumber,
5
+ removeHyphen,
6
+ commaize: formatCommaizeNumber,
7
+ padTime,
8
+ };
9
+
10
+ /**
11
+ * 숫자를 전화번호 형식으로 변환합니다.
12
+ * @example Format.phone('01012345678') // '010-1234-5678'
13
+ */
14
+ function formatPhoneNumber(phoneNumber: string) {
15
+ return phoneNumber
16
+ .replace(/[^0-9]/g, '')
17
+ .replace(/^(\d{0,3})(\d{0,4})(\d{0,4})$/g, '$1-$2-$3')
18
+ .replace(/(-{1,2})$/g, '');
19
+ }
20
+
21
+ /**
22
+ * 하이픈을 제거합니다.
23
+ * @example Format.removeHyphen('01012345678') // '01012345678'
24
+ */
25
+ function removeHyphen(value: string) {
26
+ return value.replaceAll('-', '');
27
+ }
28
+
29
+ /**
30
+ * 숫자를 콤마로 구분합니다.
31
+ * https://www.slash.page/ko/libraries/common/utils/src/Numbers_commaizeNumber.i18n
32
+ *
33
+ * @example
34
+ * Format.commaize('123456') // '123,456'
35
+ * Format.commaize(123456) // '123,456'
36
+ */
37
+ function formatCommaizeNumber(value: Value) {
38
+ const numStr = String(value);
39
+ const decimalPointIndex = numStr.indexOf('.');
40
+ const commaizeRegExp = /(\d)(?=(\d\d\d)+(?!\d))/g;
41
+
42
+ return decimalPointIndex > -1
43
+ ? numStr.slice(0, decimalPointIndex).replace(commaizeRegExp, '$1,') +
44
+ numStr.slice(decimalPointIndex)
45
+ : numStr.replace(commaizeRegExp, '$1,');
46
+ }
47
+
48
+ /**
49
+ * 숫자를 2자리 수 형태로 변환합니다.
50
+ * @example Format.padTime(9) // '09'
51
+ */
52
+ function padTime(value: Value) {
53
+ return String(value).padStart(2, '0');
54
+ }
package/src/Spacing.tsx CHANGED
@@ -11,7 +11,7 @@ export type SpacingProps = Omit<HTMLAttributes<HTMLDivElement>, 'children'> & {
11
11
  };
12
12
 
13
13
  export const Spacing = memo(function Spacing(props: SpacingProps) {
14
- const { direction = 'horizontal', size, ...restProps } = props;
14
+ const { direction = 'vertical', size, ...restProps } = props;
15
15
 
16
16
  return (
17
17
  <SpacingContainer $direction={direction} $size={size} {...restProps} />
@@ -0,0 +1,84 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+
3
+ export type DebouncedFunction<F extends (...args: any[]) => void> = {
4
+ (...args: Parameters<F>): void;
5
+
6
+ /**
7
+ * 디바운스된 함수의 모든 예약된 실행을 취소합니다.
8
+ * 이 메서드는 활성 타이머를 제거하고 저장된 컨텍스트나 인수를 재설정합니다.
9
+ */
10
+ cancel: () => void;
11
+
12
+ /**
13
+ * 예약된 실행이 있는 경우 디바운스된 함수를 즉시 호출합니다.
14
+ * 이 메서드는 현재 타이머를 취소하여 함수가 즉시 실행되도록 합니다.
15
+ */
16
+ flush: () => void;
17
+ };
18
+
19
+ /**
20
+ * @example
21
+ * const debouncedFunction = debounce(() => {
22
+ * console.log('Function executed');
23
+ * }, 1000);
24
+ *
25
+ */
26
+ export function debounce<F extends (...args: any[]) => void>(
27
+ func: F,
28
+ debounceMs: number
29
+ ): DebouncedFunction<F> {
30
+ let pendingCall: { thisArg: any; args: Parameters<F> } | null = null;
31
+
32
+ const invoke = () => {
33
+ if (pendingCall !== null) {
34
+ const { thisArg, args } = pendingCall;
35
+ func.apply(thisArg, args);
36
+ pendingCall = null;
37
+ }
38
+ };
39
+
40
+ const onTimerEnd = () => {
41
+ invoke();
42
+ cancel();
43
+ };
44
+
45
+ let timeoutId: ReturnType<typeof setTimeout> | null = null;
46
+
47
+ const schedule = () => {
48
+ if (timeoutId != null) {
49
+ clearTimeout(timeoutId);
50
+ }
51
+
52
+ timeoutId = setTimeout(() => {
53
+ timeoutId = null;
54
+ onTimerEnd();
55
+ }, debounceMs);
56
+ };
57
+
58
+ const cancelTimer = () => {
59
+ if (timeoutId !== null) {
60
+ clearTimeout(timeoutId);
61
+ timeoutId = null;
62
+ }
63
+ };
64
+
65
+ const cancel = () => {
66
+ cancelTimer();
67
+ pendingCall = null;
68
+ };
69
+
70
+ const flush = () => {
71
+ cancelTimer();
72
+ invoke();
73
+ };
74
+
75
+ const debounced = function (this: any, ...args: Parameters<F>) {
76
+ pendingCall = { thisArg: this, args };
77
+ schedule();
78
+ };
79
+
80
+ debounced.cancel = cancel;
81
+ debounced.flush = flush;
82
+
83
+ return debounced;
84
+ }
package/src/index.ts CHANGED
@@ -34,3 +34,5 @@ export { useSafeArea, type SafeAreaCssValueProps } from './useSafeArea';
34
34
  export { SafeArea, type SafeAreaProps } from './SafeArea';
35
35
 
36
36
  export { queryString } from './queryString';
37
+
38
+ export { debounce, type DebouncedFunction } from './debounce';
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/Spacing.tsx"],"sourcesContent":["import { memo, type HTMLAttributes } from 'react';\nimport { styled } from 'styled-components';\n\nimport { coerceCssPixelValue, type CSSPixelValue } from './coerceCssPixelValue';\n\ntype AxisDirection = 'vertical' | 'horizontal';\n\nexport type SpacingProps = Omit<HTMLAttributes<HTMLDivElement>, 'children'> & {\n direction?: AxisDirection;\n size: CSSPixelValue;\n};\n\nexport const Spacing = memo(function Spacing(props: SpacingProps) {\n const { direction = 'horizontal', size, ...restProps } = props;\n\n return (\n <SpacingContainer $direction={direction} $size={size} {...restProps} />\n );\n});\n\nconst SpacingContainer = styled.div<{\n $direction: SpacingProps['direction'];\n $size: SpacingProps['size'];\n}>`\n flex: none;\n width: ${({ $direction, $size }) =>\n $direction === 'horizontal' ? coerceCssPixelValue($size) : undefined};\n height: ${({ $direction, $size }) =>\n $direction === 'vertical' ? coerceCssPixelValue($size) : undefined};\n`;\n"],"mappings":";;;;;AAAA,SAAS,YAAiC;AAC1C,SAAS,cAAc;AAenB;AAJG,IAAM,UAAU,KAAK,SAASA,SAAQ,OAAqB;AAChE,QAAM,EAAE,YAAY,cAAc,MAAM,GAAG,UAAU,IAAI;AAEzD,SACE,oBAAC,oBAAiB,YAAY,WAAW,OAAO,MAAO,GAAG,WAAW;AAEzE,CAAC;AAED,IAAM,mBAAmB,OAAO;AAAA;AAAA,WAKrB,CAAC,EAAE,YAAY,MAAM,MAC5B,eAAe,eAAe,oBAAoB,KAAK,IAAI;AAAA,YACnD,CAAC,EAAE,YAAY,MAAM,MAC7B,eAAe,aAAa,oBAAoB,KAAK,IAAI;AAAA;","names":["Spacing"]}