@basiln/utils 0.1.4 → 0.1.6
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/Format.mjs +3 -22
- package/dist/Format.mjs.map +1 -1
- package/dist/chunk-OLYZDPI3.mjs +27 -0
- package/dist/chunk-OLYZDPI3.mjs.map +1 -0
- package/dist/index.d.ts +36 -4
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +4 -0
- package/package.json +3 -7
- package/.eslintrc.json +0 -4
- package/.stylelintrc +0 -3
- package/CHANGELOG.md +0 -175
- package/src/Choose.tsx +0 -45
- package/src/Flex.tsx +0 -51
- package/src/Format.ts +0 -54
- package/src/If.tsx +0 -12
- package/src/SafeArea.tsx +0 -46
- package/src/Spacing.tsx +0 -30
- package/src/Validate.ts +0 -25
- package/src/coerceCssPixelValue.ts +0 -5
- package/src/composeEventHandlers.ts +0 -18
- package/src/constants/josa.ts +0 -72
- package/src/createContext.tsx +0 -40
- package/src/debounce.ts +0 -84
- package/src/ellipsis.ts +0 -19
- package/src/getVar.ts +0 -9
- package/src/hasBatchim.ts +0 -31
- package/src/hexToRgba.ts +0 -45
- package/src/index.ts +0 -38
- package/src/josa.ts +0 -50
- package/src/queryString.ts +0 -134
- package/src/useSafeArea.ts +0 -24
- package/tsconfig.json +0 -13
- package/tsup.config.ts +0 -13
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
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,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
|
-
}
|
package/src/constants/josa.ts
DELETED
@@ -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]);
|
package/src/createContext.tsx
DELETED
@@ -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
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,38 +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';
|
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;
|