@milkdown/plugin-emoji 5.3.4 → 5.5.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/lib/index.es.js +43 -25
- package/lib/index.es.js.map +1 -1
- package/lib/src/filter/helper.d.ts.map +1 -1
- package/lib/src/filter/index.d.ts +2 -1
- package/lib/src/filter/index.d.ts.map +1 -1
- package/lib/src/picker.d.ts +2 -1
- package/lib/src/picker.d.ts.map +1 -1
- package/lib/src/remark-twemoji.d.ts.map +1 -1
- package/package.json +10 -4
- package/src/filter/helper.ts +4 -3
- package/src/filter/index.ts +14 -4
- package/src/node.ts +4 -4
- package/src/picker.ts +3 -1
- package/src/remark-twemoji.ts +16 -8
package/lib/index.es.js
CHANGED
|
@@ -4,7 +4,7 @@ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
|
4
4
|
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
5
5
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
6
|
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
7
|
-
var __defNormalProp = (obj,
|
|
7
|
+
var __defNormalProp = (obj, key2, value) => key2 in obj ? __defProp(obj, key2, { enumerable: true, configurable: true, writable: true, value }) : obj[key2] = value;
|
|
8
8
|
var __spreadValues = (a, b) => {
|
|
9
9
|
for (var prop in b || (b = {}))
|
|
10
10
|
if (__hasOwnProp.call(b, prop))
|
|
@@ -18,7 +18,7 @@ var __spreadValues = (a, b) => {
|
|
|
18
18
|
};
|
|
19
19
|
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
20
20
|
import { createNode, AtomList } from "@milkdown/utils";
|
|
21
|
-
import { Plugin, calculateNodePosition, DecorationSet, Decoration, InputRule } from "@milkdown/prose";
|
|
21
|
+
import { PluginKey, Plugin, calculateNodePosition, DecorationSet, Decoration, InputRule } from "@milkdown/prose";
|
|
22
22
|
import nodeEmoji, { search } from "node-emoji";
|
|
23
23
|
import remarkEmoji from "remark-emoji";
|
|
24
24
|
import twemoji from "twemoji";
|
|
@@ -35,12 +35,12 @@ const checkTrigger$1 = (view, from, to, text, setRange, setSearch) => {
|
|
|
35
35
|
const $from = state.doc.resolve(from);
|
|
36
36
|
if ($from.parent.type.spec.code)
|
|
37
37
|
return false;
|
|
38
|
-
const textBefore = $from.parent.textBetween(Math.max(0, $from.parentOffset - 10), $from.parentOffset, void 0, "\uFFFC") + text;
|
|
38
|
+
const textBefore = ($from.parent.textBetween(Math.max(0, $from.parentOffset - 10), $from.parentOffset, void 0, "\uFFFC") + text).toLowerCase();
|
|
39
39
|
if (full.test(textBefore)) {
|
|
40
40
|
return false;
|
|
41
41
|
}
|
|
42
42
|
const regex2 = part.exec(textBefore);
|
|
43
|
-
if (regex2 && textBefore.endsWith(regex2[0])) {
|
|
43
|
+
if (regex2 && regex2[0] && textBefore.endsWith(regex2[0])) {
|
|
44
44
|
const match = regex2[0];
|
|
45
45
|
setRange(from - (match.length - text.length), to);
|
|
46
46
|
setSearch(match);
|
|
@@ -50,14 +50,14 @@ const checkTrigger$1 = (view, from, to, text, setRange, setSearch) => {
|
|
|
50
50
|
};
|
|
51
51
|
const renderDropdownList = (list, dropDown, $active, onConfirm, setActive) => {
|
|
52
52
|
dropDown.innerHTML = "";
|
|
53
|
-
list.forEach(({ emoji: emoji2, key }, i) => {
|
|
53
|
+
list.forEach(({ emoji: emoji2, key: key2 }, i) => {
|
|
54
54
|
const container = document.createElement("div");
|
|
55
55
|
container.className = "milkdown-emoji-filter_item";
|
|
56
56
|
const emojiSpan = document.createElement("span");
|
|
57
57
|
emojiSpan.innerHTML = parse(emoji2);
|
|
58
58
|
emojiSpan.className = "milkdown-emoji-filter_item-emoji";
|
|
59
59
|
const keySpan = document.createElement("span");
|
|
60
|
-
keySpan.textContent = ":" +
|
|
60
|
+
keySpan.textContent = ":" + key2 + ":";
|
|
61
61
|
keySpan.className = "milkdown-emoji-filter_item-key";
|
|
62
62
|
container.appendChild(emojiSpan);
|
|
63
63
|
container.appendChild(keySpan);
|
|
@@ -127,6 +127,7 @@ const injectStyle = ({ size, mixin, palette, font }, { css, cx }) => {
|
|
|
127
127
|
`;
|
|
128
128
|
return cx(border, shadow, style);
|
|
129
129
|
};
|
|
130
|
+
const key$1 = new PluginKey("MILKDOWN_PLUGIN_EMOJI_FILTER");
|
|
130
131
|
const filter = (utils) => {
|
|
131
132
|
let trigger = false;
|
|
132
133
|
let _from = 0;
|
|
@@ -139,6 +140,7 @@ const filter = (utils) => {
|
|
|
139
140
|
$active = null;
|
|
140
141
|
};
|
|
141
142
|
return new Plugin({
|
|
143
|
+
key: key$1,
|
|
142
144
|
props: {
|
|
143
145
|
handleKeyDown(_, event) {
|
|
144
146
|
if (["Delete", "Backspace"].includes(event.key)) {
|
|
@@ -192,13 +194,13 @@ const filter = (utils) => {
|
|
|
192
194
|
parentNode.addEventListener("keydown", (e) => {
|
|
193
195
|
if (!trigger || !(e instanceof KeyboardEvent))
|
|
194
196
|
return;
|
|
195
|
-
const { key } = e;
|
|
196
|
-
if (
|
|
197
|
+
const { key: key2 } = e;
|
|
198
|
+
if (key2 === "Enter") {
|
|
197
199
|
replace();
|
|
198
200
|
return;
|
|
199
201
|
}
|
|
200
|
-
if (["ArrowDown", "ArrowUp"].includes(
|
|
201
|
-
const next =
|
|
202
|
+
if (["ArrowDown", "ArrowUp"].includes(key2)) {
|
|
203
|
+
const next = key2 === "ArrowDown" ? ($active == null ? void 0 : $active.nextElementSibling) || dropDown.firstElementChild : ($active == null ? void 0 : $active.previousElementSibling) || dropDown.lastElementChild;
|
|
202
204
|
if ($active) {
|
|
203
205
|
$active.classList.remove("active");
|
|
204
206
|
}
|
|
@@ -218,7 +220,9 @@ const filter = (utils) => {
|
|
|
218
220
|
});
|
|
219
221
|
return {
|
|
220
222
|
update: (view) => {
|
|
221
|
-
|
|
223
|
+
const { selection } = view.state;
|
|
224
|
+
if (selection.from - selection.to !== 0 || !trigger) {
|
|
225
|
+
off();
|
|
222
226
|
dropDown.classList.add("hide");
|
|
223
227
|
return null;
|
|
224
228
|
}
|
|
@@ -233,14 +237,18 @@ const filter = (utils) => {
|
|
|
233
237
|
$active = a;
|
|
234
238
|
});
|
|
235
239
|
calculateNodePosition(view, dropDown, (selected, target, parent) => {
|
|
240
|
+
const $editor = dropDown.parentElement;
|
|
241
|
+
if (!$editor) {
|
|
242
|
+
throw new Error();
|
|
243
|
+
}
|
|
236
244
|
const start = view.coordsAtPos(_from);
|
|
237
245
|
let left = start.left - parent.left;
|
|
238
|
-
let top = selected.bottom - parent.top + 14;
|
|
246
|
+
let top = selected.bottom - parent.top + 14 + $editor.scrollTop;
|
|
239
247
|
if (left < 0) {
|
|
240
248
|
left = 0;
|
|
241
249
|
}
|
|
242
250
|
if (window.innerHeight - start.bottom < target.height) {
|
|
243
|
-
top = selected.top - parent.top - target.height - 14;
|
|
251
|
+
top = selected.top - parent.top - target.height - 14 + $editor.scrollTop;
|
|
244
252
|
}
|
|
245
253
|
return [top, left];
|
|
246
254
|
});
|
|
@@ -251,6 +259,7 @@ const filter = (utils) => {
|
|
|
251
259
|
});
|
|
252
260
|
};
|
|
253
261
|
const keyword = ":emoji:";
|
|
262
|
+
const key = new PluginKey("MILKDOWN_PLUGIN_EMOJI_PICKER");
|
|
254
263
|
const checkTrigger = (view, from, to, text, setRange) => {
|
|
255
264
|
if (view.composing)
|
|
256
265
|
return false;
|
|
@@ -276,6 +285,7 @@ const picker = (utils) => {
|
|
|
276
285
|
_to = 0;
|
|
277
286
|
};
|
|
278
287
|
const plugin = new Plugin({
|
|
288
|
+
key,
|
|
279
289
|
props: {
|
|
280
290
|
handleKeyDown() {
|
|
281
291
|
off();
|
|
@@ -365,10 +375,16 @@ function flatMap(ast, fn) {
|
|
|
365
375
|
if (isParent(node)) {
|
|
366
376
|
const out = [];
|
|
367
377
|
for (let i = 0, n = node.children.length; i < n; i++) {
|
|
368
|
-
const
|
|
369
|
-
if (
|
|
370
|
-
|
|
371
|
-
|
|
378
|
+
const nthChild = node.children[i];
|
|
379
|
+
if (nthChild) {
|
|
380
|
+
const xs = transform(nthChild, i, node);
|
|
381
|
+
if (xs) {
|
|
382
|
+
for (let j = 0, m = xs.length; j < m; j++) {
|
|
383
|
+
const item = xs[j];
|
|
384
|
+
if (item) {
|
|
385
|
+
out.push(item);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
372
388
|
}
|
|
373
389
|
}
|
|
374
390
|
}
|
|
@@ -390,11 +406,13 @@ const twemojiPlugin = () => {
|
|
|
390
406
|
while (match = regex.exec(str)) {
|
|
391
407
|
const { index } = match;
|
|
392
408
|
const emoji2 = match[0];
|
|
393
|
-
if (
|
|
394
|
-
|
|
409
|
+
if (emoji2) {
|
|
410
|
+
if (index > 0) {
|
|
411
|
+
output.push(__spreadProps(__spreadValues({}, node), { value: str.slice(0, index) }));
|
|
412
|
+
}
|
|
413
|
+
output.push(__spreadProps(__spreadValues({}, node), { value: parse(emoji2), type: "emoji" }));
|
|
414
|
+
str = str.slice(index + emoji2.length);
|
|
395
415
|
}
|
|
396
|
-
output.push(__spreadProps(__spreadValues({}, node), { value: parse(emoji2), type: "emoji" }));
|
|
397
|
-
str = str.slice(index + emoji2.length);
|
|
398
416
|
}
|
|
399
417
|
if (str.length) {
|
|
400
418
|
output.push(__spreadProps(__spreadValues({}, node), { value: str }));
|
|
@@ -441,25 +459,25 @@ const emojiNode = createNode((utils) => {
|
|
|
441
459
|
],
|
|
442
460
|
toDOM: (node) => {
|
|
443
461
|
const span = document.createElement("span");
|
|
444
|
-
span.dataset
|
|
462
|
+
span.dataset["type"] = "emoji";
|
|
445
463
|
if (style) {
|
|
446
464
|
span.classList.add(style);
|
|
447
465
|
}
|
|
448
466
|
span.classList.add("emoji-wrapper");
|
|
449
|
-
span.innerHTML = node.attrs
|
|
467
|
+
span.innerHTML = node.attrs["html"];
|
|
450
468
|
return { dom: span };
|
|
451
469
|
},
|
|
452
470
|
parseMarkdown: {
|
|
453
471
|
match: ({ type }) => type === "emoji",
|
|
454
472
|
runner: (state, node, type) => {
|
|
455
|
-
state.addNode(type, { html: node
|
|
473
|
+
state.addNode(type, { html: node["value"] });
|
|
456
474
|
}
|
|
457
475
|
},
|
|
458
476
|
toMarkdown: {
|
|
459
477
|
match: (node) => node.type.name === "emoji",
|
|
460
478
|
runner: (state, node) => {
|
|
461
479
|
const span = document.createElement("span");
|
|
462
|
-
span.innerHTML = node.attrs
|
|
480
|
+
span.innerHTML = node.attrs["html"];
|
|
463
481
|
const img = span.querySelector("img");
|
|
464
482
|
const title = img == null ? void 0 : img.title;
|
|
465
483
|
span.remove();
|
package/lib/index.es.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.es.js","sources":["../src/constant.ts","../src/parse.ts","../src/filter/helper.ts","../src/filter/style.ts","../src/filter/index.ts","../src/picker.ts","../src/remark-twemoji.ts","../src/node.ts","../src/index.ts"],"sourcesContent":["/* Copyright 2021, Milkdown by Mirone. */\nexport const part = /:\\+1|:-1|:[\\w-]+/;\nexport const full = /:\\+1:|:-1:|:[\\w-]+:/;\nexport const input = /(:([^:\\s]+):)$/;\nexport const keyword = ':emoji:';\n","/* Copyright 2021, Milkdown by Mirone. */\nimport twemoji from 'twemoji';\n\nexport const parse = (emoji: string) => twemoji.parse(emoji, { attributes: (text) => ({ title: text }) });\n","/* Copyright 2021, Milkdown by Mirone. */\n\nimport { EditorView } from '@milkdown/prose';\nimport { Emoji } from 'node-emoji';\n\nimport { full, part } from '../constant';\nimport { parse } from '../parse';\n\nexport const checkTrigger = (\n view: EditorView,\n from: number,\n to: number,\n text: string,\n setRange: (from: number, to: number) => void,\n setSearch: (words: string) => void,\n) => {\n if (view.composing) return false;\n const { state } = view;\n const $from = state.doc.resolve(from);\n if ($from.parent.type.spec.code) return false;\n const textBefore =\n $from.parent.textBetween(Math.max(0, $from.parentOffset - 10), $from.parentOffset, undefined, '\\ufffc') + text;\n if (full.test(textBefore)) {\n return false;\n }\n const regex = part.exec(textBefore);\n if (regex && textBefore.endsWith(regex[0])) {\n const match = regex[0];\n setRange(from - (match.length - text.length), to);\n setSearch(match);\n return true;\n }\n return false;\n};\n\nexport const renderDropdownList = (\n list: Emoji[],\n dropDown: HTMLElement,\n $active: HTMLElement | null,\n onConfirm: () => void,\n setActive: (active: HTMLElement | null) => void,\n) => {\n dropDown.innerHTML = '';\n list.forEach(({ emoji, key }, i) => {\n const container = document.createElement('div');\n container.className = 'milkdown-emoji-filter_item';\n\n const emojiSpan = document.createElement('span');\n emojiSpan.innerHTML = parse(emoji);\n\n emojiSpan.className = 'milkdown-emoji-filter_item-emoji';\n const keySpan = document.createElement('span');\n keySpan.textContent = ':' + key + ':';\n keySpan.className = 'milkdown-emoji-filter_item-key';\n\n container.appendChild(emojiSpan);\n container.appendChild(keySpan);\n dropDown.appendChild(container);\n\n if (i === 0) {\n container.classList.add('active');\n setActive(container);\n }\n\n container.addEventListener('mouseenter', (e) => {\n if ($active) {\n $active.classList.remove('active');\n }\n const { target } = e;\n if (!(target instanceof HTMLElement)) return;\n target.classList.add('active');\n setActive(target);\n });\n container.addEventListener('mouseleave', (e) => {\n const { target } = e;\n if (!(target instanceof HTMLElement)) return;\n target.classList.remove('active');\n });\n container.addEventListener('mousedown', (e) => {\n onConfirm();\n e.preventDefault();\n });\n });\n};\n","/* Copyright 2021, Milkdown by Mirone. */\nimport type { Emotion, ThemeTool } from '@milkdown/core';\n\nexport const injectStyle = ({ size, mixin, palette, font }: ThemeTool, { css, cx }: Emotion) => {\n const border = mixin.border?.();\n const shadow = mixin.shadow?.();\n\n const style = css`\n position: absolute;\n &.hide {\n display: none;\n }\n\n border-radius: ${size.radius};\n background: ${palette('surface')};\n\n .milkdown-emoji-filter_item {\n display: flex;\n gap: 0.5rem;\n height: 2.25rem;\n padding: 0 1rem;\n align-items: center;\n justify-content: flex-start;\n cursor: pointer;\n line-height: 2;\n font-family: ${font.typography};\n font-size: 0.875rem;\n &.active {\n background: ${palette('secondary', 0.12)};\n color: ${palette('primary')};\n }\n }\n\n .emoji {\n height: 1em;\n width: 1em;\n margin: 0 0.05em 0 0.1em;\n vertical-align: -0.1em;\n }\n `;\n return cx(border, shadow, style);\n};\n","/* Copyright 2021, Milkdown by Mirone. */\n\nimport { calculateNodePosition, Plugin } from '@milkdown/prose';\nimport { Utils } from '@milkdown/utils';\nimport { search } from 'node-emoji';\n\nimport { checkTrigger, renderDropdownList } from './helper';\nimport { injectStyle } from './style';\n\nexport const filter = (utils: Utils) => {\n let trigger = false;\n let _from = 0;\n let _search = '';\n let $active: null | HTMLElement = null;\n\n const off = () => {\n trigger = false;\n _from = 0;\n _search = '';\n $active = null;\n };\n\n return new Plugin({\n props: {\n handleKeyDown(_, event) {\n if (['Delete', 'Backspace'].includes(event.key)) {\n _search = _search.slice(0, -1);\n if (_search.length <= 1) {\n off();\n }\n return false;\n }\n if (!trigger) return false;\n if (!['ArrowUp', 'ArrowDown', 'Enter'].includes(event.key)) {\n return false;\n }\n return true;\n },\n handleTextInput(view, from, to, text) {\n trigger = checkTrigger(\n view,\n from,\n to,\n text,\n (from) => {\n _from = from;\n },\n (search) => {\n _search = search;\n },\n );\n if (!trigger) {\n off();\n }\n return false;\n },\n },\n view: (editorView) => {\n const { parentNode } = editorView.dom;\n if (!parentNode) {\n throw new Error();\n }\n\n const dropDown = document.createElement('div');\n const style = utils.getStyle(injectStyle);\n\n if (style) {\n style.split(' ').forEach((x) => dropDown.classList.add(x));\n }\n\n dropDown.classList.add('milkdown-emoji-filter', 'hide');\n\n const replace = () => {\n if (!$active) return;\n\n const { tr } = editorView.state;\n const node = editorView.state.schema.node('emoji', { html: $active.firstElementChild?.innerHTML });\n\n editorView.dispatch(tr.delete(_from, _from + _search.length).insert(_from, node));\n off();\n dropDown.classList.add('hide');\n };\n\n parentNode.appendChild(dropDown);\n parentNode.addEventListener('keydown', (e) => {\n if (!trigger || !(e instanceof KeyboardEvent)) return;\n\n const { key } = e;\n\n if (key === 'Enter') {\n replace();\n return;\n }\n\n if (['ArrowDown', 'ArrowUp'].includes(key)) {\n const next =\n key === 'ArrowDown'\n ? $active?.nextElementSibling || dropDown.firstElementChild\n : $active?.previousElementSibling || dropDown.lastElementChild;\n if ($active) {\n $active.classList.remove('active');\n }\n if (!next) return;\n next.classList.add('active');\n $active = next as HTMLElement;\n\n return;\n }\n });\n parentNode.addEventListener('mousedown', (e) => {\n if (!trigger) return;\n\n e.stopPropagation();\n off();\n dropDown.classList.add('hide');\n });\n\n return {\n update: (view) => {\n if (!trigger) {\n dropDown.classList.add('hide');\n return null;\n }\n const result = search(_search).slice(0, 5);\n const { node } = view.domAtPos(_from);\n if (result.length === 0 || !node) {\n dropDown.classList.add('hide');\n return null;\n }\n\n dropDown.classList.remove('hide');\n renderDropdownList(result, dropDown, $active, replace, (a) => {\n $active = a;\n });\n calculateNodePosition(view, dropDown, (selected, target, parent) => {\n const start = view.coordsAtPos(_from);\n let left = start.left - parent.left;\n let top = selected.bottom - parent.top + 14;\n\n if (left < 0) {\n left = 0;\n }\n\n if (window.innerHeight - start.bottom < target.height) {\n top = selected.top - parent.top - target.height - 14;\n }\n return [top, left];\n });\n\n return null;\n },\n };\n },\n });\n};\n","/* Copyright 2021, Milkdown by Mirone. */\nimport { EmojiButton } from '@joeattardi/emoji-button';\nimport { Decoration, DecorationSet, EditorView, Plugin } from '@milkdown/prose';\nimport { Utils } from '@milkdown/utils';\n\nimport { parse } from './parse';\n\nconst keyword = ':emoji:';\n\nconst checkTrigger = (\n view: EditorView,\n from: number,\n to: number,\n text: string,\n setRange: (from: number, to: number) => void,\n) => {\n if (view.composing) return false;\n const { state } = view;\n const $from = state.doc.resolve(from);\n if ($from.parent.type.spec.code) return false;\n const textBefore =\n $from.parent.textBetween($from.parentOffset - keyword.length + 1, $from.parentOffset, undefined, '\\ufffc') +\n text;\n if (textBefore === keyword) {\n setRange(from - keyword.length + 1, to + 1);\n return true;\n }\n return false;\n};\n\nexport const picker = (utils: Utils) => {\n let trigger = false;\n const holder = document.createElement('span');\n let _from = 0;\n let _to = 0;\n const off = () => {\n trigger = false;\n _from = 0;\n _to = 0;\n };\n\n const plugin = new Plugin({\n props: {\n handleKeyDown() {\n off();\n return false;\n },\n handleClick() {\n off();\n return false;\n },\n handleTextInput(view, from, to, text) {\n trigger = checkTrigger(view, from, to, text, (from, to) => {\n _from = from;\n _to = to;\n });\n\n if (!trigger) {\n off();\n }\n return false;\n },\n decorations(state) {\n if (!trigger) return null;\n\n return DecorationSet.create(state.doc, [Decoration.widget(state.selection.to, holder)]);\n },\n },\n view: (editorView) => {\n const { parentNode } = editorView.dom;\n if (!parentNode) {\n throw new Error();\n }\n utils.getStyle(({ palette, font }, { injectGlobal }) => {\n const css = injectGlobal;\n css`\n .emoji-picker {\n --dark-search-background-color: ${palette('surface')} !important;\n --dark-text-color: ${palette('neutral', 0.87)} !important;\n --dark-background-color: ${palette('background')} !important;\n --dark-border-color: ${palette('shadow')} !important;\n --dark-hover-color: ${palette('secondary', 0.12)} !important;\n --dark-blue-color: ${palette('primary')} !important;\n --dark-search-icon-color: ${palette('primary')} !important;\n --dark-category-button-color: ${palette('secondary', 0.4)} !important;\n --font: ${font.typography} !important;\n --font-size: 1rem !important;\n }\n `;\n });\n const emojiPicker = new EmojiButton({\n rootElement: parentNode as HTMLElement,\n autoFocusSearch: false,\n style: 'twemoji',\n theme: 'dark',\n zIndex: 99,\n });\n emojiPicker.on('emoji', (selection) => {\n const start = _from;\n const end = _to;\n off();\n const html = parse(selection.emoji);\n const node = editorView.state.schema.node('emoji', { html });\n const { tr } = editorView.state;\n\n editorView.dispatch(tr.replaceRangeWith(start, end, node));\n });\n return {\n update: () => {\n if (!trigger) {\n emojiPicker.hidePicker();\n return null;\n }\n emojiPicker.showPicker(holder);\n return null;\n },\n destroy: () => {\n emojiPicker.destroyPicker();\n },\n };\n },\n });\n\n return plugin;\n};\n","/* Copyright 2021, Milkdown by Mirone. */\nimport emojiRegex from 'emoji-regex';\nimport { Literal, Node, Parent } from 'unist';\n\nimport { parse } from './parse';\n\nconst regex = emojiRegex();\n\nconst isParent = (node: Node): node is Parent => !!(node as Parent).children;\nconst isLiteral = (node: Node): node is Literal => !!(node as Literal).value;\n\nfunction flatMap(ast: Node, fn: (node: Node, index: number, parent: Node | null) => Node[]) {\n return transform(ast, 0, null)[0];\n\n function transform(node: Node, index: number, parent: Node | null) {\n if (isParent(node)) {\n const out = [];\n for (let i = 0, n = node.children.length; i < n; i++) {\n const xs = transform(node.children[i], i, node);\n if (xs) {\n for (let j = 0, m = xs.length; j < m; j++) {\n out.push(xs[j]);\n }\n }\n }\n node.children = out;\n }\n\n return fn(node, index, parent);\n }\n}\n\nexport const twemojiPlugin = () => {\n function transformer(tree: Node) {\n flatMap(tree, (node) => {\n if (!isLiteral(node)) {\n return [node];\n }\n const value = node.value as string;\n const output: Literal<string>[] = [];\n let match;\n let str = value;\n while ((match = regex.exec(str))) {\n const { index } = match;\n const emoji = match[0];\n if (index > 0) {\n output.push({ ...node, value: str.slice(0, index) });\n }\n output.push({ ...node, value: parse(emoji), type: 'emoji' });\n str = str.slice(index + emoji.length);\n }\n if (str.length) {\n output.push({ ...node, value: str });\n }\n return output;\n });\n }\n return transformer;\n};\n","/* Copyright 2021, Milkdown by Mirone. */\nimport { RemarkPlugin } from '@milkdown/core';\nimport { InputRule } from '@milkdown/prose';\nimport { createNode } from '@milkdown/utils';\nimport nodeEmoji from 'node-emoji';\nimport remarkEmoji from 'remark-emoji';\n\nimport { input } from './constant';\nimport { filter } from './filter';\nimport { parse } from './parse';\nimport { picker } from './picker';\nimport { twemojiPlugin } from './remark-twemoji';\n\nexport const emojiNode = createNode((utils) => {\n const style = utils.getStyle(\n (_, { css }) => css`\n display: inline-flex;\n justify-content: center;\n align-items: center;\n\n .emoji {\n height: 1em;\n width: 1em;\n margin: 0 0.05em 0 0.1em;\n vertical-align: -0.1em;\n }\n `,\n );\n return {\n id: 'emoji',\n schema: () => ({\n group: 'inline',\n inline: true,\n selectable: false,\n attrs: {\n html: {\n default: '',\n },\n },\n parseDOM: [\n {\n tag: 'span[data-type=\"emoji\"]',\n getAttrs: (dom) => {\n if (!(dom instanceof HTMLElement)) {\n throw new Error();\n }\n return { html: dom.innerHTML };\n },\n },\n ],\n toDOM: (node) => {\n const span = document.createElement('span');\n span.dataset.type = 'emoji';\n if (style) {\n span.classList.add(style);\n }\n span.classList.add('emoji-wrapper');\n span.innerHTML = node.attrs.html;\n return { dom: span };\n },\n parseMarkdown: {\n match: ({ type }) => type === 'emoji',\n runner: (state, node, type) => {\n state.addNode(type, { html: node.value as string });\n },\n },\n toMarkdown: {\n match: (node) => node.type.name === 'emoji',\n runner: (state, node) => {\n const span = document.createElement('span');\n span.innerHTML = node.attrs.html;\n const img = span.querySelector('img');\n const title = img?.title;\n span.remove();\n state.addNode('text', undefined, title);\n },\n },\n }),\n inputRules: (nodeType) => [\n new InputRule(input, (state, match, start, end) => {\n const content = match[0];\n if (!content) return null;\n const got = nodeEmoji.get(content);\n if (!got || content.includes(got)) return null;\n\n const html = parse(got);\n\n return state.tr\n .setMeta('emoji', true)\n .replaceRangeWith(start, end, nodeType.create({ html }))\n .scrollIntoView();\n }),\n ],\n remarkPlugins: () => [remarkEmoji as RemarkPlugin, twemojiPlugin],\n prosePlugins: () => [picker(utils), filter(utils)],\n };\n});\n","/* Copyright 2021, Milkdown by Mirone. */\nimport { AtomList } from '@milkdown/utils';\n\nimport { emojiNode } from './node';\n\nexport const emoji = AtomList.create([emojiNode()]);\n\nexport { emojiNode } from './node';\n"],"names":["checkTrigger"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.es.js","sources":["../src/constant.ts","../src/parse.ts","../src/filter/helper.ts","../src/filter/style.ts","../src/filter/index.ts","../src/picker.ts","../src/remark-twemoji.ts","../src/node.ts","../src/index.ts"],"sourcesContent":["/* Copyright 2021, Milkdown by Mirone. */\nexport const part = /:\\+1|:-1|:[\\w-]+/;\nexport const full = /:\\+1:|:-1:|:[\\w-]+:/;\nexport const input = /(:([^:\\s]+):)$/;\nexport const keyword = ':emoji:';\n","/* Copyright 2021, Milkdown by Mirone. */\nimport twemoji from 'twemoji';\n\nexport const parse = (emoji: string) => twemoji.parse(emoji, { attributes: (text) => ({ title: text }) });\n","/* Copyright 2021, Milkdown by Mirone. */\n\nimport { EditorView } from '@milkdown/prose';\nimport { Emoji } from 'node-emoji';\n\nimport { full, part } from '../constant';\nimport { parse } from '../parse';\n\nexport const checkTrigger = (\n view: EditorView,\n from: number,\n to: number,\n text: string,\n setRange: (from: number, to: number) => void,\n setSearch: (words: string) => void,\n) => {\n if (view.composing) return false;\n const { state } = view;\n const $from = state.doc.resolve(from);\n if ($from.parent.type.spec.code) return false;\n const textBefore = (\n $from.parent.textBetween(Math.max(0, $from.parentOffset - 10), $from.parentOffset, undefined, '\\ufffc') + text\n ).toLowerCase();\n if (full.test(textBefore)) {\n return false;\n }\n const regex = part.exec(textBefore);\n if (regex && regex[0] && textBefore.endsWith(regex[0])) {\n const match = regex[0];\n setRange(from - (match.length - text.length), to);\n setSearch(match);\n return true;\n }\n return false;\n};\n\nexport const renderDropdownList = (\n list: Emoji[],\n dropDown: HTMLElement,\n $active: HTMLElement | null,\n onConfirm: () => void,\n setActive: (active: HTMLElement | null) => void,\n) => {\n dropDown.innerHTML = '';\n list.forEach(({ emoji, key }, i) => {\n const container = document.createElement('div');\n container.className = 'milkdown-emoji-filter_item';\n\n const emojiSpan = document.createElement('span');\n emojiSpan.innerHTML = parse(emoji);\n\n emojiSpan.className = 'milkdown-emoji-filter_item-emoji';\n const keySpan = document.createElement('span');\n keySpan.textContent = ':' + key + ':';\n keySpan.className = 'milkdown-emoji-filter_item-key';\n\n container.appendChild(emojiSpan);\n container.appendChild(keySpan);\n dropDown.appendChild(container);\n\n if (i === 0) {\n container.classList.add('active');\n setActive(container);\n }\n\n container.addEventListener('mouseenter', (e) => {\n if ($active) {\n $active.classList.remove('active');\n }\n const { target } = e;\n if (!(target instanceof HTMLElement)) return;\n target.classList.add('active');\n setActive(target);\n });\n container.addEventListener('mouseleave', (e) => {\n const { target } = e;\n if (!(target instanceof HTMLElement)) return;\n target.classList.remove('active');\n });\n container.addEventListener('mousedown', (e) => {\n onConfirm();\n e.preventDefault();\n });\n });\n};\n","/* Copyright 2021, Milkdown by Mirone. */\nimport type { Emotion, ThemeTool } from '@milkdown/core';\n\nexport const injectStyle = ({ size, mixin, palette, font }: ThemeTool, { css, cx }: Emotion) => {\n const border = mixin.border?.();\n const shadow = mixin.shadow?.();\n\n const style = css`\n position: absolute;\n &.hide {\n display: none;\n }\n\n border-radius: ${size.radius};\n background: ${palette('surface')};\n\n .milkdown-emoji-filter_item {\n display: flex;\n gap: 0.5rem;\n height: 2.25rem;\n padding: 0 1rem;\n align-items: center;\n justify-content: flex-start;\n cursor: pointer;\n line-height: 2;\n font-family: ${font.typography};\n font-size: 0.875rem;\n &.active {\n background: ${palette('secondary', 0.12)};\n color: ${palette('primary')};\n }\n }\n\n .emoji {\n height: 1em;\n width: 1em;\n margin: 0 0.05em 0 0.1em;\n vertical-align: -0.1em;\n }\n `;\n return cx(border, shadow, style);\n};\n","/* Copyright 2021, Milkdown by Mirone. */\n\nimport { calculateNodePosition, Plugin, PluginKey } from '@milkdown/prose';\nimport { Utils } from '@milkdown/utils';\nimport { search } from 'node-emoji';\n\nimport { checkTrigger, renderDropdownList } from './helper';\nimport { injectStyle } from './style';\n\nexport const key = new PluginKey('MILKDOWN_PLUGIN_EMOJI_FILTER');\n\nexport const filter = (utils: Utils) => {\n let trigger = false;\n let _from = 0;\n let _search = '';\n let $active: null | HTMLElement = null;\n\n const off = () => {\n trigger = false;\n _from = 0;\n _search = '';\n $active = null;\n };\n\n return new Plugin({\n key,\n props: {\n handleKeyDown(_, event) {\n if (['Delete', 'Backspace'].includes(event.key)) {\n _search = _search.slice(0, -1);\n if (_search.length <= 1) {\n off();\n }\n return false;\n }\n if (!trigger) return false;\n if (!['ArrowUp', 'ArrowDown', 'Enter'].includes(event.key)) {\n return false;\n }\n return true;\n },\n handleTextInput(view, from, to, text) {\n trigger = checkTrigger(\n view,\n from,\n to,\n text,\n (from) => {\n _from = from;\n },\n (search) => {\n _search = search;\n },\n );\n if (!trigger) {\n off();\n }\n return false;\n },\n },\n view: (editorView) => {\n const { parentNode } = editorView.dom;\n if (!parentNode) {\n throw new Error();\n }\n\n const dropDown = document.createElement('div');\n const style = utils.getStyle(injectStyle);\n\n if (style) {\n style.split(' ').forEach((x) => dropDown.classList.add(x));\n }\n\n dropDown.classList.add('milkdown-emoji-filter', 'hide');\n\n const replace = () => {\n if (!$active) return;\n\n const { tr } = editorView.state;\n const node = editorView.state.schema.node('emoji', { html: $active.firstElementChild?.innerHTML });\n\n editorView.dispatch(tr.delete(_from, _from + _search.length).insert(_from, node));\n off();\n dropDown.classList.add('hide');\n };\n\n parentNode.appendChild(dropDown);\n parentNode.addEventListener('keydown', (e) => {\n if (!trigger || !(e instanceof KeyboardEvent)) return;\n\n const { key } = e;\n\n if (key === 'Enter') {\n replace();\n return;\n }\n\n if (['ArrowDown', 'ArrowUp'].includes(key)) {\n const next =\n key === 'ArrowDown'\n ? $active?.nextElementSibling || dropDown.firstElementChild\n : $active?.previousElementSibling || dropDown.lastElementChild;\n if ($active) {\n $active.classList.remove('active');\n }\n if (!next) return;\n next.classList.add('active');\n $active = next as HTMLElement;\n\n return;\n }\n });\n parentNode.addEventListener('mousedown', (e) => {\n if (!trigger) return;\n\n e.stopPropagation();\n off();\n dropDown.classList.add('hide');\n });\n\n return {\n update: (view) => {\n const { selection } = view.state;\n\n if (selection.from - selection.to !== 0 || !trigger) {\n off();\n dropDown.classList.add('hide');\n return null;\n }\n const result = search(_search).slice(0, 5);\n const { node } = view.domAtPos(_from);\n if (result.length === 0 || !node) {\n dropDown.classList.add('hide');\n return null;\n }\n\n dropDown.classList.remove('hide');\n renderDropdownList(result, dropDown, $active, replace, (a) => {\n $active = a;\n });\n calculateNodePosition(view, dropDown, (selected, target, parent) => {\n const $editor = dropDown.parentElement;\n if (!$editor) {\n throw new Error();\n }\n const start = view.coordsAtPos(_from);\n let left = start.left - parent.left;\n let top = selected.bottom - parent.top + 14 + $editor.scrollTop;\n\n if (left < 0) {\n left = 0;\n }\n\n if (window.innerHeight - start.bottom < target.height) {\n top = selected.top - parent.top - target.height - 14 + $editor.scrollTop;\n }\n return [top, left];\n });\n\n return null;\n },\n };\n },\n });\n};\n","/* Copyright 2021, Milkdown by Mirone. */\nimport { EmojiButton } from '@joeattardi/emoji-button';\nimport { Decoration, DecorationSet, EditorView, Plugin, PluginKey } from '@milkdown/prose';\nimport { Utils } from '@milkdown/utils';\n\nimport { parse } from './parse';\n\nconst keyword = ':emoji:';\nexport const key = new PluginKey('MILKDOWN_PLUGIN_EMOJI_PICKER');\n\nconst checkTrigger = (\n view: EditorView,\n from: number,\n to: number,\n text: string,\n setRange: (from: number, to: number) => void,\n) => {\n if (view.composing) return false;\n const { state } = view;\n const $from = state.doc.resolve(from);\n if ($from.parent.type.spec.code) return false;\n const textBefore =\n $from.parent.textBetween($from.parentOffset - keyword.length + 1, $from.parentOffset, undefined, '\\ufffc') +\n text;\n if (textBefore === keyword) {\n setRange(from - keyword.length + 1, to + 1);\n return true;\n }\n return false;\n};\n\nexport const picker = (utils: Utils) => {\n let trigger = false;\n const holder = document.createElement('span');\n let _from = 0;\n let _to = 0;\n const off = () => {\n trigger = false;\n _from = 0;\n _to = 0;\n };\n\n const plugin = new Plugin({\n key,\n props: {\n handleKeyDown() {\n off();\n return false;\n },\n handleClick() {\n off();\n return false;\n },\n handleTextInput(view, from, to, text) {\n trigger = checkTrigger(view, from, to, text, (from, to) => {\n _from = from;\n _to = to;\n });\n\n if (!trigger) {\n off();\n }\n return false;\n },\n decorations(state) {\n if (!trigger) return null;\n\n return DecorationSet.create(state.doc, [Decoration.widget(state.selection.to, holder)]);\n },\n },\n view: (editorView) => {\n const { parentNode } = editorView.dom;\n if (!parentNode) {\n throw new Error();\n }\n utils.getStyle(({ palette, font }, { injectGlobal }) => {\n const css = injectGlobal;\n css`\n .emoji-picker {\n --dark-search-background-color: ${palette('surface')} !important;\n --dark-text-color: ${palette('neutral', 0.87)} !important;\n --dark-background-color: ${palette('background')} !important;\n --dark-border-color: ${palette('shadow')} !important;\n --dark-hover-color: ${palette('secondary', 0.12)} !important;\n --dark-blue-color: ${palette('primary')} !important;\n --dark-search-icon-color: ${palette('primary')} !important;\n --dark-category-button-color: ${palette('secondary', 0.4)} !important;\n --font: ${font.typography} !important;\n --font-size: 1rem !important;\n }\n `;\n });\n const emojiPicker = new EmojiButton({\n rootElement: parentNode as HTMLElement,\n autoFocusSearch: false,\n style: 'twemoji',\n theme: 'dark',\n zIndex: 99,\n });\n emojiPicker.on('emoji', (selection) => {\n const start = _from;\n const end = _to;\n off();\n const html = parse(selection.emoji);\n const node = editorView.state.schema.node('emoji', { html });\n const { tr } = editorView.state;\n\n editorView.dispatch(tr.replaceRangeWith(start, end, node));\n });\n return {\n update: () => {\n if (!trigger) {\n emojiPicker.hidePicker();\n return null;\n }\n emojiPicker.showPicker(holder);\n return null;\n },\n destroy: () => {\n emojiPicker.destroyPicker();\n },\n };\n },\n });\n\n return plugin;\n};\n","/* Copyright 2021, Milkdown by Mirone. */\nimport emojiRegex from 'emoji-regex';\nimport { Literal, Node, Parent } from 'unist';\n\nimport { parse } from './parse';\n\nconst regex = emojiRegex();\n\nconst isParent = (node: Node): node is Parent => !!(node as Parent).children;\nconst isLiteral = (node: Node): node is Literal => !!(node as Literal).value;\n\nfunction flatMap(ast: Node, fn: (node: Node, index: number, parent: Node | null) => Node[]) {\n return transform(ast, 0, null)[0];\n\n function transform(node: Node, index: number, parent: Node | null) {\n if (isParent(node)) {\n const out = [];\n for (let i = 0, n = node.children.length; i < n; i++) {\n const nthChild = node.children[i];\n if (nthChild) {\n const xs = transform(nthChild, i, node);\n if (xs) {\n for (let j = 0, m = xs.length; j < m; j++) {\n const item = xs[j];\n if (item) {\n out.push(item);\n }\n }\n }\n }\n }\n node.children = out;\n }\n\n return fn(node, index, parent);\n }\n}\n\nexport const twemojiPlugin = () => {\n function transformer(tree: Node) {\n flatMap(tree, (node) => {\n if (!isLiteral(node)) {\n return [node];\n }\n const value = node.value as string;\n const output: Literal<string>[] = [];\n let match;\n let str = value;\n while ((match = regex.exec(str))) {\n const { index } = match;\n const emoji = match[0];\n if (emoji) {\n if (index > 0) {\n output.push({ ...node, value: str.slice(0, index) });\n }\n output.push({ ...node, value: parse(emoji), type: 'emoji' });\n str = str.slice(index + emoji.length);\n }\n }\n if (str.length) {\n output.push({ ...node, value: str });\n }\n return output;\n });\n }\n return transformer;\n};\n","/* Copyright 2021, Milkdown by Mirone. */\nimport { RemarkPlugin } from '@milkdown/core';\nimport { InputRule } from '@milkdown/prose';\nimport { createNode } from '@milkdown/utils';\nimport nodeEmoji from 'node-emoji';\nimport remarkEmoji from 'remark-emoji';\n\nimport { input } from './constant';\nimport { filter } from './filter';\nimport { parse } from './parse';\nimport { picker } from './picker';\nimport { twemojiPlugin } from './remark-twemoji';\n\nexport const emojiNode = createNode((utils) => {\n const style = utils.getStyle(\n (_, { css }) => css`\n display: inline-flex;\n justify-content: center;\n align-items: center;\n\n .emoji {\n height: 1em;\n width: 1em;\n margin: 0 0.05em 0 0.1em;\n vertical-align: -0.1em;\n }\n `,\n );\n return {\n id: 'emoji',\n schema: () => ({\n group: 'inline',\n inline: true,\n selectable: false,\n attrs: {\n html: {\n default: '',\n },\n },\n parseDOM: [\n {\n tag: 'span[data-type=\"emoji\"]',\n getAttrs: (dom) => {\n if (!(dom instanceof HTMLElement)) {\n throw new Error();\n }\n return { html: dom.innerHTML };\n },\n },\n ],\n toDOM: (node) => {\n const span = document.createElement('span');\n span.dataset['type'] = 'emoji';\n if (style) {\n span.classList.add(style);\n }\n span.classList.add('emoji-wrapper');\n span.innerHTML = node.attrs['html'];\n return { dom: span };\n },\n parseMarkdown: {\n match: ({ type }) => type === 'emoji',\n runner: (state, node, type) => {\n state.addNode(type, { html: node['value'] as string });\n },\n },\n toMarkdown: {\n match: (node) => node.type.name === 'emoji',\n runner: (state, node) => {\n const span = document.createElement('span');\n span.innerHTML = node.attrs['html'];\n const img = span.querySelector('img');\n const title = img?.title;\n span.remove();\n state.addNode('text', undefined, title);\n },\n },\n }),\n inputRules: (nodeType) => [\n new InputRule(input, (state, match, start, end) => {\n const content = match[0];\n if (!content) return null;\n const got = nodeEmoji.get(content);\n if (!got || content.includes(got)) return null;\n\n const html = parse(got);\n\n return state.tr\n .setMeta('emoji', true)\n .replaceRangeWith(start, end, nodeType.create({ html }))\n .scrollIntoView();\n }),\n ],\n remarkPlugins: () => [remarkEmoji as RemarkPlugin, twemojiPlugin],\n prosePlugins: () => [picker(utils), filter(utils)],\n };\n});\n","/* Copyright 2021, Milkdown by Mirone. */\nimport { AtomList } from '@milkdown/utils';\n\nimport { emojiNode } from './node';\n\nexport const emoji = AtomList.create([emojiNode()]);\n\nexport { emojiNode } from './node';\n"],"names":["checkTrigger","key"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helper.d.ts","sourceRoot":"","sources":["helper.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAKnC,eAAO,MAAM,YAAY,SACf,UAAU,QACV,MAAM,MACR,MAAM,QACJ,MAAM,mBACK,MAAM,MAAM,MAAM,KAAK,IAAI,qBACzB,MAAM,KAAK,IAAI,
|
|
1
|
+
{"version":3,"file":"helper.d.ts","sourceRoot":"","sources":["helper.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAKnC,eAAO,MAAM,YAAY,SACf,UAAU,QACV,MAAM,MACR,MAAM,QACJ,MAAM,mBACK,MAAM,MAAM,MAAM,KAAK,IAAI,qBACzB,MAAM,KAAK,IAAI,YAoBrC,CAAC;AAEF,eAAO,MAAM,kBAAkB,SACrB,KAAK,EAAE,YACH,WAAW,WACZ,WAAW,GAAG,IAAI,aAChB,MAAM,IAAI,sBACD,WAAW,GAAG,IAAI,KAAK,IAAI,SA2ClD,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { Plugin } from '@milkdown/prose';
|
|
1
|
+
import { Plugin, PluginKey } from '@milkdown/prose';
|
|
2
2
|
import { Utils } from '@milkdown/utils';
|
|
3
|
+
export declare const key: PluginKey<any, any>;
|
|
3
4
|
export declare const filter: (utils: Utils) => Plugin<any, any>;
|
|
4
5
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAyB,MAAM,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAyB,MAAM,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC3E,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAMxC,eAAO,MAAM,GAAG,qBAAgD,CAAC;AAEjE,eAAO,MAAM,MAAM,UAAW,KAAK,qBAyJlC,CAAC"}
|
package/lib/src/picker.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { Plugin } from '@milkdown/prose';
|
|
1
|
+
import { Plugin, PluginKey } from '@milkdown/prose';
|
|
2
2
|
import { Utils } from '@milkdown/utils';
|
|
3
|
+
export declare const key: PluginKey<any, any>;
|
|
3
4
|
export declare const picker: (utils: Utils) => Plugin<any, any>;
|
|
4
5
|
//# sourceMappingURL=picker.d.ts.map
|
package/lib/src/picker.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"picker.d.ts","sourceRoot":"","sources":["picker.ts"],"names":[],"mappings":"AAEA,OAAO,EAAyC,MAAM,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"picker.d.ts","sourceRoot":"","sources":["picker.ts"],"names":[],"mappings":"AAEA,OAAO,EAAyC,MAAM,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC3F,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAKxC,eAAO,MAAM,GAAG,qBAAgD,CAAC;AAuBjE,eAAO,MAAM,MAAM,UAAW,KAAK,qBA+FlC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remark-twemoji.d.ts","sourceRoot":"","sources":["remark-twemoji.ts"],"names":[],"mappings":"AAEA,OAAO,EAAW,IAAI,EAAU,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"remark-twemoji.d.ts","sourceRoot":"","sources":["remark-twemoji.ts"],"names":[],"mappings":"AAEA,OAAO,EAAW,IAAI,EAAU,MAAM,OAAO,CAAC;AAoC9C,eAAO,MAAM,aAAa,eACK,IAAI,SA2BlC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@milkdown/plugin-emoji",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.5.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./lib/index.es.js",
|
|
6
6
|
"types": "./lib/index.d.ts",
|
|
@@ -14,11 +14,17 @@
|
|
|
14
14
|
"milkdown",
|
|
15
15
|
"milkdown plugin"
|
|
16
16
|
],
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"@milkdown/core": "5.5.0",
|
|
19
|
+
"@milkdown/prose": "5.5.0"
|
|
20
|
+
},
|
|
21
|
+
"peerDependencies": {
|
|
22
|
+
"@milkdown/core": "^5.4.0",
|
|
23
|
+
"@milkdown/prose": "^5.4.0"
|
|
24
|
+
},
|
|
17
25
|
"dependencies": {
|
|
18
26
|
"@joeattardi/emoji-button": "^4.6.0",
|
|
19
|
-
"@milkdown/
|
|
20
|
-
"@milkdown/prose": "5.3.4",
|
|
21
|
-
"@milkdown/utils": "5.3.4",
|
|
27
|
+
"@milkdown/utils": "5.5.0",
|
|
22
28
|
"@types/node-emoji": "^1.8.1",
|
|
23
29
|
"@types/twemoji": "^12.1.2",
|
|
24
30
|
"emoji-regex": "^10.0.0",
|
package/src/filter/helper.ts
CHANGED
|
@@ -18,13 +18,14 @@ export const checkTrigger = (
|
|
|
18
18
|
const { state } = view;
|
|
19
19
|
const $from = state.doc.resolve(from);
|
|
20
20
|
if ($from.parent.type.spec.code) return false;
|
|
21
|
-
const textBefore =
|
|
22
|
-
$from.parent.textBetween(Math.max(0, $from.parentOffset - 10), $from.parentOffset, undefined, '\ufffc') + text
|
|
21
|
+
const textBefore = (
|
|
22
|
+
$from.parent.textBetween(Math.max(0, $from.parentOffset - 10), $from.parentOffset, undefined, '\ufffc') + text
|
|
23
|
+
).toLowerCase();
|
|
23
24
|
if (full.test(textBefore)) {
|
|
24
25
|
return false;
|
|
25
26
|
}
|
|
26
27
|
const regex = part.exec(textBefore);
|
|
27
|
-
if (regex && textBefore.endsWith(regex[0])) {
|
|
28
|
+
if (regex && regex[0] && textBefore.endsWith(regex[0])) {
|
|
28
29
|
const match = regex[0];
|
|
29
30
|
setRange(from - (match.length - text.length), to);
|
|
30
31
|
setSearch(match);
|
package/src/filter/index.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
/* Copyright 2021, Milkdown by Mirone. */
|
|
2
2
|
|
|
3
|
-
import { calculateNodePosition, Plugin } from '@milkdown/prose';
|
|
3
|
+
import { calculateNodePosition, Plugin, PluginKey } from '@milkdown/prose';
|
|
4
4
|
import { Utils } from '@milkdown/utils';
|
|
5
5
|
import { search } from 'node-emoji';
|
|
6
6
|
|
|
7
7
|
import { checkTrigger, renderDropdownList } from './helper';
|
|
8
8
|
import { injectStyle } from './style';
|
|
9
9
|
|
|
10
|
+
export const key = new PluginKey('MILKDOWN_PLUGIN_EMOJI_FILTER');
|
|
11
|
+
|
|
10
12
|
export const filter = (utils: Utils) => {
|
|
11
13
|
let trigger = false;
|
|
12
14
|
let _from = 0;
|
|
@@ -21,6 +23,7 @@ export const filter = (utils: Utils) => {
|
|
|
21
23
|
};
|
|
22
24
|
|
|
23
25
|
return new Plugin({
|
|
26
|
+
key,
|
|
24
27
|
props: {
|
|
25
28
|
handleKeyDown(_, event) {
|
|
26
29
|
if (['Delete', 'Backspace'].includes(event.key)) {
|
|
@@ -117,7 +120,10 @@ export const filter = (utils: Utils) => {
|
|
|
117
120
|
|
|
118
121
|
return {
|
|
119
122
|
update: (view) => {
|
|
120
|
-
|
|
123
|
+
const { selection } = view.state;
|
|
124
|
+
|
|
125
|
+
if (selection.from - selection.to !== 0 || !trigger) {
|
|
126
|
+
off();
|
|
121
127
|
dropDown.classList.add('hide');
|
|
122
128
|
return null;
|
|
123
129
|
}
|
|
@@ -133,16 +139,20 @@ export const filter = (utils: Utils) => {
|
|
|
133
139
|
$active = a;
|
|
134
140
|
});
|
|
135
141
|
calculateNodePosition(view, dropDown, (selected, target, parent) => {
|
|
142
|
+
const $editor = dropDown.parentElement;
|
|
143
|
+
if (!$editor) {
|
|
144
|
+
throw new Error();
|
|
145
|
+
}
|
|
136
146
|
const start = view.coordsAtPos(_from);
|
|
137
147
|
let left = start.left - parent.left;
|
|
138
|
-
let top = selected.bottom - parent.top + 14;
|
|
148
|
+
let top = selected.bottom - parent.top + 14 + $editor.scrollTop;
|
|
139
149
|
|
|
140
150
|
if (left < 0) {
|
|
141
151
|
left = 0;
|
|
142
152
|
}
|
|
143
153
|
|
|
144
154
|
if (window.innerHeight - start.bottom < target.height) {
|
|
145
|
-
top = selected.top - parent.top - target.height - 14;
|
|
155
|
+
top = selected.top - parent.top - target.height - 14 + $editor.scrollTop;
|
|
146
156
|
}
|
|
147
157
|
return [top, left];
|
|
148
158
|
});
|
package/src/node.ts
CHANGED
|
@@ -50,25 +50,25 @@ export const emojiNode = createNode((utils) => {
|
|
|
50
50
|
],
|
|
51
51
|
toDOM: (node) => {
|
|
52
52
|
const span = document.createElement('span');
|
|
53
|
-
span.dataset
|
|
53
|
+
span.dataset['type'] = 'emoji';
|
|
54
54
|
if (style) {
|
|
55
55
|
span.classList.add(style);
|
|
56
56
|
}
|
|
57
57
|
span.classList.add('emoji-wrapper');
|
|
58
|
-
span.innerHTML = node.attrs
|
|
58
|
+
span.innerHTML = node.attrs['html'];
|
|
59
59
|
return { dom: span };
|
|
60
60
|
},
|
|
61
61
|
parseMarkdown: {
|
|
62
62
|
match: ({ type }) => type === 'emoji',
|
|
63
63
|
runner: (state, node, type) => {
|
|
64
|
-
state.addNode(type, { html: node
|
|
64
|
+
state.addNode(type, { html: node['value'] as string });
|
|
65
65
|
},
|
|
66
66
|
},
|
|
67
67
|
toMarkdown: {
|
|
68
68
|
match: (node) => node.type.name === 'emoji',
|
|
69
69
|
runner: (state, node) => {
|
|
70
70
|
const span = document.createElement('span');
|
|
71
|
-
span.innerHTML = node.attrs
|
|
71
|
+
span.innerHTML = node.attrs['html'];
|
|
72
72
|
const img = span.querySelector('img');
|
|
73
73
|
const title = img?.title;
|
|
74
74
|
span.remove();
|
package/src/picker.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
/* Copyright 2021, Milkdown by Mirone. */
|
|
2
2
|
import { EmojiButton } from '@joeattardi/emoji-button';
|
|
3
|
-
import { Decoration, DecorationSet, EditorView, Plugin } from '@milkdown/prose';
|
|
3
|
+
import { Decoration, DecorationSet, EditorView, Plugin, PluginKey } from '@milkdown/prose';
|
|
4
4
|
import { Utils } from '@milkdown/utils';
|
|
5
5
|
|
|
6
6
|
import { parse } from './parse';
|
|
7
7
|
|
|
8
8
|
const keyword = ':emoji:';
|
|
9
|
+
export const key = new PluginKey('MILKDOWN_PLUGIN_EMOJI_PICKER');
|
|
9
10
|
|
|
10
11
|
const checkTrigger = (
|
|
11
12
|
view: EditorView,
|
|
@@ -40,6 +41,7 @@ export const picker = (utils: Utils) => {
|
|
|
40
41
|
};
|
|
41
42
|
|
|
42
43
|
const plugin = new Plugin({
|
|
44
|
+
key,
|
|
43
45
|
props: {
|
|
44
46
|
handleKeyDown() {
|
|
45
47
|
off();
|
package/src/remark-twemoji.ts
CHANGED
|
@@ -16,10 +16,16 @@ function flatMap(ast: Node, fn: (node: Node, index: number, parent: Node | null)
|
|
|
16
16
|
if (isParent(node)) {
|
|
17
17
|
const out = [];
|
|
18
18
|
for (let i = 0, n = node.children.length; i < n; i++) {
|
|
19
|
-
const
|
|
20
|
-
if (
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
const nthChild = node.children[i];
|
|
20
|
+
if (nthChild) {
|
|
21
|
+
const xs = transform(nthChild, i, node);
|
|
22
|
+
if (xs) {
|
|
23
|
+
for (let j = 0, m = xs.length; j < m; j++) {
|
|
24
|
+
const item = xs[j];
|
|
25
|
+
if (item) {
|
|
26
|
+
out.push(item);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
23
29
|
}
|
|
24
30
|
}
|
|
25
31
|
}
|
|
@@ -43,11 +49,13 @@ export const twemojiPlugin = () => {
|
|
|
43
49
|
while ((match = regex.exec(str))) {
|
|
44
50
|
const { index } = match;
|
|
45
51
|
const emoji = match[0];
|
|
46
|
-
if (
|
|
47
|
-
|
|
52
|
+
if (emoji) {
|
|
53
|
+
if (index > 0) {
|
|
54
|
+
output.push({ ...node, value: str.slice(0, index) });
|
|
55
|
+
}
|
|
56
|
+
output.push({ ...node, value: parse(emoji), type: 'emoji' });
|
|
57
|
+
str = str.slice(index + emoji.length);
|
|
48
58
|
}
|
|
49
|
-
output.push({ ...node, value: parse(emoji), type: 'emoji' });
|
|
50
|
-
str = str.slice(index + emoji.length);
|
|
51
59
|
}
|
|
52
60
|
if (str.length) {
|
|
53
61
|
output.push({ ...node, value: str });
|