@tiptap/extension-emoji 3.27.1 → 3.27.2
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.cjs +50 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +52 -3
- package/dist/index.js.map +1 -1
- package/package.json +10 -10
- package/src/emoji.ts +71 -3
package/package.json
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tiptap/extension-emoji",
|
|
3
|
-
"version": "3.27.
|
|
3
|
+
"version": "3.27.2",
|
|
4
4
|
"description": "emoji extension for tiptap",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"tiptap",
|
|
7
7
|
"tiptap extension"
|
|
8
8
|
],
|
|
9
9
|
"homepage": "https://tiptap.dev/api/nodes/emoji",
|
|
10
|
+
"bugs": {
|
|
11
|
+
"url": "https://github.com/ueberdosis/tiptap/issues"
|
|
12
|
+
},
|
|
10
13
|
"license": "MIT",
|
|
11
14
|
"repository": {
|
|
12
15
|
"type": "git",
|
|
13
16
|
"url": "https://github.com/ueberdosis/tiptap",
|
|
14
17
|
"directory": "packages/extension-emoji"
|
|
15
18
|
},
|
|
16
|
-
"bugs": {
|
|
17
|
-
"url": "https://github.com/ueberdosis/tiptap/issues"
|
|
18
|
-
},
|
|
19
19
|
"funding": {
|
|
20
20
|
"type": "github",
|
|
21
21
|
"url": "https://github.com/sponsors/ueberdosis"
|
|
@@ -47,14 +47,14 @@
|
|
|
47
47
|
"emoji-datasource": "^16.0.0",
|
|
48
48
|
"json5": "^2.2.3",
|
|
49
49
|
"tsm": "^2.3.0",
|
|
50
|
-
"@tiptap/
|
|
51
|
-
"@tiptap/
|
|
52
|
-
"@tiptap/suggestion": "^3.27.
|
|
50
|
+
"@tiptap/core": "^3.27.2",
|
|
51
|
+
"@tiptap/pm": "^3.27.2",
|
|
52
|
+
"@tiptap/suggestion": "^3.27.2"
|
|
53
53
|
},
|
|
54
54
|
"peerDependencies": {
|
|
55
|
-
"@tiptap/core": "3.27.
|
|
56
|
-
"@tiptap/pm": "3.27.
|
|
57
|
-
"@tiptap/suggestion": "3.27.
|
|
55
|
+
"@tiptap/core": "3.27.2",
|
|
56
|
+
"@tiptap/pm": "3.27.2",
|
|
57
|
+
"@tiptap/suggestion": "3.27.2"
|
|
58
58
|
},
|
|
59
59
|
"scripts": {
|
|
60
60
|
"build": "tsup"
|
package/src/emoji.ts
CHANGED
|
@@ -4,13 +4,14 @@ import {
|
|
|
4
4
|
findChildrenInRange,
|
|
5
5
|
getChangedRanges,
|
|
6
6
|
InputRule,
|
|
7
|
+
isFirefox,
|
|
7
8
|
mergeAttributes,
|
|
8
9
|
Node,
|
|
9
10
|
nodeInputRule,
|
|
10
11
|
PasteRule,
|
|
11
12
|
} from '@tiptap/core'
|
|
12
13
|
import type { Transaction } from '@tiptap/pm/state'
|
|
13
|
-
import { Plugin, PluginKey } from '@tiptap/pm/state'
|
|
14
|
+
import { Plugin, PluginKey, TextSelection } from '@tiptap/pm/state'
|
|
14
15
|
import type { SuggestionOptions } from '@tiptap/suggestion'
|
|
15
16
|
import { Suggestion } from '@tiptap/suggestion'
|
|
16
17
|
import emojiRegex from 'emoji-regex'
|
|
@@ -385,8 +386,75 @@ export const Emoji = Node.create<EmojiOptions, EmojiStorage>({
|
|
|
385
386
|
new Plugin({
|
|
386
387
|
key: new PluginKey('emoji'),
|
|
387
388
|
props: {
|
|
388
|
-
//
|
|
389
|
-
//
|
|
389
|
+
// Firefox cannot move the cursor past emoji nodes at paragraph
|
|
390
|
+
// boundaries using arrow keys. We intercept plain (unmodified)
|
|
391
|
+
// ArrowLeft/ArrowRight and manually resolve the correct position.
|
|
392
|
+
// Only handles emoji nodes — other inline non-selectable nodes
|
|
393
|
+
// (mentions, hard breaks) are out of scope for this extension.
|
|
394
|
+
// See: https://github.com/ProseMirror/prosemirror/issues/1220
|
|
395
|
+
handleKeyDown: (view, event) => {
|
|
396
|
+
if (!isFirefox()) {
|
|
397
|
+
return false
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
const isLeft = event.key === 'ArrowLeft'
|
|
401
|
+
const isRight = event.key === 'ArrowRight'
|
|
402
|
+
|
|
403
|
+
if (!isLeft && !isRight) {
|
|
404
|
+
return false
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// Don't interfere with selection extension (Shift), word
|
|
408
|
+
// navigation (Ctrl/Alt), or OS shortcuts (Meta).
|
|
409
|
+
if (event.shiftKey || event.ctrlKey || event.altKey || event.metaKey) {
|
|
410
|
+
return false
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
const { state } = view
|
|
414
|
+
const { selection } = state
|
|
415
|
+
|
|
416
|
+
if (!selection.empty || !(selection instanceof TextSelection)) {
|
|
417
|
+
return false
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
const $pos = selection.$from
|
|
421
|
+
const emojiType = this.type
|
|
422
|
+
|
|
423
|
+
if (isLeft) {
|
|
424
|
+
const nodeBefore = $pos.nodeBefore
|
|
425
|
+
|
|
426
|
+
if (!nodeBefore || nodeBefore.type !== emojiType) {
|
|
427
|
+
return false
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
// Cursor is right after an emoji node. Move past it to the left.
|
|
431
|
+
const newPos = $pos.pos - nodeBefore.nodeSize
|
|
432
|
+
|
|
433
|
+
if (newPos >= $pos.start()) {
|
|
434
|
+
view.dispatch(state.tr.setSelection(TextSelection.create(state.doc, newPos)))
|
|
435
|
+
return true
|
|
436
|
+
}
|
|
437
|
+
} else {
|
|
438
|
+
const nodeAfter = $pos.nodeAfter
|
|
439
|
+
|
|
440
|
+
if (!nodeAfter || nodeAfter.type !== emojiType) {
|
|
441
|
+
return false
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
// Cursor is right before an emoji node. Skip over it to the right.
|
|
445
|
+
const newPos = $pos.pos + nodeAfter.nodeSize
|
|
446
|
+
|
|
447
|
+
if (newPos <= $pos.end()) {
|
|
448
|
+
view.dispatch(state.tr.setSelection(TextSelection.create(state.doc, newPos)))
|
|
449
|
+
return true
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
return false
|
|
454
|
+
},
|
|
455
|
+
|
|
456
|
+
// double click to select emoji doesn't work by default
|
|
457
|
+
// that's why we simulate this behavior
|
|
390
458
|
handleDoubleClickOn: (view, pos, node) => {
|
|
391
459
|
if (node.type !== this.type) {
|
|
392
460
|
return false
|