Skip to content

Commit 130d2e8

Browse files
committed
feat(sender): implement grapheme-aware character counting
1 parent 16fd9bf commit 130d2e8

File tree

5 files changed

+29
-3
lines changed

5 files changed

+29
-3
lines changed

packages/components/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@
6464
"@tiptap/extension-text": "^3.11.0",
6565
"@tiptap/extension-history": "^3.11.0",
6666
"@tiptap/extension-placeholder": "^3.11.0",
67-
"@tiptap/extension-character-count": "^3.11.0"
67+
"@tiptap/extension-character-count": "^3.11.0",
68+
"unicode-segmenter": "^0.14.5"
6869
},
6970
"devDependencies": {
7071
"@types/dom-speech-recognition": "^0.0.6",

packages/components/src/sender/composables/useEditor.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import CharacterCount from '@tiptap/extension-character-count'
1313
import type { AnyExtension } from '@tiptap/core'
1414
import type { SenderEmits, UseEditorReturn } from '../index.type'
1515
import type { SenderPropsWithDefaults } from '../index.vue'
16+
import { countGraphemes } from '../utils/countGraphemes'
1617

1718
/**
1819
* 编辑器 Hook
@@ -46,6 +47,7 @@ export function useEditor(props: SenderPropsWithDefaults, emit: SenderEmits): Us
4647
}),
4748
CharacterCount.configure({
4849
mode: 'textSize',
50+
textCounter: countGraphemes,
4951
}),
5052
]
5153

packages/components/src/sender/composables/useSenderCore.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import { useEditor } from './useEditor'
2727
import { useKeyboardShortcuts } from './useKeyboardShortcuts'
2828
import { useModeSwitch } from './useModeSwitch'
2929
import { useAutoSize } from './useAutoSize'
30+
import { countGraphemes } from '../utils/countGraphemes'
3031

3132
/**
3233
* useSenderCore 返回类型
@@ -76,8 +77,7 @@ export function useSenderCore(props: SenderPropsWithDefaults, emit: SenderEmits)
7677

7778
const characterCount = computed(() => {
7879
if (!editor.value) return 0
79-
const text = getTextWithTemplates(editor.value)
80-
return text.length
80+
return countGraphemes(getTextWithTemplates(editor.value))
8181
})
8282

8383
const isOverLimit = computed(() => {
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { countGraphemes as countGraphemesFallback } from 'unicode-segmenter/grapheme'
2+
3+
const graphemeSegmenter =
4+
typeof Intl !== 'undefined' && typeof Intl.Segmenter === 'function'
5+
? new Intl.Segmenter(undefined, { granularity: 'grapheme' })
6+
: null
7+
8+
export function countGraphemes(text: string): number {
9+
if (!text) return 0
10+
11+
if (graphemeSegmenter) {
12+
let count = 0
13+
14+
for (const _segment of graphemeSegmenter.segment(text)) {
15+
count++
16+
}
17+
18+
return count
19+
}
20+
21+
return countGraphemesFallback(text)
22+
}

packages/components/tsconfig.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"useDefineForClassFields": true,
55
"module": "ESNext",
66
"lib": [
7+
"ES2022.Intl",
78
"ES2020",
89
"DOM",
910
"DOM.Iterable"

0 commit comments

Comments
 (0)