@ihabdevteam/core 0.180.0 → 0.181.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +41 -0
- package/dist/components.cjs.js +10 -10
- package/dist/hooks.cjs.js +3 -3
- package/dist/i18n.cjs.js +1 -1
- package/dist/ihabdevteam-core.cjs.js +184 -184
- package/dist/ihabdevteam-core.d.ts +33 -9
- package/dist/packages/core/src/components/EmptyState.d.ts +2 -0
- package/dist/packages/core/src/components/EmptyState.js +4 -1
- package/dist/packages/core/src/components/barChartTypes.d.ts +11 -1
- package/dist/packages/core/src/hooks/wordTrainingFilterModel.d.ts +3 -3
- package/dist/packages/core/src/utils/koreanSyllable.d.ts +18 -7
- package/dist/packages/core/src/utils/koreanSyllable.js +20 -16
- package/dist/packages/core/src/version.d.ts +1 -1
- package/dist/packages/core/src/version.js +1 -1
- package/dist/utils.cjs.js +2 -2
- package/package.json +1 -1
|
@@ -389,7 +389,17 @@ export declare interface BarChartProps {
|
|
|
389
389
|
rate?: boolean;
|
|
390
390
|
/** y축 최대를 데이터 최댓값으로 (10 단위 올림 없이). 가장 큰 막대가 차트 상단에 닿음 */
|
|
391
391
|
tightMax?: boolean;
|
|
392
|
-
/** 평균 모드 — 합계 대신
|
|
392
|
+
/** 평균 모드 — 합계 대신 **경과한 날마다의 `a` 평균**을 머리에 보인다(진행률처럼 쌓은 라벨).
|
|
393
|
+
*
|
|
394
|
+
* 셈은 이렇다 — **막대는 이 셈에 안 들어간다:**
|
|
395
|
+
* - 재는 자료: 주 보기는 그 주의 막대들, **월 보기는 `data[monthRange].daily`**.
|
|
396
|
+
* 월 보기가 daily 인 것은 주 막대가 **달 경계를 넘기 때문**이다(월요일 시작 7일이라 마지막 주에 다음 달 날이 든다).
|
|
397
|
+
* - 분모: 그 자료 중 **`a !== -1` 인 칸 수** — 미래 칸만 뺀다. **기록 없는 날(0)도 분모에 든다.**
|
|
398
|
+
* - 분자: 그 칸들의 `a` 가 양수인 것만 더한 값.
|
|
399
|
+
* - 그 나눗셈을 `Math.round` 한다.
|
|
400
|
+
*
|
|
401
|
+
* 그래서 **막대 평균과는 안 맞는다** — 화면의 막대가 주 단위면 특히 그렇다(말귀 검수 2026-09-18:
|
|
402
|
+
* 막대 93·22·0·0 인데 머리는 12 였고, 205 / 17(경과일) = 12.06 이 그 수였다). */
|
|
393
403
|
avgMode?: boolean;
|
|
394
404
|
/** 헤더 합계/평균 값 포맷터(예: 분 → 'X시간 Y분'). 지정 시 단위 대신 포맷 문자열 표시. */
|
|
395
405
|
totalFormat?: (n: number) => string;
|
|
@@ -1196,10 +1206,6 @@ export declare function ChoiceChips({ subs, selected, onSelect, size }: {
|
|
|
1196
1206
|
size?: 'medium' | 'small';
|
|
1197
1207
|
}): JSX.Element;
|
|
1198
1208
|
|
|
1199
|
-
/**
|
|
1200
|
-
* 한글 음절 분해/조립/거리 계산 유틸
|
|
1201
|
-
* @public
|
|
1202
|
-
*/
|
|
1203
1209
|
export declare const CHOSEONG: readonly ["ㄱ", "ㄲ", "ㄴ", "ㄷ", "ㄸ", "ㄹ", "ㅁ", "ㅂ", "ㅃ", "ㅅ", "ㅆ", "ㅇ", "ㅈ", "ㅉ", "ㅊ", "ㅋ", "ㅌ", "ㅍ", "ㅎ"];
|
|
1204
1210
|
|
|
1205
1211
|
/**
|
|
@@ -1594,7 +1600,7 @@ export declare function copyText(text: string): Promise<boolean>;
|
|
|
1594
1600
|
*
|
|
1595
1601
|
* 값은 손으로 적고 `test/coreVersion.test.ts` 가 package.json 과 어긋나면 운다.
|
|
1596
1602
|
*/
|
|
1597
|
-
export declare const CORE_VERSION = "0.
|
|
1603
|
+
export declare const CORE_VERSION = "0.181.0";
|
|
1598
1604
|
|
|
1599
1605
|
/** @public */
|
|
1600
1606
|
declare const coreDefault: Record<string, unknown>;
|
|
@@ -2157,6 +2163,8 @@ export declare interface EmptyStateProps {
|
|
|
2157
2163
|
label: string;
|
|
2158
2164
|
icon?: string;
|
|
2159
2165
|
onClick: () => void | Promise<unknown>;
|
|
2166
|
+
/** 단추 크기 — 기본 40. 빈 화면이 한 쪽을 통째로 차지하면 48·56 이 어울린다(말귀 고객관리 2026-09-21). */
|
|
2167
|
+
size?: 40 | 48 | 56;
|
|
2160
2168
|
};
|
|
2161
2169
|
/** 표 안의 빈 행처럼 좁은 자리에 넣을 때 위아래 여백을 줄인다. */
|
|
2162
2170
|
compact?: boolean;
|
|
@@ -2939,6 +2947,19 @@ export declare function itemCorrectness(r: RawResult): boolean | null;
|
|
|
2939
2947
|
*/
|
|
2940
2948
|
export declare function jamoToNamesForSpeech(text: string): string;
|
|
2941
2949
|
|
|
2950
|
+
/**
|
|
2951
|
+
* @public 종성을 **무엇으로 견줄지.**
|
|
2952
|
+
*
|
|
2953
|
+
* - `'glyph'`(기본) — 쓰인 글자 그대로. 고른 것이 `ㅅ` 이면 받침이 `ㅅ` 인 음절만, `ㅄ` 이면 `ㅄ` 인 음절만.
|
|
2954
|
+
* - `'phoneme'` — **받침 소리**(대표음)로. `ㄱ` 을 고르면 `ㄱ·ㄲ·ㅋ·ㄳ·ㄺ`(박·밖·녘·넋·닭)이 함께 든다.
|
|
2955
|
+
*
|
|
2956
|
+
* 0.181.0 전에는 이름 없는 셋째 규칙이었다 — 원형이 아니면 **겹받침 구성 자모 아무거나** 로 걸렸다.
|
|
2957
|
+
* 그래서 `ㅅ` 에 `값(갑)·넋(넉)·몫(목)·삯(삭)` 이 들고(받침 소리는 ㅂ·ㄱ), `ㄱ` 에는 `넋·닭` 은 드는데
|
|
2958
|
+
* **소리가 같은 `밖·녘` 은 안 들었다** — 한쪽은 넓고 한쪽은 좁았다. 글자도 소리도 아닌 자리였다
|
|
2959
|
+
* (말귀 실측 2026-09-21: 라이브 23,000 낱말 중 겹받침 낱말 308개가 제 받침 소리가 아닌 자모로 한 번씩 더 걸렸다).
|
|
2960
|
+
*/
|
|
2961
|
+
declare type JongMatch = 'glyph' | 'phoneme';
|
|
2962
|
+
|
|
2942
2963
|
/** 종성 0번은 받침 없음 */
|
|
2943
2964
|
export declare const JONGSEONG: readonly ["", "ㄱ", "ㄲ", "ㄳ", "ㄴ", "ㄵ", "ㄶ", "ㄷ", "ㄹ", "ㄺ", "ㄻ", "ㄼ", "ㄽ", "ㄾ", "ㄿ", "ㅀ", "ㅁ", "ㅂ", "ㅄ", "ㅅ", "ㅆ", "ㅇ", "ㅈ", "ㅊ", "ㅋ", "ㅌ", "ㅍ", "ㅎ"];
|
|
2944
2965
|
|
|
@@ -9345,8 +9366,8 @@ export declare interface WordComposition {
|
|
|
9345
9366
|
export declare function wordContainsChoseong(word: string, jamo: string): boolean;
|
|
9346
9367
|
|
|
9347
9368
|
/** @public 단어가 특정 자모를 종성(coda)으로 포함하는지.
|
|
9348
|
-
*
|
|
9349
|
-
export declare function wordContainsJongseong(word: string, jamo: string): boolean;
|
|
9369
|
+
* `jongMatch` 로 **글자 그대로**(기본) · **받침 소리**(`'phoneme'`)를 고른다 — `JongMatch` 설명을 본다. */
|
|
9370
|
+
export declare function wordContainsJongseong(word: string, jamo: string, jongMatch?: JongMatch): boolean;
|
|
9350
9371
|
|
|
9351
9372
|
/** @public 단어가 특정 모음을 중성(vowel)으로 포함하는지 */
|
|
9352
9373
|
export declare function wordContainsJungseong(word: string, jamo: string): boolean;
|
|
@@ -9453,7 +9474,10 @@ export declare function wordHasSyllableMatching(word: string, parts: {
|
|
|
9453
9474
|
jung?: string[] | null;
|
|
9454
9475
|
jong?: string[] | null;
|
|
9455
9476
|
jongNone?: boolean;
|
|
9456
|
-
}, position?: 'head' | 'mid' | 'tail' | null
|
|
9477
|
+
}, position?: 'head' | 'mid' | 'tail' | null,
|
|
9478
|
+
/** 종성을 무엇으로 견줄지 — 기본은 **글자 그대로**(`'glyph'`). 받침 **소리**로 모으려면 `'phoneme'`(`JongMatch` 참고).
|
|
9479
|
+
* 발음 입력 화면은 넘기는 낱말 자체가 표준발음이라 겹받침이 안 나온다 — 기본 그대로 두면 된다. */
|
|
9480
|
+
jongMatch?: JongMatch): boolean;
|
|
9457
9481
|
|
|
9458
9482
|
/** @public */
|
|
9459
9483
|
export declare function WordImageTooltip({ words, anchorRect }: WordImageTooltipProps): ReactPortal | null;
|
|
@@ -15,6 +15,8 @@ export interface EmptyStateProps {
|
|
|
15
15
|
label: string;
|
|
16
16
|
icon?: string;
|
|
17
17
|
onClick: () => void | Promise<unknown>;
|
|
18
|
+
/** 단추 크기 — 기본 40. 빈 화면이 한 쪽을 통째로 차지하면 48·56 이 어울린다(말귀 고객관리 2026-09-21). */
|
|
19
|
+
size?: 40 | 48 | 56;
|
|
18
20
|
};
|
|
19
21
|
/** 표 안의 빈 행처럼 좁은 자리에 넣을 때 위아래 여백을 줄인다. */
|
|
20
22
|
compact?: boolean;
|
|
@@ -8,5 +8,8 @@ export default function EmptyState({ icon, emoji, title, message, hint, action,
|
|
|
8
8
|
const { pending, press } = usePendingPress(action?.onClick);
|
|
9
9
|
return (_jsxs("div", { className: cx('empty-state', compact && 'empty-state--compact', className), children: [emoji && _jsx("span", { className: "empty-state__emoji", children: emoji }), icon && _jsx(Icon, { icon: icon, className: "empty-state__icon" }), title && _jsx("p", { className: "empty-state__title body-2", children: title }), message && _jsx("p", { className: "empty-state__message body-3", children: message }), hint && _jsx("p", { className: "empty-state__hint caption-1", children: hint }), action && (
|
|
10
10
|
// type="button" — 없으면 폼 안에서 누르는 순간 폼이 제출된다
|
|
11
|
-
_jsxs("button", { type: "button",
|
|
11
|
+
_jsxs("button", { type: "button",
|
|
12
|
+
/* 코어 `Button` 을 안 쓰고 클래스를 적는 것은 `aria-busy` 때문이다 — 약속이 끝날 때까지 알린다.
|
|
13
|
+
크기만 `action.size` 로 받는다(그 값이 `button{n}`·`button{n}--bar` 두 이름을 함께 정한다). */
|
|
14
|
+
className: cx('empty-state__action button', `button${action.size ?? 40}`, `button${action.size ?? 40}--bar`, 'button--variant-main button--align-center button--shape-rounded'), onClick: press, disabled: pending, "aria-busy": pending || undefined, children: [action.icon && _jsx(Icon, { icon: action.icon, className: "button__icon" }), _jsx("span", { className: "button__label button-1", children: action.label })] }))] }));
|
|
12
15
|
}
|
|
@@ -74,7 +74,17 @@ export interface BarChartProps {
|
|
|
74
74
|
rate?: boolean;
|
|
75
75
|
/** y축 최대를 데이터 최댓값으로 (10 단위 올림 없이). 가장 큰 막대가 차트 상단에 닿음 */
|
|
76
76
|
tightMax?: boolean;
|
|
77
|
-
/** 평균 모드 — 합계 대신
|
|
77
|
+
/** 평균 모드 — 합계 대신 **경과한 날마다의 `a` 평균**을 머리에 보인다(진행률처럼 쌓은 라벨).
|
|
78
|
+
*
|
|
79
|
+
* 셈은 이렇다 — **막대는 이 셈에 안 들어간다:**
|
|
80
|
+
* - 재는 자료: 주 보기는 그 주의 막대들, **월 보기는 `data[monthRange].daily`**.
|
|
81
|
+
* 월 보기가 daily 인 것은 주 막대가 **달 경계를 넘기 때문**이다(월요일 시작 7일이라 마지막 주에 다음 달 날이 든다).
|
|
82
|
+
* - 분모: 그 자료 중 **`a !== -1` 인 칸 수** — 미래 칸만 뺀다. **기록 없는 날(0)도 분모에 든다.**
|
|
83
|
+
* - 분자: 그 칸들의 `a` 가 양수인 것만 더한 값.
|
|
84
|
+
* - 그 나눗셈을 `Math.round` 한다.
|
|
85
|
+
*
|
|
86
|
+
* 그래서 **막대 평균과는 안 맞는다** — 화면의 막대가 주 단위면 특히 그렇다(말귀 검수 2026-09-18:
|
|
87
|
+
* 막대 93·22·0·0 인데 머리는 12 였고, 205 / 17(경과일) = 12.06 이 그 수였다). */
|
|
78
88
|
avgMode?: boolean;
|
|
79
89
|
/** 헤더 합계/평균 값 포맷터(예: 분 → 'X시간 Y분'). 지정 시 단위 대신 포맷 문자열 표시. */
|
|
80
90
|
totalFormat?: (n: number) => string;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { CompositionPart } from '../utils/koreanSyllable';
|
|
2
2
|
import { type PhonemeGroupItem, type PhoneticFeature } from '../utils/phonemeGroups';
|
|
3
|
-
export declare const FULL_CHOSEONG: ("ㄱ" | "ㄲ" | "
|
|
4
|
-
export declare const FULL_JUNGSEONG: ("ㅏ" | "
|
|
5
|
-
export declare const FULL_JONGSEONG: ("ㄱ" | "ㄲ" | "
|
|
3
|
+
export declare const FULL_CHOSEONG: ("ㄱ" | "ㄲ" | "ㅋ" | "ㄴ" | "ㄷ" | "ㅅ" | "ㅆ" | "ㅈ" | "ㅊ" | "ㅌ" | "ㅎ" | "ㄹ" | "ㅁ" | "ㅂ" | "ㅍ" | "ㅇ" | "ㄸ" | "ㅃ" | "ㅉ")[];
|
|
4
|
+
export declare const FULL_JUNGSEONG: ("ㅏ" | "ㅓ" | "ㅗ" | "ㅜ" | "ㅣ" | "ㅡ" | "ㅑ" | "ㅕ" | "ㅛ" | "ㅠ" | "ㅐ" | "ㅒ" | "ㅔ" | "ㅖ" | "ㅘ" | "ㅙ" | "ㅚ" | "ㅝ" | "ㅞ" | "ㅟ" | "ㅢ")[];
|
|
5
|
+
export declare const FULL_JONGSEONG: ("ㄱ" | "ㄲ" | "ㅋ" | "ㄳ" | "ㄺ" | "ㄴ" | "ㄵ" | "ㄶ" | "ㄷ" | "ㅅ" | "ㅆ" | "ㅈ" | "ㅊ" | "ㅌ" | "ㅎ" | "ㄹ" | "ㄼ" | "ㄽ" | "ㄾ" | "ㅀ" | "ㅁ" | "ㄻ" | "ㅂ" | "ㅍ" | "ㄿ" | "ㅄ" | "ㅇ")[];
|
|
6
6
|
/** 선택 값(자모 문자열, 병합 버튼은 다자모)을 실제 매칭 자모 배열로 분해. NO_CODA는 빈 배열. */
|
|
7
7
|
export declare const valueToJamos: (v: string) => string[];
|
|
8
8
|
/** 종성 '제외'(받침 없는 단어만) 선택을 나타내는 센티넬 값 */
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 한글 음절 분해/조립/거리 계산 유틸
|
|
3
|
-
* @public
|
|
4
|
-
*/
|
|
5
1
|
export declare const CHOSEONG: readonly ["ㄱ", "ㄲ", "ㄴ", "ㄷ", "ㄸ", "ㄹ", "ㅁ", "ㅂ", "ㅃ", "ㅅ", "ㅆ", "ㅇ", "ㅈ", "ㅉ", "ㅊ", "ㅋ", "ㅌ", "ㅍ", "ㅎ"];
|
|
6
2
|
export declare const JUNGSEONG: readonly ["ㅏ", "ㅐ", "ㅑ", "ㅒ", "ㅓ", "ㅔ", "ㅕ", "ㅖ", "ㅗ", "ㅘ", "ㅙ", "ㅚ", "ㅛ", "ㅜ", "ㅝ", "ㅞ", "ㅟ", "ㅠ", "ㅡ", "ㅢ", "ㅣ"];
|
|
7
3
|
/** 종성 0번은 받침 없음 */
|
|
@@ -63,9 +59,21 @@ export declare function wordContainsPhoneme(word: string, jamo: string): boolean
|
|
|
63
59
|
export declare function wordContainsChoseong(word: string, jamo: string): boolean;
|
|
64
60
|
/** @public 단어가 특정 모음을 중성(vowel)으로 포함하는지 */
|
|
65
61
|
export declare function wordContainsJungseong(word: string, jamo: string): boolean;
|
|
62
|
+
/**
|
|
63
|
+
* @public 종성을 **무엇으로 견줄지.**
|
|
64
|
+
*
|
|
65
|
+
* - `'glyph'`(기본) — 쓰인 글자 그대로. 고른 것이 `ㅅ` 이면 받침이 `ㅅ` 인 음절만, `ㅄ` 이면 `ㅄ` 인 음절만.
|
|
66
|
+
* - `'phoneme'` — **받침 소리**(대표음)로. `ㄱ` 을 고르면 `ㄱ·ㄲ·ㅋ·ㄳ·ㄺ`(박·밖·녘·넋·닭)이 함께 든다.
|
|
67
|
+
*
|
|
68
|
+
* 0.181.0 전에는 이름 없는 셋째 규칙이었다 — 원형이 아니면 **겹받침 구성 자모 아무거나** 로 걸렸다.
|
|
69
|
+
* 그래서 `ㅅ` 에 `값(갑)·넋(넉)·몫(목)·삯(삭)` 이 들고(받침 소리는 ㅂ·ㄱ), `ㄱ` 에는 `넋·닭` 은 드는데
|
|
70
|
+
* **소리가 같은 `밖·녘` 은 안 들었다** — 한쪽은 넓고 한쪽은 좁았다. 글자도 소리도 아닌 자리였다
|
|
71
|
+
* (말귀 실측 2026-09-21: 라이브 23,000 낱말 중 겹받침 낱말 308개가 제 받침 소리가 아닌 자모로 한 번씩 더 걸렸다).
|
|
72
|
+
*/
|
|
73
|
+
export type JongMatch = 'glyph' | 'phoneme';
|
|
66
74
|
/** @public 단어가 특정 자모를 종성(coda)으로 포함하는지.
|
|
67
|
-
*
|
|
68
|
-
export declare function wordContainsJongseong(word: string, jamo: string): boolean;
|
|
75
|
+
* `jongMatch` 로 **글자 그대로**(기본) · **받침 소리**(`'phoneme'`)를 고른다 — `JongMatch` 설명을 본다. */
|
|
76
|
+
export declare function wordContainsJongseong(word: string, jamo: string, jongMatch?: JongMatch): boolean;
|
|
69
77
|
/** @public 단어의 한글 음절 개수 (한글 이외 문자는 제외) */
|
|
70
78
|
export declare function syllableLength(word: string): number;
|
|
71
79
|
/** @public 단어의 모든 한글 음절에 종성(받침)이 없는지 (열린 음절로만 구성) */
|
|
@@ -81,7 +89,10 @@ export declare function wordHasSyllableMatching(word: string, parts: {
|
|
|
81
89
|
jung?: string[] | null;
|
|
82
90
|
jong?: string[] | null;
|
|
83
91
|
jongNone?: boolean;
|
|
84
|
-
}, position?: 'head' | 'mid' | 'tail' | null
|
|
92
|
+
}, position?: 'head' | 'mid' | 'tail' | null,
|
|
93
|
+
/** 종성을 무엇으로 견줄지 — 기본은 **글자 그대로**(`'glyph'`). 받침 **소리**로 모으려면 `'phoneme'`(`JongMatch` 참고).
|
|
94
|
+
* 발음 입력 화면은 넘기는 낱말 자체가 표준발음이라 겹받침이 안 나온다 — 기본 그대로 두면 된다. */
|
|
95
|
+
jongMatch?: JongMatch): boolean;
|
|
85
96
|
/**
|
|
86
97
|
* @public 문자열이 음절 패턴 DSL 문법인지 — 쉼표(,) 포함 여부로 판별한다.
|
|
87
98
|
* 일반 단어 검색어엔 쉼표가 쓰이지 않으므로 충돌 없이 자동 분기할 수 있다.
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* 한글 음절 분해/조립/거리 계산 유틸
|
|
3
3
|
* @public
|
|
4
4
|
*/
|
|
5
|
+
import { finalToPhoneme } from './phonemeConvert';
|
|
5
6
|
export const CHOSEONG = ['ㄱ', 'ㄲ', 'ㄴ', 'ㄷ', 'ㄸ', 'ㄹ', 'ㅁ', 'ㅂ', 'ㅃ', 'ㅅ', 'ㅆ', 'ㅇ', 'ㅈ', 'ㅉ', 'ㅊ', 'ㅋ', 'ㅌ', 'ㅍ', 'ㅎ'];
|
|
6
7
|
export const JUNGSEONG = ['ㅏ', 'ㅐ', 'ㅑ', 'ㅒ', 'ㅓ', 'ㅔ', 'ㅕ', 'ㅖ', 'ㅗ', 'ㅘ', 'ㅙ', 'ㅚ', 'ㅛ', 'ㅜ', 'ㅝ', 'ㅞ', 'ㅟ', 'ㅠ', 'ㅡ', 'ㅢ', 'ㅣ'];
|
|
7
8
|
/** 종성 0번은 받침 없음 */
|
|
@@ -238,20 +239,24 @@ export function wordContainsJungseong(word, jamo) {
|
|
|
238
239
|
}
|
|
239
240
|
return false;
|
|
240
241
|
}
|
|
242
|
+
/** 음절의 종성이 고른 자모 하나와 맞는지 — 두 모드의 단일 출처. */
|
|
243
|
+
function jongMatchesJamo(jong, jamo, mode) {
|
|
244
|
+
const 글자 = JONGSEONG[jong];
|
|
245
|
+
if (글자 === jamo)
|
|
246
|
+
return true;
|
|
247
|
+
return mode === 'phoneme' && finalToPhoneme(글자) === finalToPhoneme(jamo);
|
|
248
|
+
}
|
|
241
249
|
/** @public 단어가 특정 자모를 종성(coda)으로 포함하는지.
|
|
242
|
-
*
|
|
243
|
-
export function wordContainsJongseong(word, jamo) {
|
|
250
|
+
* `jongMatch` 로 **글자 그대로**(기본) · **받침 소리**(`'phoneme'`)를 고른다 — `JongMatch` 설명을 본다. */
|
|
251
|
+
export function wordContainsJongseong(word, jamo, jongMatch = 'glyph') {
|
|
244
252
|
if (!word || !jamo)
|
|
245
253
|
return false;
|
|
246
254
|
for (const ch of word) {
|
|
247
255
|
const s = parseSyllable(ch);
|
|
248
256
|
if (!s || s.jong <= 0)
|
|
249
257
|
continue;
|
|
250
|
-
if (
|
|
251
|
-
return true;
|
|
252
|
-
const decomp = JONG_DECOMPOSE[s.jong];
|
|
253
|
-
if (decomp && decomp.includes(jamo))
|
|
254
|
-
return true; // 겹받침 구성 자모(대표음) 매칭
|
|
258
|
+
if (jongMatchesJamo(s.jong, jamo, jongMatch))
|
|
259
|
+
return true;
|
|
255
260
|
}
|
|
256
261
|
return false;
|
|
257
262
|
}
|
|
@@ -280,15 +285,11 @@ export function wordHasNoCoda(word) {
|
|
|
280
285
|
}
|
|
281
286
|
return sawSyllable;
|
|
282
287
|
}
|
|
283
|
-
/** 한 음절(Syllable)이 주어진 종성 자모 집합 중 하나를 종성으로
|
|
284
|
-
|
|
285
|
-
function syllableJongMatches(s, jamos) {
|
|
288
|
+
/** 한 음절(Syllable)이 주어진 종성 자모 집합 중 하나를 종성으로 갖는지(`JongMatch` 규칙). */
|
|
289
|
+
function syllableJongMatches(s, jamos, mode) {
|
|
286
290
|
if (s.jong <= 0)
|
|
287
291
|
return false;
|
|
288
|
-
|
|
289
|
-
return true;
|
|
290
|
-
const decomp = JONG_DECOMPOSE[s.jong];
|
|
291
|
-
return !!decomp && decomp.some(j => jamos.includes(j));
|
|
292
|
+
return jamos.some(j => jongMatchesJamo(s.jong, j, mode));
|
|
292
293
|
}
|
|
293
294
|
/**
|
|
294
295
|
* @public 단어에 '하나의 음절'이 주어진 초성/중성/종성 제약을 **모두** 만족하는지.
|
|
@@ -298,7 +299,10 @@ function syllableJongMatches(s, jamos) {
|
|
|
298
299
|
*/
|
|
299
300
|
export function wordHasSyllableMatching(word, parts,
|
|
300
301
|
// 위치 제약(선택) — 'head'=어두(첫음절), 'tail'=어말(끝음절), 'mid'=어중(가운데, 3음절+). 미지정=모든 음절.
|
|
301
|
-
position
|
|
302
|
+
position,
|
|
303
|
+
/** 종성을 무엇으로 견줄지 — 기본은 **글자 그대로**(`'glyph'`). 받침 **소리**로 모으려면 `'phoneme'`(`JongMatch` 참고).
|
|
304
|
+
* 발음 입력 화면은 넘기는 낱말 자체가 표준발음이라 겹받침이 안 나온다 — 기본 그대로 두면 된다. */
|
|
305
|
+
jongMatch = 'glyph') {
|
|
302
306
|
if (!word)
|
|
303
307
|
return false;
|
|
304
308
|
const chars = [...word];
|
|
@@ -314,7 +318,7 @@ position) {
|
|
|
314
318
|
if (s.jong > 0)
|
|
315
319
|
return false;
|
|
316
320
|
}
|
|
317
|
-
else if (parts.jong && !syllableJongMatches(s, parts.jong))
|
|
321
|
+
else if (parts.jong && !syllableJongMatches(s, parts.jong, jongMatch))
|
|
318
322
|
return false;
|
|
319
323
|
return true;
|
|
320
324
|
};
|