@basiln/utils 0.1.5 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -118,13 +118,13 @@ type SafeAreaProps<T extends React__default.ElementType = 'div'> = {
118
118
  children: ReactNode;
119
119
  } & ComponentPropsWithoutRef<T>;
120
120
  declare const SafeArea: {
121
- <T extends React__default.ElementType<any, keyof React__default.JSX.IntrinsicElements> = "div">({ as, children, ...props }: SafeAreaProps<T>): react_jsx_runtime.JSX.Element;
121
+ <T extends React__default.ElementType = "div">({ as, children, ...props }: SafeAreaProps<T>): react_jsx_runtime.JSX.Element;
122
122
  Top: React__default.NamedExoticComponent<Omit<Omit<React__default.HTMLAttributes<HTMLDivElement>, "children"> & {
123
- direction?: ("horizontal" | "vertical") | undefined;
123
+ direction?: "horizontal" | "vertical";
124
124
  size: CSSPixelValue;
125
125
  }, "size">>;
126
126
  Bottom: React__default.NamedExoticComponent<Omit<Omit<React__default.HTMLAttributes<HTMLDivElement>, "children"> & {
127
- direction?: ("horizontal" | "vertical") | undefined;
127
+ direction?: "horizontal" | "vertical";
128
128
  size: CSSPixelValue;
129
129
  }, "size">>;
130
130
  };
package/package.json CHANGED
@@ -1,11 +1,9 @@
1
1
  {
2
2
  "name": "@basiln/utils",
3
- "version": "0.1.5",
4
- "exports": {
5
- ".": "./src/index.ts",
6
- "./package.json": "./package.json"
7
- },
8
- "main": "./src/index.ts",
3
+ "version": "0.1.7",
4
+ "main": "dist/index.js",
5
+ "module": "dist/index.mjs",
6
+ "types": "dist/index.d.ts",
9
7
  "publishConfig": {
10
8
  "access": "public",
11
9
  "exports": {
@@ -41,7 +39,7 @@
41
39
  "eslint-plugin-react-refresh": "^0.4.14",
42
40
  "styled-components": "^6.1.13",
43
41
  "tsup": "^6.5.0",
44
- "typescript": "^4.9.5"
42
+ "typescript": "^5.2.2"
45
43
  },
46
44
  "peerDependencies": {
47
45
  "react": "^18",
package/.eslintrc.json DELETED
@@ -1,4 +0,0 @@
1
- {
2
- "extends": "../../.eslintrc.cjs",
3
- "ignorePatterns": ["tsup.config.ts"]
4
- }
package/.stylelintrc DELETED
@@ -1,3 +0,0 @@
1
- {
2
- "extends": ["../../.stylelintrc"]
3
- }
package/CHANGELOG.md DELETED
@@ -1,181 +0,0 @@
1
- # Change Log
2
-
3
- ## 0.1.5
4
-
5
- ### Patch Changes
6
-
7
- - [#47](https://github.com/seedn-corp/basiln-packages-fe/pull/47) [`0614b05`](https://github.com/seedn-corp/basiln-packages-fe/commit/0614b05622472f0a7a76ebc8e0d8ef66248fd34e) Thanks [@sjgske](https://github.com/sjgske)! - Format export 누락 수정
8
-
9
- ## 0.1.4
10
-
11
- ### Patch Changes
12
-
13
- - [#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)! - 다양한 데이터를 원하는 형식으로 변환하는 포맷팅 유틸 추가
14
-
15
- ```tsx
16
- // 사용 방법
17
- import { Format } from '@basiln/utils';
18
-
19
- Format.phone('01012345678'); // '010-1234-5678'
20
- Format.removeHyphen('010-1234-5678'); // '01012345678'
21
- Format.commaize('123456'); // '123,456'
22
- Format.padTime(1); // '01'
23
- ```
24
-
25
- - [#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된 함수를 생성하는 유틸 추가
26
-
27
- ```tsx
28
- // 사용 방법
29
-
30
- const debouncedFunction = debounce(() => {
31
- console.log('Function executed');
32
- }, 1000);
33
-
34
- //flush - 즉시 요청
35
- debouncedFunction.flush();
36
-
37
- //cancel - 요청 취소
38
- debouncedFunction.cancel();
39
- ```
40
-
41
- ## 0.1.3
42
-
43
- ### Patch Changes
44
-
45
- - [#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 로 수정
46
-
47
- ## 0.1.2
48
-
49
- ### Patch Changes
50
-
51
- - [#8](https://github.com/seedn-corp/basiln-packages-fe/pull/8) [`7c1a636`](https://github.com/seedn-corp/basiln-packages-fe/commit/7c1a636efe1ba5c04609094f0c359ca959adf0f4) Thanks [@im-binary](https://github.com/im-binary)! - 선언적으로 flex box를 적용하고 싶을 때 사용할 수 있는 유틸 컴포넌트 Flex 추가
52
-
53
- ```tsx
54
- // 사용 방법
55
-
56
- <Flex justify="space-between" align="center">
57
- ...
58
- </Flex>
59
- ```
60
-
61
- - [#20](https://github.com/seedn-corp/basiln-packages-fe/pull/20) [`d26fcf7`](https://github.com/seedn-corp/basiln-packages-fe/commit/d26fcf7fb13987553af612bacafc814f3d6ee926) Thanks [@yoonhihi97](https://github.com/yoonhihi97)! - 정규식 검사를 할 수 있는 Validate 유틸 추가
62
-
63
- ```tsx
64
- Validate.email('basiln@basiln.com');
65
- Validate.phoneNumber('basiln@basiln.com');
66
- ```
67
-
68
- - [#22](https://github.com/seedn-corp/basiln-packages-fe/pull/22) [`3f8b55e`](https://github.com/seedn-corp/basiln-packages-fe/commit/3f8b55e0125332036408cb91d2a255a4a8c51f3c) Thanks [@im-binary](https://github.com/im-binary)! - - Flex 유틸 컴포넌트의 속성 gap 을 number 타입도 허용
69
-
70
- - [#24](https://github.com/seedn-corp/basiln-packages-fe/pull/24) [`dabf0c8`](https://github.com/seedn-corp/basiln-packages-fe/commit/dabf0c8154e7da5f0f12cb65142b396bb6e3c3f6) Thanks [@im-binary](https://github.com/im-binary)! - queryString을 create, parse, get, set할 때 사용할 수 있는 유틸입니다.
71
-
72
- ```ts
73
- // queryString create
74
- queryString.create({ a: '1', b: '2' }); // ?a=1&b=2&c=3
75
-
76
- // queryString parse
77
- queryString.parse('?a=1&b=2&c=3'); // { a: '1', b: '2' }
78
-
79
- // queryString get
80
- queryString.get('a'); // '1'
81
- queryString.get('a', parseInt); // 1
82
-
83
- // queryString set
84
- queryString.set({ qs: '?a=1', key: 'b', value: '2' }); // '?a=1&b=2'
85
- ```
86
-
87
- - [#13](https://github.com/seedn-corp/basiln-packages-fe/pull/13) [`68e5c1a`](https://github.com/seedn-corp/basiln-packages-fe/commit/68e5c1a57deb628f7322fff2e30c0e4be995ecb7) Thanks [@yoonhihi97](https://github.com/yoonhihi97)! - 16진수 컬러 코드를 rgba() 표기로 변환하는 유틸 추가
88
-
89
- ```tsx
90
- // 사용 방법
91
-
92
- hexToRgba({ hex: '#000000', alpha: 0.5 }); // 'rgba(0, 0, 0, 0.5)'
93
- hexToRgba({ hex: '#000', alpha: 0.5 }); // 'rgba(0, 0, 0, 0.5)'
94
- ```
95
-
96
- - [#25](https://github.com/seedn-corp/basiln-packages-fe/pull/25) [`203b91d`](https://github.com/seedn-corp/basiln-packages-fe/commit/203b91d64561931167fda6205422b34bb1962786) Thanks [@yoonhihi97](https://github.com/yoonhihi97)! - 웹뷰 환경에서 Safe Area를 선언적으로 사용할 수 있는 유틸 컴포넌트 추가
97
-
98
- ```tsx
99
- // 사용 방법
100
-
101
- <SafeArea>
102
- <p>안녕하세요</p>
103
- </SafeArea>
104
- ```
105
-
106
- 웹뷰 환경에서 SafeArea 값을 사용하기 위한 유틸 추가
107
-
108
- ```tsx
109
- // 사용 방법
110
-
111
- const { top } = useSafeArea();
112
- ```
113
-
114
- - [#19](https://github.com/seedn-corp/basiln-packages-fe/pull/19) [`2a2c812`](https://github.com/seedn-corp/basiln-packages-fe/commit/2a2c812494e63c599c573ff9bf8338a5b584928d) Thanks [@im-binary](https://github.com/im-binary)! - 선언적으로 요소들의 간격을 주고 싶을 때 사용할 수 있는 Spacing 유틸 컴포넌트 추가
115
-
116
- ```tsx
117
- // 사용 방법
118
-
119
- <Spacing size={30}>
120
-
121
- <Spacing size="3rem">
122
-
123
- <Spacing size="30px" direction="horizontal">
124
- ```
125
-
126
- - [#11](https://github.com/seedn-corp/basiln-packages-fe/pull/11) [`2e1833e`](https://github.com/seedn-corp/basiln-packages-fe/commit/2e1833e76c920b97231671cc4f64bb17d68646b3) Thanks [@yoonhihi97](https://github.com/yoonhihi97)! - ellipsis 스타일링을 위한 유틸리티 추가
127
-
128
- ```tsx
129
- // ellipsis 사용 방법
130
-
131
- <p css={ellipsis}>
132
- ...
133
- </p>
134
-
135
- const Text = styled.p`
136
- ...
137
- ${ellipsis}
138
- `
139
-
140
- // multiLineEllipsis 사용 방법
141
- // line: 몇번째 line에 ellipsis를 적용할지 지정
142
- <p css={multiLineEllipsis({line: 3})}>
143
- ...
144
- </p>
145
-
146
- const Text = styled.p`
147
- ...
148
- ${multiLineEllipsis({line: 3})}
149
- `
150
- ```
151
-
152
- - [#16](https://github.com/seedn-corp/basiln-packages-fe/pull/16) [`044a33c`](https://github.com/seedn-corp/basiln-packages-fe/commit/044a33cee600fbd1de1ba0971f2e02ba4280227e) Thanks [@yoonhihi97](https://github.com/yoonhihi97)! - 한글 문자열에 맞는 조사를 반환하는 유틸 추가
153
- (이/가, 을/를, 은/는 제공)
154
-
155
- ```tsx
156
- // 사용 방법
157
- josa({ josa: '을/를', word: '망곰이' }); // 망곰이를
158
- josa.pick({ josa: '은/는', word: '하츄핑' }); // 은
159
- ```
160
-
161
- ## 0.1.1
162
-
163
- ### Patch Changes
164
-
165
- - [#6](https://github.com/seedn-corp/basiln-packages-fe/pull/6) [`a7bb9b2`](https://github.com/seedn-corp/basiln-packages-fe/commit/a7bb9b27f214f4c8d9337dd586a0424fe8a98280) Thanks [@im-binary](https://github.com/im-binary)! - - 폴더 구조 수정
166
- - eslint, prettier, settings.json 컨벤션에 맞게 수정
167
- - changeset 관련 누락된 패키지 설치
168
-
169
- All notable changes to this project will be documented in this file.
170
- See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
171
-
172
- # 0.1.0 (2024-11-21)
173
-
174
- ### Bug Fixes
175
-
176
- - **util:** build error fix ([cbb6bba](https://github.com/seedn-corp/basiln-packages-fe/commit/cbb6bbaf34ecfa267109961dd9d6853c93a0631f))
177
-
178
- ### Features
179
-
180
- - tsup 세팅 ([c6e1aaf](https://github.com/seedn-corp/basiln-packages-fe/commit/c6e1aaf2f9b0ba6ef2090531bdcbe466581723d4))
181
- - 컴포넌트 추가 ([3656d2f](https://github.com/seedn-corp/basiln-packages-fe/commit/3656d2f8c58a14a3fd7931c6349c34b49fce676c))
package/src/Choose.tsx DELETED
@@ -1,45 +0,0 @@
1
- import { isValidElement, type ReactNode, type FC, Children } from 'react';
2
-
3
- export type ChooseWhenProps = {
4
- condition: boolean;
5
- children: ReactNode;
6
- };
7
-
8
- export type ChooseProps = {
9
- children: ReactNode;
10
- };
11
-
12
- export type ChooseOtherwiseProps = {
13
- children: ReactNode;
14
- };
15
-
16
- export function Choose({ children }: ChooseProps) {
17
- const validChildren = Children.toArray(children);
18
-
19
- const matchingChild = validChildren.find(
20
- (child) =>
21
- isValidElement<ChooseWhenProps>(child) &&
22
- child.type === Choose.When &&
23
- child.props.condition
24
- );
25
-
26
- if (matchingChild) {
27
- return matchingChild;
28
- }
29
-
30
- const otherwiseChild = validChildren.find(
31
- (child) => isValidElement(child) && child.type === Choose.Otherwise
32
- );
33
-
34
- return otherwiseChild || <></>;
35
- }
36
-
37
- const ChooseWhen: FC<ChooseWhenProps> = ({ children }) => <>{children}</>;
38
- ChooseWhen.displayName = 'Choose.When';
39
-
40
- const ChooseOtherwise: FC<ChooseOtherwiseProps> = ({ children }) => (
41
- <>{children}</>
42
- );
43
-
44
- Choose.When = ChooseWhen;
45
- Choose.Otherwise = ChooseOtherwise;
package/src/Flex.tsx DELETED
@@ -1,51 +0,0 @@
1
- import { memo, type CSSProperties, type HTMLAttributes } from 'react';
2
- import { styled } from 'styled-components';
3
-
4
- import { coerceCssPixelValue, type CSSPixelValue } from './coerceCssPixelValue';
5
-
6
- type Justify = CSSProperties['justifyContent'];
7
- type Align = CSSProperties['alignItems'];
8
- type Direction = CSSProperties['flexDirection'];
9
-
10
- export type FlexProps = HTMLAttributes<HTMLDivElement> & {
11
- gap?: CSSPixelValue;
12
- justify?: Justify;
13
- align?: Align;
14
- direction?: Direction;
15
- };
16
-
17
- export const Flex = memo(function Flex(props: FlexProps) {
18
- const {
19
- gap = 0,
20
- justify = 'center',
21
- align = 'center',
22
- direction = 'row',
23
- children,
24
- ...restProps
25
- } = props;
26
-
27
- return (
28
- <Container
29
- $gap={gap}
30
- $justify={justify}
31
- $align={align}
32
- $direction={direction}
33
- {...restProps}
34
- >
35
- {children}
36
- </Container>
37
- );
38
- });
39
-
40
- export const Container = styled.div<{
41
- $gap: CSSPixelValue;
42
- $justify: Justify;
43
- $align: Align;
44
- $direction: Direction;
45
- }>`
46
- display: flex;
47
- flex-direction: ${({ $direction }) => $direction};
48
- gap: ${({ $gap }) => coerceCssPixelValue($gap)};
49
- align-items: ${({ $align }) => $align};
50
- justify-content: ${({ $justify }) => $justify};
51
- `;
package/src/Format.ts DELETED
@@ -1,54 +0,0 @@
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/If.tsx DELETED
@@ -1,12 +0,0 @@
1
- import { type ReactNode } from 'react';
2
-
3
- export type IfProps = {
4
- condition: boolean;
5
- children: ReactNode;
6
- };
7
-
8
- export function If(props: IfProps) {
9
- const { condition, children } = props;
10
-
11
- return condition ? <>{children}</> : null;
12
- }
package/src/SafeArea.tsx DELETED
@@ -1,46 +0,0 @@
1
- import React, {
2
- memo,
3
- type ComponentPropsWithoutRef,
4
- type ReactNode,
5
- } from 'react';
6
-
7
- import { Spacing } from './Spacing';
8
- import { useSafeArea } from './useSafeArea';
9
-
10
- export type SafeAreaProps<T extends React.ElementType = 'div'> = {
11
- as?: T;
12
- children: ReactNode;
13
- } & ComponentPropsWithoutRef<T>;
14
-
15
- export const SafeArea = <T extends React.ElementType = 'div'>({
16
- as,
17
- children,
18
- ...props
19
- }: SafeAreaProps<T>) => {
20
- const Component = as || 'div';
21
-
22
- return (
23
- <Component {...props}>
24
- <SafeAreaTop />
25
- {children}
26
- <SafeAreaBottom />
27
- </Component>
28
- );
29
- };
30
-
31
- const SafeAreaTop = memo(function SafeAreaTop(
32
- props: Omit<ComponentPropsWithoutRef<typeof Spacing>, 'size'>
33
- ) {
34
- const { top } = useSafeArea();
35
- return <Spacing {...props} size={top} />;
36
- });
37
-
38
- const SafeAreaBottom = memo(function SafeAreaBottom(
39
- props: Omit<ComponentPropsWithoutRef<typeof Spacing>, 'size'>
40
- ) {
41
- const { bottom } = useSafeArea();
42
- return <Spacing {...props} size={bottom} />;
43
- });
44
-
45
- SafeArea.Top = SafeAreaTop;
46
- SafeArea.Bottom = SafeAreaBottom;
package/src/Spacing.tsx DELETED
@@ -1,30 +0,0 @@
1
- import { memo, type HTMLAttributes } from 'react';
2
- import { styled } from 'styled-components';
3
-
4
- import { coerceCssPixelValue, type CSSPixelValue } from './coerceCssPixelValue';
5
-
6
- type AxisDirection = 'vertical' | 'horizontal';
7
-
8
- export type SpacingProps = Omit<HTMLAttributes<HTMLDivElement>, 'children'> & {
9
- direction?: AxisDirection;
10
- size: CSSPixelValue;
11
- };
12
-
13
- export const Spacing = memo(function Spacing(props: SpacingProps) {
14
- const { direction = 'vertical', size, ...restProps } = props;
15
-
16
- return (
17
- <SpacingContainer $direction={direction} $size={size} {...restProps} />
18
- );
19
- });
20
-
21
- const SpacingContainer = styled.div<{
22
- $direction: SpacingProps['direction'];
23
- $size: SpacingProps['size'];
24
- }>`
25
- flex: none;
26
- width: ${({ $direction, $size }) =>
27
- $direction === 'horizontal' ? coerceCssPixelValue($size) : undefined};
28
- height: ${({ $direction, $size }) =>
29
- $direction === 'vertical' ? coerceCssPixelValue($size) : undefined};
30
- `;
package/src/Validate.ts DELETED
@@ -1,25 +0,0 @@
1
- /**
2
- *
3
- * @see 이메일 주소가 RFC 5322 표준을 따르는지 검사합니다. {@link https://emailregex.com/}
4
- */
5
- function isEmail(email: string) {
6
- const regExp =
7
- /^(([^<>()\[\]\\.,;:\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,}))$/;
8
- return regExp.test(email);
9
- }
10
-
11
- function isPhoneNumber(phoneNumber: string) {
12
- // 하이픈 있는 형식
13
- const regExpWithHyphen = /^01([0|1|6|7|8|9])-([0-9]{3,4})-([0-9]{4})$/;
14
- // 하이픈 없는 형식
15
- const regExpWithoutHyphen = /^01([0|1|6|7|8|9])([0-9]{3,4})([0-9]{4})$/;
16
-
17
- return (
18
- regExpWithHyphen.test(phoneNumber) || regExpWithoutHyphen.test(phoneNumber)
19
- );
20
- }
21
-
22
- export const Validate = {
23
- email: isEmail,
24
- phoneNumber: isPhoneNumber,
25
- };
@@ -1,5 +0,0 @@
1
- export type CSSPixelValue = string | number;
2
-
3
- export function coerceCssPixelValue(value: CSSPixelValue): string {
4
- return typeof value === 'string' ? value : `${value}px`;
5
- }
@@ -1,18 +0,0 @@
1
- // @see https://github.com/radix-ui/primitives/blob/main/packages/core/primitive/src/primitive.tsx
2
-
3
- export function composeEventHandlers<E>(
4
- originalEventHandler?: (event: E) => void,
5
- ourEventHandler?: (event: E) => void,
6
- { checkForDefaultPrevented = true } = {}
7
- ) {
8
- return function handleEvent(event: E) {
9
- originalEventHandler?.(event);
10
-
11
- if (
12
- checkForDefaultPrevented === false ||
13
- !(event as unknown as Event).defaultPrevented
14
- ) {
15
- return ourEventHandler?.(event);
16
- }
17
- };
18
- }
@@ -1,72 +0,0 @@
1
- export const COMPLETE_HANGUL_START_CHARCODE = '가'.charCodeAt(0);
2
- export const COMPLETE_HANGUL_END_CHARCODE = '힣'.charCodeAt(0);
3
-
4
- export const NUMBER_OF_JONGSEONG = 28;
5
- export const NUMBER_OF_JUNGSEONG = 21;
6
-
7
- const DISASSEMBLED_CONSONANTS_BY_CONSONANT = {
8
- '': '',
9
- ㄱ: 'ㄱ',
10
- ㄲ: 'ㄲ',
11
- ㄳ: 'ㄱㅅ',
12
- ㄴ: 'ㄴ',
13
- ㄵ: 'ㄴㅈ',
14
- ㄶ: 'ㄴㅎ',
15
- ㄷ: 'ㄷ',
16
- ㄸ: 'ㄸ',
17
- ㄹ: 'ㄹ',
18
- ㄺ: 'ㄹㄱ',
19
- ㄻ: 'ㄹㅁ',
20
- ㄼ: 'ㄹㅂ',
21
- ㄽ: 'ㄹㅅ',
22
- ㄾ: 'ㄹㅌ',
23
- ㄿ: 'ㄹㅍ',
24
- ㅀ: 'ㄹㅎ',
25
- ㅁ: 'ㅁ',
26
- ㅂ: 'ㅂ',
27
- ㅃ: 'ㅃ',
28
- ㅄ: 'ㅂㅅ',
29
- ㅅ: 'ㅅ',
30
- ㅆ: 'ㅆ',
31
- ㅇ: 'ㅇ',
32
- ㅈ: 'ㅈ',
33
- ㅉ: 'ㅉ',
34
- ㅊ: 'ㅊ',
35
- ㅋ: 'ㅋ',
36
- ㅌ: 'ㅌ',
37
- ㅍ: 'ㅍ',
38
- ㅎ: 'ㅎ',
39
- } as const;
40
-
41
- export const JONGSEONGS = (
42
- [
43
- '',
44
- 'ㄱ',
45
- 'ㄲ',
46
- 'ㄳ',
47
- 'ㄴ',
48
- 'ㄵ',
49
- 'ㄶ',
50
- 'ㄷ',
51
- 'ㄹ',
52
- 'ㄺ',
53
- 'ㄻ',
54
- 'ㄼ',
55
- 'ㄽ',
56
- 'ㄾ',
57
- 'ㄿ',
58
- 'ㅀ',
59
- 'ㅁ',
60
- 'ㅂ',
61
- 'ㅄ',
62
- 'ㅅ',
63
- 'ㅆ',
64
- 'ㅇ',
65
- 'ㅈ',
66
- 'ㅊ',
67
- 'ㅋ',
68
- 'ㅌ',
69
- 'ㅍ',
70
- 'ㅎ',
71
- ] as const
72
- ).map((consonant) => DISASSEMBLED_CONSONANTS_BY_CONSONANT[consonant]);
@@ -1,40 +0,0 @@
1
- import {
2
- useMemo,
3
- createContext as createContextRaw,
4
- useContext as useContextRaw,
5
- type PropsWithChildren,
6
- } from 'react';
7
-
8
- export function createContext<ContextValueType extends object | null>(
9
- rootComponentName: string,
10
- defaultContext?: ContextValueType
11
- ) {
12
- const Context = createContextRaw<ContextValueType | undefined>(
13
- defaultContext
14
- );
15
-
16
- function Provider(props: PropsWithChildren<ContextValueType>) {
17
- const { children, ...contextValues } = props;
18
-
19
- const value = useMemo(
20
- () => contextValues,
21
- [contextValues]
22
- ) as ContextValueType;
23
-
24
- return <Context.Provider value={value}>{children}</Context.Provider>;
25
- }
26
-
27
- function useContext(consumerName: string) {
28
- const context = useContextRaw(Context);
29
- if (context == null) {
30
- throw new Error(
31
- `${consumerName}은 ${rootComponentName}하위에서 사용해야 합니다.`
32
- );
33
- }
34
-
35
- return context;
36
- }
37
-
38
- Provider.displayName = `${rootComponentName}Provider`;
39
- return [Provider, useContext] as const;
40
- }
package/src/debounce.ts DELETED
@@ -1,84 +0,0 @@
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/ellipsis.ts DELETED
@@ -1,19 +0,0 @@
1
- import { css } from 'styled-components';
2
-
3
- export type MultiLineEllipsisProps = {
4
- line: number;
5
- };
6
-
7
- export const ellipsis = css`
8
- overflow: hidden;
9
- white-space: nowrap;
10
- text-overflow: ellipsis;
11
- `;
12
-
13
- export const multiLineEllipsis = ({ line }: MultiLineEllipsisProps) => css`
14
- display: -webkit-box;
15
- overflow: hidden;
16
- text-overflow: ellipsis;
17
- -webkit-line-clamp: ${line};
18
- -webkit-box-orient: vertical;
19
- `;
package/src/getVar.ts DELETED
@@ -1,9 +0,0 @@
1
- export type VariableType = `--${string}`;
2
-
3
- export function getVar(variable: VariableType, defaultValue?: string) {
4
- if (defaultValue) {
5
- return `var(${variable}, ${defaultValue})`;
6
- }
7
-
8
- return `var(${variable})`;
9
- }
package/src/hasBatchim.ts DELETED
@@ -1,31 +0,0 @@
1
- import {
2
- COMPLETE_HANGUL_END_CHARCODE,
3
- COMPLETE_HANGUL_START_CHARCODE,
4
- NUMBER_OF_JONGSEONG,
5
- } from './constants/josa';
6
-
7
- /**
8
- * 한글 음절의 받침 유무를 확인합니다.
9
- * @param str - 검사할 문자열
10
- * @returns 받침이 있으면 true, 없으면 false
11
- */
12
- export function hasBatchim(str: string): boolean {
13
- const lastChar = str[str.length - 1];
14
- if (!lastChar) return false;
15
-
16
- const charCode = lastChar.charCodeAt(0);
17
-
18
- // 한글 완성형 문자인지 확인
19
- if (
20
- charCode < COMPLETE_HANGUL_START_CHARCODE ||
21
- charCode > COMPLETE_HANGUL_END_CHARCODE
22
- ) {
23
- return false;
24
- }
25
-
26
- // 받침 코드 계산
27
- const batchimCode =
28
- (charCode - COMPLETE_HANGUL_START_CHARCODE) % NUMBER_OF_JONGSEONG;
29
-
30
- return batchimCode > 0; // 받침이 있으면 true
31
- }
package/src/hexToRgba.ts DELETED
@@ -1,45 +0,0 @@
1
- export type HexToRgbaProps = { hex: string; alpha?: number };
2
-
3
- function parseHexToDecimal(hex: string): number {
4
- return parseInt(hex, 16);
5
- }
6
-
7
- function validateHex(hex: string): string {
8
- const match = /^#?([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/.exec(hex);
9
- if (!match) {
10
- throw new Error(
11
- `Invalid hex value: "${hex}". Expected formats: "#RGB", "RGB", "#RRGGBB", or "RRGGBB".`
12
- );
13
- }
14
- return match[1];
15
- }
16
-
17
- function expandHex(hex: string): string {
18
- return hex.length === 3
19
- ? hex
20
- .split('')
21
- .map((char) => char + char)
22
- .join('')
23
- : hex;
24
- }
25
-
26
- function isValidAlpha(alpha: number): boolean {
27
- return alpha >= 0 && alpha <= 1;
28
- }
29
-
30
- export function hexToRgba({ hex, alpha = 1 }: HexToRgbaProps): string {
31
- if (!isValidAlpha(alpha)) {
32
- throw new Error(
33
- `Invalid alpha value. Must be between 0 and 1, received: ${alpha}`
34
- );
35
- }
36
-
37
- const validatedHex = validateHex(hex);
38
- const expandedHex = expandHex(validatedHex);
39
-
40
- const r = parseHexToDecimal(expandedHex.slice(0, 2));
41
- const g = parseHexToDecimal(expandedHex.slice(2, 4));
42
- const b = parseHexToDecimal(expandedHex.slice(4, 6));
43
-
44
- return `rgba(${r},${g},${b},${alpha})`;
45
- }
package/src/index.ts DELETED
@@ -1,40 +0,0 @@
1
- export {
2
- Choose,
3
- type ChooseWhenProps,
4
- type ChooseProps,
5
- type ChooseOtherwiseProps,
6
- } from './Choose';
7
-
8
- export { composeEventHandlers } from './composeEventHandlers';
9
-
10
- export { createContext } from './createContext';
11
-
12
- export { getVar, type VariableType } from './getVar';
13
-
14
- export { If, type IfProps } from './If';
15
-
16
- export { Flex, type FlexProps } from './Flex';
17
-
18
- export {
19
- ellipsis,
20
- multiLineEllipsis,
21
- type MultiLineEllipsisProps,
22
- } from './ellipsis';
23
-
24
- export { hexToRgba, type HexToRgbaProps } from './hexToRgba';
25
-
26
- export { josa, type JosaProps } from './josa';
27
-
28
- export { Validate } from './Validate';
29
-
30
- export { Spacing, type SpacingProps } from './Spacing';
31
-
32
- export { useSafeArea, type SafeAreaCssValueProps } from './useSafeArea';
33
-
34
- export { SafeArea, type SafeAreaProps } from './SafeArea';
35
-
36
- export { queryString } from './queryString';
37
-
38
- export { debounce, type DebouncedFunction } from './debounce';
39
-
40
- export { Format } from './Format';
package/src/josa.ts DELETED
@@ -1,50 +0,0 @@
1
- import { hasBatchim } from './hasBatchim';
2
-
3
- type JosaOption = '이/가' | '을/를' | '은/는';
4
-
5
- type ExtractJosaOption<T> = T extends `${infer A}/${infer B}` ? A | B : never;
6
-
7
- export type JosaProps<U extends JosaOption> = {
8
- word: string;
9
- josa: U;
10
- };
11
-
12
- /**
13
- * 주어진 단어와 조사 옵션을 기반으로 올바른 조사를 반환합니다.
14
- * @returns 단어와 올바른 조사가 결합된 문자열
15
- */
16
- export function josa<U extends JosaOption>(
17
- props: JosaProps<U>
18
- ): `${JosaProps<U>['word']}${ExtractJosaOption<U>}` {
19
- const { word, josa } = props;
20
-
21
- if (!word) {
22
- return word as `${JosaProps<U>['word']}${ExtractJosaOption<U>}`;
23
- }
24
-
25
- return `${word}${josaPicker({
26
- word,
27
- josa,
28
- })}` as `${JosaProps<U>['word']}${ExtractJosaOption<U>}`;
29
- }
30
-
31
- /**
32
- * 주어진 단어와 조사 옵션을 기반으로 올바른 조사를 선택합니다.
33
- * @returns 올바른 조사
34
- */
35
- function josaPicker<U extends JosaOption>(
36
- props: JosaProps<U>
37
- ): ExtractJosaOption<U> {
38
- const { word, josa } = props;
39
-
40
- if (!word) {
41
- return josa.split('/')[0] as ExtractJosaOption<U>;
42
- }
43
-
44
- const has받침 = hasBatchim(word);
45
- const index = has받침 ? 0 : 1;
46
-
47
- return josa.split('/')[index] as ExtractJosaOption<U>;
48
- }
49
-
50
- josa.pick = josaPicker;
@@ -1,134 +0,0 @@
1
- /**
2
- * @description 쿼리 스트링을 생성합니다.
3
- * @example createSearchParamString({ a: 1, b: 2, c: 3 }) // 'a=1&b=2&c=3'
4
- */
5
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
6
- function createSearchParamString(params: Record<string, any>) {
7
- return (
8
- new URLSearchParams(
9
- Object.entries(params)
10
- .filter(([, value]) => value != null)
11
- .map(([key, value]) => {
12
- if (Array.isArray(value)) {
13
- return value.map((x) => [key, x]);
14
- }
15
- return [[key, value]];
16
- })
17
- .flat()
18
- )
19
- .toString()
20
- // Convert space characters to '%20' according to RFC3986 spec, from RFC1738.
21
- .replace(/\+/g, '%20')
22
- );
23
- }
24
-
25
- /**
26
- * @description 물음표를 포함한 쿼리 스트링을 생성합니다.
27
- * @example createQueryString({ a: 1, b: 2, c: 3 }) // '?a=1&b=2&c=3'
28
- */
29
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
30
- function createQueryString(params: Record<string, any>) {
31
- const queryString = createSearchParamString(params);
32
-
33
- if (queryString === '') {
34
- return '';
35
- }
36
-
37
- return `?${queryString}`;
38
- }
39
-
40
- /**
41
- * @description 이터러블에서 키와 값을 가진 객체로 변환합니다.
42
- * @example fromEntries([['a', 1], ['b', 2], ['c', 3]]) // { a: 1, b: 2, c: 3 }
43
- */
44
- function fromEntries<T extends readonly [string | number, unknown]>(
45
- iterable: Iterable<T>
46
- ) {
47
- const result: Record<string | number | symbol, T[1]> = {};
48
-
49
- for (const [key, value] of Array.from(iterable)) {
50
- if (result[key]) {
51
- if (Array.isArray(result[key])) {
52
- (result[key] as Array<string | number>).push(value as string | number);
53
- } else {
54
- result[key] = [result[key], value];
55
- }
56
- } else {
57
- result[key] = value;
58
- }
59
- }
60
-
61
- return result;
62
- }
63
-
64
- /**
65
- * @description 쿼리 스트링을 객체로 변환합니다.
66
- * @example parseQueryString('?a=1&b=2&c=3') // { a: '1', b: '2', c: '3' }
67
- */
68
- function parseQueryString<Result = Record<string, string>>(
69
- queryString: string = typeof location !== 'undefined' ? location.search : ''
70
- ): Result {
71
- const query = queryString.trim().replace(/^[?#&]/, '');
72
-
73
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
74
- return fromEntries(new URLSearchParams(query)) as any;
75
- }
76
-
77
- /**
78
- * @description 쿼리 스트링에서 특정 키의 값을 가져옵니다.
79
- *
80
- * @param name 가져올 쿼리 스트링의 키
81
- * @param parser 가져온 값을 파싱할 함수
82
- * @returns 파싱된 값
83
- *
84
- * @example
85
- * url: 'http://example.com/?a=1'
86
- * getQueryString('a') // '1'
87
- * getQueryString('a', parseInt) // 1
88
- * getQueryString('b') // undefined
89
- * getQueryString('b', parseInt) // undefined
90
- */
91
- function getQueryString(name: string): string | undefined;
92
- function getQueryString<T>(
93
- name: string,
94
- parser: (val: string) => T
95
- ): T | undefined;
96
- function getQueryString<T = string>(name: string, parser?: (val: string) => T) {
97
- const value = queryString.parse<{ [name: string]: string | undefined }>()[
98
- name
99
- ];
100
-
101
- if (parser == null || value == null) {
102
- return value;
103
- } else {
104
- return parser(value);
105
- }
106
- }
107
-
108
- /**
109
- * @description 기존 쿼리 스트링에 새로운 쿼리 스트링을 추가합니다.
110
- * @example setQueryString({ qs: '?a=1', key: 'b', value: '2' }) // '?a=1&b=2'
111
- */
112
- function setQueryString({
113
- qs,
114
- key,
115
- value,
116
- }: {
117
- qs: string;
118
- key: string;
119
- value: string;
120
- }) {
121
- const parsed = parseQueryString(qs);
122
-
123
- return createQueryString({
124
- ...parsed,
125
- [key]: value,
126
- });
127
- }
128
-
129
- export const queryString = {
130
- create: createQueryString,
131
- parse: parseQueryString,
132
- get: getQueryString,
133
- set: setQueryString,
134
- };
@@ -1,24 +0,0 @@
1
- import { coerceCssPixelValue, type CSSPixelValue } from './coerceCssPixelValue';
2
-
3
- export type SafeAreaCssValueProps = {
4
- top?: CSSPixelValue;
5
- bottom?: CSSPixelValue;
6
- left?: CSSPixelValue;
7
- right?: CSSPixelValue;
8
- };
9
-
10
- const useSafeArea = ({
11
- top: T = 0,
12
- bottom: B = 0,
13
- left: L = 0,
14
- right: R = 0,
15
- }: SafeAreaCssValueProps = {}) => {
16
- const top = `max(${coerceCssPixelValue(T)}, env(safe-area-inset-top))`;
17
- const bottom = `max(${coerceCssPixelValue(B)}, env(safe-area-inset-bottom))`;
18
- const left = `max(${coerceCssPixelValue(L)}, env(safe-area-inset-left))`;
19
- const right = `max(${coerceCssPixelValue(R)}, env(safe-area-inset-right))`;
20
-
21
- return { top, bottom, left, right };
22
- };
23
-
24
- export { useSafeArea };
package/tsconfig.json DELETED
@@ -1,13 +0,0 @@
1
- {
2
- "extends": "../../tsconfig.base.json",
3
- "compilerOptions": {
4
- "jsx": "react-jsx",
5
- "resolveJsonModule": true,
6
- "isolatedModules": true,
7
- "esModuleInterop": true,
8
- "declaration": true,
9
- "outDir": "./dist"
10
- },
11
- "include": ["src", "./tsup.config.ts"],
12
- "exclude": ["node_modules"]
13
- }
package/tsup.config.ts DELETED
@@ -1,13 +0,0 @@
1
- import { defineConfig } from 'tsup';
2
- import pkgJson from './package.json';
3
-
4
- const external = [...Object.keys((pkgJson as any).peerDependencies || {})];
5
-
6
- export default defineConfig({
7
- entry: ['src/**/*.{ts,tsx}'],
8
- format: ['esm', 'cjs'],
9
- sourcemap: true,
10
- clean: true,
11
- dts: 'src/index.ts',
12
- external,
13
- });