@milkdown/plugin-emoji 5.4.0 → 6.0.0-next.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.
Files changed (40) hide show
  1. package/lib/{src/constant.d.ts → constant.d.ts} +0 -0
  2. package/lib/constant.d.ts.map +1 -0
  3. package/lib/{src/filter → filter}/helper.d.ts +0 -0
  4. package/lib/filter/helper.d.ts.map +1 -0
  5. package/lib/filter/index.d.ts +5 -0
  6. package/lib/filter/index.d.ts.map +1 -0
  7. package/lib/filter/style.d.ts +3 -0
  8. package/lib/filter/style.d.ts.map +1 -0
  9. package/lib/index.d.ts +4 -1
  10. package/lib/index.d.ts.map +1 -0
  11. package/lib/index.es.js +98 -64
  12. package/lib/index.es.js.map +1 -1
  13. package/lib/{src/node.d.ts → node.d.ts} +1 -1
  14. package/lib/node.d.ts.map +1 -0
  15. package/lib/{src/parse.d.ts → parse.d.ts} +0 -0
  16. package/lib/parse.d.ts.map +1 -0
  17. package/lib/picker.d.ts +5 -0
  18. package/lib/picker.d.ts.map +1 -0
  19. package/lib/{src/remark-twemoji.d.ts → remark-twemoji.d.ts} +0 -0
  20. package/lib/remark-twemoji.d.ts.map +1 -0
  21. package/package.json +34 -10
  22. package/src/filter/helper.ts +17 -9
  23. package/src/filter/index.ts +22 -9
  24. package/src/filter/style.ts +22 -10
  25. package/src/node.ts +24 -20
  26. package/src/picker.ts +9 -4
  27. package/src/remark-twemoji.ts +16 -8
  28. package/lib/src/constant.d.ts.map +0 -1
  29. package/lib/src/filter/helper.d.ts.map +0 -1
  30. package/lib/src/filter/index.d.ts +0 -4
  31. package/lib/src/filter/index.d.ts.map +0 -1
  32. package/lib/src/filter/style.d.ts +0 -3
  33. package/lib/src/filter/style.d.ts.map +0 -1
  34. package/lib/src/index.d.ts +0 -4
  35. package/lib/src/index.d.ts.map +0 -1
  36. package/lib/src/node.d.ts.map +0 -1
  37. package/lib/src/parse.d.ts.map +0 -1
  38. package/lib/src/picker.d.ts +0 -4
  39. package/lib/src/picker.d.ts.map +0 -1
  40. package/lib/src/remark-twemoji.d.ts.map +0 -1
File without changes
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constant.d.ts","sourceRoot":"","sources":["../src/constant.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,IAAI,QAAqB,CAAC;AACvC,eAAO,MAAM,IAAI,QAAwB,CAAC;AAC1C,eAAO,MAAM,KAAK,QAAmB,CAAC;AACtC,eAAO,MAAM,OAAO,YAAY,CAAC"}
File without changes
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helper.d.ts","sourceRoot":"","sources":["../../src/filter/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,SAmDlD,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { Plugin, PluginKey } from '@milkdown/prose';
2
+ import { Utils } from '@milkdown/utils';
3
+ export declare const key: PluginKey<any, any>;
4
+ export declare const filter: (utils: Utils) => Plugin<any, any>;
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/filter/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,qBAmKlC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Emotion, ThemeManager } from '@milkdown/core';
2
+ export declare const injectStyle: (themeManager: ThemeManager, { css, cx }: Emotion) => string;
3
+ //# sourceMappingURL=style.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"style.d.ts","sourceRoot":"","sources":["../../src/filter/style.ts"],"names":[],"mappings":"AACA,OAAO,EAEH,OAAO,EAIP,YAAY,EAGf,MAAM,gBAAgB,CAAC;AAExB,eAAO,MAAM,WAAW,iBAAkB,YAAY,eAAe,OAAO,WAyC3E,CAAC"}
package/lib/index.d.ts CHANGED
@@ -1 +1,4 @@
1
- export * from './src/index'
1
+ import { AtomList } from '@milkdown/utils';
2
+ export declare const emoji: AtomList<import("@milkdown/utils/lib/types").Metadata<import("@milkdown/utils/lib/types").GetPlugin<string, import("@milkdown/utils").UnknownRecord>> & import("@milkdown/core").MilkdownPlugin>;
3
+ export { emojiNode } from './node';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAI3C,eAAO,MAAM,KAAK,kMAAiC,CAAC;AAEpD,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC"}
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, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
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,10 +18,11 @@ 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";
25
+ import { ThemeBorder, ThemeShadow, ThemeSize, ThemeFont, ThemeColor } from "@milkdown/core";
25
26
  import { EmojiButton } from "@joeattardi/emoji-button";
26
27
  import emojiRegex from "emoji-regex";
27
28
  const part = /:\+1|:-1|:[\w-]+/;
@@ -40,7 +41,7 @@ const checkTrigger$1 = (view, from, to, text, setRange, setSearch) => {
40
41
  return false;
41
42
  }
42
43
  const regex2 = part.exec(textBefore);
43
- if (regex2 && textBefore.endsWith(regex2[0])) {
44
+ if (regex2 && regex2[0] && textBefore.endsWith(regex2[0])) {
44
45
  const match = regex2[0];
45
46
  setRange(from - (match.length - text.length), to);
46
47
  setSearch(match);
@@ -49,15 +50,17 @@ const checkTrigger$1 = (view, from, to, text, setRange, setSearch) => {
49
50
  return false;
50
51
  };
51
52
  const renderDropdownList = (list, dropDown, $active, onConfirm, setActive) => {
52
- dropDown.innerHTML = "";
53
- list.forEach(({ emoji: emoji2, key }, i) => {
53
+ while (dropDown.firstChild) {
54
+ dropDown.firstChild.remove();
55
+ }
56
+ list.forEach(({ emoji: emoji2, key: key2 }, i) => {
54
57
  const container = document.createElement("div");
55
58
  container.className = "milkdown-emoji-filter_item";
56
59
  const emojiSpan = document.createElement("span");
57
60
  emojiSpan.innerHTML = parse(emoji2);
58
61
  emojiSpan.className = "milkdown-emoji-filter_item-emoji";
59
62
  const keySpan = document.createElement("span");
60
- keySpan.textContent = ":" + key + ":";
63
+ keySpan.textContent = ":" + key2 + ":";
61
64
  keySpan.className = "milkdown-emoji-filter_item-key";
62
65
  container.appendChild(emojiSpan);
63
66
  container.appendChild(keySpan);
@@ -66,7 +69,7 @@ const renderDropdownList = (list, dropDown, $active, onConfirm, setActive) => {
66
69
  container.classList.add("active");
67
70
  setActive(container);
68
71
  }
69
- container.addEventListener("mouseenter", (e) => {
72
+ const onEnter = (e) => {
70
73
  if ($active) {
71
74
  $active.classList.remove("active");
72
75
  }
@@ -75,43 +78,48 @@ const renderDropdownList = (list, dropDown, $active, onConfirm, setActive) => {
75
78
  return;
76
79
  target.classList.add("active");
77
80
  setActive(target);
78
- });
79
- container.addEventListener("mouseleave", (e) => {
81
+ };
82
+ const onLeave = (e) => {
80
83
  const { target } = e;
81
84
  if (!(target instanceof HTMLElement))
82
85
  return;
83
86
  target.classList.remove("active");
84
- });
85
- container.addEventListener("mousedown", (e) => {
86
- onConfirm();
87
+ };
88
+ const onClick = (e) => {
87
89
  e.preventDefault();
88
- });
90
+ onConfirm();
91
+ };
92
+ container.addEventListener("mouseenter", onEnter);
93
+ container.addEventListener("mouseleave", onLeave);
94
+ container.addEventListener("mousedown", onClick);
89
95
  });
90
96
  };
91
- const injectStyle = ({ size, mixin, palette, font }, { css, cx }) => {
92
- var _a, _b;
93
- const border = (_a = mixin.border) == null ? void 0 : _a.call(mixin);
94
- const shadow = (_b = mixin.shadow) == null ? void 0 : _b.call(mixin);
97
+ const injectStyle = (themeManager, { css, cx }) => {
98
+ const border = themeManager.get(ThemeBorder, void 0);
99
+ const shadow = themeManager.get(ThemeShadow, void 0);
100
+ const radius = themeManager.get(ThemeSize, "radius");
101
+ const typography = themeManager.get(ThemeFont, "typography");
102
+ const palette = (color, opacity = 1) => themeManager.get(ThemeColor, [color, opacity]);
95
103
  const style = css`
96
104
  position: absolute;
97
105
  &.hide {
98
106
  display: none;
99
107
  }
100
108
 
101
- border-radius: ${size.radius};
109
+ border-radius: ${radius};
102
110
  background: ${palette("surface")};
103
111
 
104
112
  .milkdown-emoji-filter_item {
105
113
  display: flex;
106
- gap: 0.5rem;
107
- height: 2.25rem;
108
- padding: 0 1rem;
114
+ gap: 0.5em;
115
+ height: 2.57143em;
116
+ padding: 0 1em;
109
117
  align-items: center;
110
118
  justify-content: flex-start;
111
119
  cursor: pointer;
112
120
  line-height: 2;
113
- font-family: ${font.typography};
114
- font-size: 0.875rem;
121
+ font-family: ${typography};
122
+ font-size: 0.875em;
115
123
  &.active {
116
124
  background: ${palette("secondary", 0.12)};
117
125
  color: ${palette("primary")};
@@ -127,6 +135,7 @@ const injectStyle = ({ size, mixin, palette, font }, { css, cx }) => {
127
135
  `;
128
136
  return cx(border, shadow, style);
129
137
  };
138
+ const key$1 = new PluginKey("MILKDOWN_PLUGIN_EMOJI_FILTER");
130
139
  const filter = (utils) => {
131
140
  let trigger = false;
132
141
  let _from = 0;
@@ -139,6 +148,7 @@ const filter = (utils) => {
139
148
  $active = null;
140
149
  };
141
150
  return new Plugin({
151
+ key: key$1,
142
152
  props: {
143
153
  handleKeyDown(_, event) {
144
154
  if (["Delete", "Backspace"].includes(event.key)) {
@@ -173,10 +183,12 @@ const filter = (utils) => {
173
183
  throw new Error();
174
184
  }
175
185
  const dropDown = document.createElement("div");
176
- const style = utils.getStyle(injectStyle);
177
- if (style) {
178
- style.split(" ").forEach((x) => dropDown.classList.add(x));
179
- }
186
+ utils.themeManager.onFlush(() => {
187
+ const style = utils.getStyle(injectStyle);
188
+ if (style) {
189
+ style.split(" ").forEach((x) => dropDown.classList.add(x));
190
+ }
191
+ });
180
192
  dropDown.classList.add("milkdown-emoji-filter", "hide");
181
193
  const replace = () => {
182
194
  var _a;
@@ -189,16 +201,16 @@ const filter = (utils) => {
189
201
  dropDown.classList.add("hide");
190
202
  };
191
203
  parentNode.appendChild(dropDown);
192
- parentNode.addEventListener("keydown", (e) => {
204
+ const onKeydown = (e) => {
193
205
  if (!trigger || !(e instanceof KeyboardEvent))
194
206
  return;
195
- const { key } = e;
196
- if (key === "Enter") {
207
+ const { key: key2 } = e;
208
+ if (key2 === "Enter") {
197
209
  replace();
198
210
  return;
199
211
  }
200
- if (["ArrowDown", "ArrowUp"].includes(key)) {
201
- const next = key === "ArrowDown" ? ($active == null ? void 0 : $active.nextElementSibling) || dropDown.firstElementChild : ($active == null ? void 0 : $active.previousElementSibling) || dropDown.lastElementChild;
212
+ if (["ArrowDown", "ArrowUp"].includes(key2)) {
213
+ const next = key2 === "ArrowDown" ? ($active == null ? void 0 : $active.nextElementSibling) || dropDown.firstElementChild : ($active == null ? void 0 : $active.previousElementSibling) || dropDown.lastElementChild;
202
214
  if ($active) {
203
215
  $active.classList.remove("active");
204
216
  }
@@ -208,14 +220,16 @@ const filter = (utils) => {
208
220
  $active = next;
209
221
  return;
210
222
  }
211
- });
212
- parentNode.addEventListener("mousedown", (e) => {
223
+ };
224
+ const onClick = (e) => {
213
225
  if (!trigger)
214
226
  return;
215
227
  e.stopPropagation();
216
228
  off();
217
229
  dropDown.classList.add("hide");
218
- });
230
+ };
231
+ parentNode.addEventListener("keydown", onKeydown);
232
+ parentNode.addEventListener("mousedown", onClick);
219
233
  return {
220
234
  update: (view) => {
221
235
  const { selection } = view.state;
@@ -251,12 +265,18 @@ const filter = (utils) => {
251
265
  return [top, left];
252
266
  });
253
267
  return null;
268
+ },
269
+ destroy: () => {
270
+ parentNode.removeEventListener("keydown", onKeydown);
271
+ parentNode.removeEventListener("mousedown", onClick);
272
+ dropDown.remove();
254
273
  }
255
274
  };
256
275
  }
257
276
  });
258
277
  };
259
278
  const keyword = ":emoji:";
279
+ const key = new PluginKey("MILKDOWN_PLUGIN_EMOJI_PICKER");
260
280
  const checkTrigger = (view, from, to, text, setRange) => {
261
281
  if (view.composing)
262
282
  return false;
@@ -282,6 +302,7 @@ const picker = (utils) => {
282
302
  _to = 0;
283
303
  };
284
304
  const plugin = new Plugin({
305
+ key,
285
306
  props: {
286
307
  handleKeyDown() {
287
308
  off();
@@ -312,7 +333,9 @@ const picker = (utils) => {
312
333
  if (!parentNode) {
313
334
  throw new Error();
314
335
  }
315
- utils.getStyle(({ palette, font }, { injectGlobal }) => {
336
+ utils.getStyle((themeManager, { injectGlobal }) => {
337
+ const palette = (color, opacity = 1) => themeManager.get(ThemeColor, [color, opacity]);
338
+ const typography = themeManager.get(ThemeFont, "typography");
316
339
  const css = injectGlobal;
317
340
  css`
318
341
  .emoji-picker {
@@ -324,8 +347,8 @@ const picker = (utils) => {
324
347
  --dark-blue-color: ${palette("primary")} !important;
325
348
  --dark-search-icon-color: ${palette("primary")} !important;
326
349
  --dark-category-button-color: ${palette("secondary", 0.4)} !important;
327
- --font: ${font.typography} !important;
328
- --font-size: 1rem !important;
350
+ --font: ${typography} !important;
351
+ --font-size: 1em !important;
329
352
  }
330
353
  `;
331
354
  });
@@ -371,10 +394,16 @@ function flatMap(ast, fn) {
371
394
  if (isParent(node)) {
372
395
  const out = [];
373
396
  for (let i = 0, n = node.children.length; i < n; i++) {
374
- const xs = transform(node.children[i], i, node);
375
- if (xs) {
376
- for (let j = 0, m = xs.length; j < m; j++) {
377
- out.push(xs[j]);
397
+ const nthChild = node.children[i];
398
+ if (nthChild) {
399
+ const xs = transform(nthChild, i, node);
400
+ if (xs) {
401
+ for (let j = 0, m = xs.length; j < m; j++) {
402
+ const item = xs[j];
403
+ if (item) {
404
+ out.push(item);
405
+ }
406
+ }
378
407
  }
379
408
  }
380
409
  }
@@ -396,11 +425,13 @@ const twemojiPlugin = () => {
396
425
  while (match = regex.exec(str)) {
397
426
  const { index } = match;
398
427
  const emoji2 = match[0];
399
- if (index > 0) {
400
- output.push(__spreadProps(__spreadValues({}, node), { value: str.slice(0, index) }));
428
+ if (emoji2) {
429
+ if (index > 0) {
430
+ output.push(__spreadProps(__spreadValues({}, node), { value: str.slice(0, index) }));
431
+ }
432
+ output.push(__spreadProps(__spreadValues({}, node), { value: parse(emoji2), type: "emoji" }));
433
+ str = str.slice(index + emoji2.length);
401
434
  }
402
- output.push(__spreadProps(__spreadValues({}, node), { value: parse(emoji2), type: "emoji" }));
403
- str = str.slice(index + emoji2.length);
404
435
  }
405
436
  if (str.length) {
406
437
  output.push(__spreadProps(__spreadValues({}, node), { value: str }));
@@ -411,18 +442,18 @@ const twemojiPlugin = () => {
411
442
  return transformer;
412
443
  };
413
444
  const emojiNode = createNode((utils) => {
414
- const style = utils.getStyle((_, { css }) => css`
415
- display: inline-flex;
416
- justify-content: center;
417
- align-items: center;
445
+ const getStyle = () => utils.getStyle((_, { css }) => css`
446
+ display: inline-flex;
447
+ justify-content: center;
448
+ align-items: center;
418
449
 
419
- .emoji {
420
- height: 1em;
421
- width: 1em;
422
- margin: 0 0.05em 0 0.1em;
423
- vertical-align: -0.1em;
424
- }
425
- `);
450
+ .emoji {
451
+ height: 1em;
452
+ width: 1em;
453
+ margin: 0 0.05em 0 0.1em;
454
+ vertical-align: -0.1em;
455
+ }
456
+ `);
426
457
  return {
427
458
  id: "emoji",
428
459
  schema: () => ({
@@ -447,25 +478,28 @@ const emojiNode = createNode((utils) => {
447
478
  ],
448
479
  toDOM: (node) => {
449
480
  const span = document.createElement("span");
450
- span.dataset.type = "emoji";
451
- if (style) {
452
- span.classList.add(style);
453
- }
481
+ span.dataset["type"] = "emoji";
482
+ utils.themeManager.onFlush(() => {
483
+ const style = getStyle();
484
+ if (style) {
485
+ span.classList.add(style);
486
+ }
487
+ });
454
488
  span.classList.add("emoji-wrapper");
455
- span.innerHTML = node.attrs.html;
489
+ span.innerHTML = node.attrs["html"];
456
490
  return { dom: span };
457
491
  },
458
492
  parseMarkdown: {
459
493
  match: ({ type }) => type === "emoji",
460
494
  runner: (state, node, type) => {
461
- state.addNode(type, { html: node.value });
495
+ state.addNode(type, { html: node["value"] });
462
496
  }
463
497
  },
464
498
  toMarkdown: {
465
499
  match: (node) => node.type.name === "emoji",
466
500
  runner: (state, node) => {
467
501
  const span = document.createElement("span");
468
- span.innerHTML = node.attrs.html;
502
+ span.innerHTML = node.attrs["html"];
469
503
  const img = span.querySelector("img");
470
504
  const title = img == null ? void 0 : img.title;
471
505
  span.remove();
@@ -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 ).toLowerCase();\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 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 } 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 while (dropDown.firstChild) {\n dropDown.firstChild.remove();\n }\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 const onEnter = (e: MouseEvent) => {\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\n const onLeave = (e: MouseEvent) => {\n const { target } = e;\n if (!(target instanceof HTMLElement)) return;\n target.classList.remove('active');\n };\n\n const onClick = (e: MouseEvent) => {\n e.preventDefault();\n onConfirm();\n };\n\n container.addEventListener('mouseenter', onEnter);\n container.addEventListener('mouseleave', onLeave);\n container.addEventListener('mousedown', onClick);\n });\n};\n","/* Copyright 2021, Milkdown by Mirone. */\nimport {\n Color,\n Emotion,\n ThemeBorder,\n ThemeColor,\n ThemeFont,\n ThemeManager,\n ThemeShadow,\n ThemeSize,\n} from '@milkdown/core';\n\nexport const injectStyle = (themeManager: ThemeManager, { css, cx }: Emotion) => {\n const border = themeManager.get(ThemeBorder, undefined);\n const shadow = themeManager.get(ThemeShadow, undefined);\n const radius = themeManager.get(ThemeSize, 'radius');\n const typography = themeManager.get(ThemeFont, 'typography');\n const palette = (color: Color, opacity = 1) => themeManager.get(ThemeColor, [color, opacity]);\n\n const style = css`\n position: absolute;\n &.hide {\n display: none;\n }\n\n border-radius: ${radius};\n background: ${palette('surface')};\n\n .milkdown-emoji-filter_item {\n display: flex;\n gap: 0.5em;\n height: 2.57143em;\n padding: 0 1em;\n align-items: center;\n justify-content: flex-start;\n cursor: pointer;\n line-height: 2;\n font-family: ${typography};\n font-size: 0.875em;\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\n utils.themeManager.onFlush(() => {\n const style = utils.getStyle(injectStyle);\n if (style) {\n style.split(' ').forEach((x) => dropDown.classList.add(x));\n }\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 const onKeydown = (e: Event) => {\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 const onClick = (e: Event) => {\n if (!trigger) return;\n\n e.stopPropagation();\n off();\n dropDown.classList.add('hide');\n };\n parentNode.addEventListener('keydown', onKeydown);\n parentNode.addEventListener('mousedown', onClick);\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 destroy: () => {\n parentNode.removeEventListener('keydown', onKeydown);\n parentNode.removeEventListener('mousedown', onClick);\n dropDown.remove();\n },\n };\n },\n });\n};\n","/* Copyright 2021, Milkdown by Mirone. */\nimport { EmojiButton } from '@joeattardi/emoji-button';\nimport { Color, ThemeColor, ThemeFont } from '@milkdown/core';\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((themeManager, { injectGlobal }) => {\n const palette = (color: Color, opacity = 1) => themeManager.get(ThemeColor, [color, opacity]);\n const typography = themeManager.get(ThemeFont, 'typography');\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: ${typography} !important;\n --font-size: 1em !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 getStyle = () =>\n 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 utils.themeManager.onFlush(() => {\n const style = getStyle();\n if (style) {\n span.classList.add(style);\n }\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,4 +1,4 @@
1
- export declare const emojiNode: import("@milkdown/utils/lib/src/types").WithExtend<string, import("@milkdown/utils").UnknownRecord, import("prosemirror-model").NodeType<any>, {
1
+ export declare const emojiNode: import("@milkdown/utils/lib/types").WithExtend<string, import("@milkdown/utils").UnknownRecord, import("prosemirror-model").NodeType<any>, {
2
2
  id: string;
3
3
  schema: (ctx: import("@milkdown/core").Ctx) => import("@milkdown/core").NodeSchema;
4
4
  view?: ((ctx: import("@milkdown/core").Ctx) => import("@milkdown/prose").NodeViewFactory) | undefined;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,SAAS;;;;EAuFpB,CAAC"}
File without changes
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,KAAK,UAAW,MAAM,WAAsE,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { Plugin, PluginKey } from '@milkdown/prose';
2
+ import { Utils } from '@milkdown/utils';
3
+ export declare const key: PluginKey<any, any>;
4
+ export declare const picker: (utils: Utils) => Plugin<any, any>;
5
+ //# sourceMappingURL=picker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"picker.d.ts","sourceRoot":"","sources":["../src/picker.ts"],"names":[],"mappings":"AAGA,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,qBAiGlC,CAAC"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remark-twemoji.d.ts","sourceRoot":"","sources":["../src/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.4.0",
3
+ "version": "6.0.0-next.0",
4
4
  "type": "module",
5
5
  "main": "./lib/index.es.js",
6
6
  "types": "./lib/index.d.ts",
@@ -15,30 +15,54 @@
15
15
  "milkdown plugin"
16
16
  ],
17
17
  "devDependencies": {
18
- "@milkdown/core": "5.4.0",
19
- "@milkdown/prose": "5.4.0"
18
+ "@milkdown/core": "6.0.0-next.0",
19
+ "@milkdown/prose": "6.0.0-next.0"
20
20
  },
21
21
  "peerDependencies": {
22
- "@milkdown/core": "^5.4.0",
23
- "@milkdown/prose": "^5.4.0"
22
+ "@milkdown/core": "^6.0.0-next.0",
23
+ "@milkdown/prose": "^6.0.0-next.0"
24
24
  },
25
25
  "dependencies": {
26
- "@joeattardi/emoji-button": "^4.6.0",
27
- "@milkdown/utils": "5.4.0",
26
+ "@joeattardi/emoji-button": "^4.6.4",
27
+ "@milkdown/utils": "6.0.0-next.0",
28
28
  "@types/node-emoji": "^1.8.1",
29
29
  "@types/twemoji": "^12.1.2",
30
30
  "emoji-regex": "^10.0.0",
31
31
  "node-emoji": "^1.10.0",
32
32
  "remark-emoji": "^3.0.1",
33
33
  "tslib": "^2.3.1",
34
- "twemoji": "^13.1.0",
34
+ "twemoji": "~12.1.2",
35
35
  "unist-util-visit": "^4.0.0"
36
36
  },
37
+ "nx": {
38
+ "targets": {
39
+ "build": {
40
+ "outputs": [
41
+ "packages/plugin-emoji/lib"
42
+ ],
43
+ "dependsOn": [
44
+ {
45
+ "target": "build",
46
+ "projects": "dependencies"
47
+ }
48
+ ]
49
+ },
50
+ "tsc": {
51
+ "outputs": [],
52
+ "dependsOn": [
53
+ {
54
+ "target": "build",
55
+ "projects": "dependencies"
56
+ }
57
+ ]
58
+ }
59
+ }
60
+ },
37
61
  "scripts": {
38
- "start": "vite build --watch",
62
+ "start": "concurrently -n es,dts \"vite build --watch\" \"tsc --emitDeclarationOnly --watch\"",
39
63
  "test": "vitest",
40
64
  "tsc": "tsc --noEmit",
41
- "build": "vite build"
65
+ "build": "vite build && tsc --emitDeclarationOnly"
42
66
  },
43
67
  "readme": "# @milkdown/plugin-emoji\n\nEmoji plugin for [milkdown](https://saul-mirone.github.io/milkdown/).\nAdd support for emoji through [shortcuts](https://www.webfx.com/tools/emoji-cheat-sheet/).\nRendered by [twemoji](https://github.com/twitter/twemoji).\n\n# Example Usage\n\n```typescript\nimport { Editor } from '@milkdown/core';\nimport { commonmark } from '@milkdown/preset-commonmark';\nimport { nord } from '@milkdown/theme-nord';\n\nimport { emoji } from '@milkdown/plugin-emoji';\n\nEditor.make().use(nord).use(commonmark).use(emoji).create();\n```\n\n# License\n\nMilkdown is open sourced software licensed under [MIT license](https://github.com/Saul-Mirone/milkdown/blob/main/LICENSE).\n"
44
68
  }
@@ -25,7 +25,7 @@ export const checkTrigger = (
25
25
  return false;
26
26
  }
27
27
  const regex = part.exec(textBefore);
28
- if (regex && textBefore.endsWith(regex[0])) {
28
+ if (regex && regex[0] && textBefore.endsWith(regex[0])) {
29
29
  const match = regex[0];
30
30
  setRange(from - (match.length - text.length), to);
31
31
  setSearch(match);
@@ -41,7 +41,9 @@ export const renderDropdownList = (
41
41
  onConfirm: () => void,
42
42
  setActive: (active: HTMLElement | null) => void,
43
43
  ) => {
44
- dropDown.innerHTML = '';
44
+ while (dropDown.firstChild) {
45
+ dropDown.firstChild.remove();
46
+ }
45
47
  list.forEach(({ emoji, key }, i) => {
46
48
  const container = document.createElement('div');
47
49
  container.className = 'milkdown-emoji-filter_item';
@@ -63,7 +65,7 @@ export const renderDropdownList = (
63
65
  setActive(container);
64
66
  }
65
67
 
66
- container.addEventListener('mouseenter', (e) => {
68
+ const onEnter = (e: MouseEvent) => {
67
69
  if ($active) {
68
70
  $active.classList.remove('active');
69
71
  }
@@ -71,15 +73,21 @@ export const renderDropdownList = (
71
73
  if (!(target instanceof HTMLElement)) return;
72
74
  target.classList.add('active');
73
75
  setActive(target);
74
- });
75
- container.addEventListener('mouseleave', (e) => {
76
+ };
77
+
78
+ const onLeave = (e: MouseEvent) => {
76
79
  const { target } = e;
77
80
  if (!(target instanceof HTMLElement)) return;
78
81
  target.classList.remove('active');
79
- });
80
- container.addEventListener('mousedown', (e) => {
81
- onConfirm();
82
+ };
83
+
84
+ const onClick = (e: MouseEvent) => {
82
85
  e.preventDefault();
83
- });
86
+ onConfirm();
87
+ };
88
+
89
+ container.addEventListener('mouseenter', onEnter);
90
+ container.addEventListener('mouseleave', onLeave);
91
+ container.addEventListener('mousedown', onClick);
84
92
  });
85
93
  };
@@ -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)) {
@@ -62,11 +65,13 @@ export const filter = (utils: Utils) => {
62
65
  }
63
66
 
64
67
  const dropDown = document.createElement('div');
65
- const style = utils.getStyle(injectStyle);
66
68
 
67
- if (style) {
68
- style.split(' ').forEach((x) => dropDown.classList.add(x));
69
- }
69
+ utils.themeManager.onFlush(() => {
70
+ const style = utils.getStyle(injectStyle);
71
+ if (style) {
72
+ style.split(' ').forEach((x) => dropDown.classList.add(x));
73
+ }
74
+ });
70
75
 
71
76
  dropDown.classList.add('milkdown-emoji-filter', 'hide');
72
77
 
@@ -82,7 +87,7 @@ export const filter = (utils: Utils) => {
82
87
  };
83
88
 
84
89
  parentNode.appendChild(dropDown);
85
- parentNode.addEventListener('keydown', (e) => {
90
+ const onKeydown = (e: Event) => {
86
91
  if (!trigger || !(e instanceof KeyboardEvent)) return;
87
92
 
88
93
  const { key } = e;
@@ -106,14 +111,16 @@ export const filter = (utils: Utils) => {
106
111
 
107
112
  return;
108
113
  }
109
- });
110
- parentNode.addEventListener('mousedown', (e) => {
114
+ };
115
+ const onClick = (e: Event) => {
111
116
  if (!trigger) return;
112
117
 
113
118
  e.stopPropagation();
114
119
  off();
115
120
  dropDown.classList.add('hide');
116
- });
121
+ };
122
+ parentNode.addEventListener('keydown', onKeydown);
123
+ parentNode.addEventListener('mousedown', onClick);
117
124
 
118
125
  return {
119
126
  update: (view) => {
@@ -156,6 +163,12 @@ export const filter = (utils: Utils) => {
156
163
 
157
164
  return null;
158
165
  },
166
+
167
+ destroy: () => {
168
+ parentNode.removeEventListener('keydown', onKeydown);
169
+ parentNode.removeEventListener('mousedown', onClick);
170
+ dropDown.remove();
171
+ },
159
172
  };
160
173
  },
161
174
  });
@@ -1,9 +1,21 @@
1
1
  /* Copyright 2021, Milkdown by Mirone. */
2
- import type { Emotion, ThemeTool } from '@milkdown/core';
2
+ import {
3
+ Color,
4
+ Emotion,
5
+ ThemeBorder,
6
+ ThemeColor,
7
+ ThemeFont,
8
+ ThemeManager,
9
+ ThemeShadow,
10
+ ThemeSize,
11
+ } from '@milkdown/core';
3
12
 
4
- export const injectStyle = ({ size, mixin, palette, font }: ThemeTool, { css, cx }: Emotion) => {
5
- const border = mixin.border?.();
6
- const shadow = mixin.shadow?.();
13
+ export const injectStyle = (themeManager: ThemeManager, { css, cx }: Emotion) => {
14
+ const border = themeManager.get(ThemeBorder, undefined);
15
+ const shadow = themeManager.get(ThemeShadow, undefined);
16
+ const radius = themeManager.get(ThemeSize, 'radius');
17
+ const typography = themeManager.get(ThemeFont, 'typography');
18
+ const palette = (color: Color, opacity = 1) => themeManager.get(ThemeColor, [color, opacity]);
7
19
 
8
20
  const style = css`
9
21
  position: absolute;
@@ -11,20 +23,20 @@ export const injectStyle = ({ size, mixin, palette, font }: ThemeTool, { css, cx
11
23
  display: none;
12
24
  }
13
25
 
14
- border-radius: ${size.radius};
26
+ border-radius: ${radius};
15
27
  background: ${palette('surface')};
16
28
 
17
29
  .milkdown-emoji-filter_item {
18
30
  display: flex;
19
- gap: 0.5rem;
20
- height: 2.25rem;
21
- padding: 0 1rem;
31
+ gap: 0.5em;
32
+ height: 2.57143em;
33
+ padding: 0 1em;
22
34
  align-items: center;
23
35
  justify-content: flex-start;
24
36
  cursor: pointer;
25
37
  line-height: 2;
26
- font-family: ${font.typography};
27
- font-size: 0.875rem;
38
+ font-family: ${typography};
39
+ font-size: 0.875em;
28
40
  &.active {
29
41
  background: ${palette('secondary', 0.12)};
30
42
  color: ${palette('primary')};
package/src/node.ts CHANGED
@@ -12,20 +12,21 @@ import { picker } from './picker';
12
12
  import { twemojiPlugin } from './remark-twemoji';
13
13
 
14
14
  export const emojiNode = createNode((utils) => {
15
- const style = utils.getStyle(
16
- (_, { css }) => css`
17
- display: inline-flex;
18
- justify-content: center;
19
- align-items: center;
15
+ const getStyle = () =>
16
+ utils.getStyle(
17
+ (_, { css }) => css`
18
+ display: inline-flex;
19
+ justify-content: center;
20
+ align-items: center;
20
21
 
21
- .emoji {
22
- height: 1em;
23
- width: 1em;
24
- margin: 0 0.05em 0 0.1em;
25
- vertical-align: -0.1em;
26
- }
27
- `,
28
- );
22
+ .emoji {
23
+ height: 1em;
24
+ width: 1em;
25
+ margin: 0 0.05em 0 0.1em;
26
+ vertical-align: -0.1em;
27
+ }
28
+ `,
29
+ );
29
30
  return {
30
31
  id: 'emoji',
31
32
  schema: () => ({
@@ -50,25 +51,28 @@ export const emojiNode = createNode((utils) => {
50
51
  ],
51
52
  toDOM: (node) => {
52
53
  const span = document.createElement('span');
53
- span.dataset.type = 'emoji';
54
- if (style) {
55
- span.classList.add(style);
56
- }
54
+ span.dataset['type'] = 'emoji';
55
+ utils.themeManager.onFlush(() => {
56
+ const style = getStyle();
57
+ if (style) {
58
+ span.classList.add(style);
59
+ }
60
+ });
57
61
  span.classList.add('emoji-wrapper');
58
- span.innerHTML = node.attrs.html;
62
+ span.innerHTML = node.attrs['html'];
59
63
  return { dom: span };
60
64
  },
61
65
  parseMarkdown: {
62
66
  match: ({ type }) => type === 'emoji',
63
67
  runner: (state, node, type) => {
64
- state.addNode(type, { html: node.value as string });
68
+ state.addNode(type, { html: node['value'] as string });
65
69
  },
66
70
  },
67
71
  toMarkdown: {
68
72
  match: (node) => node.type.name === 'emoji',
69
73
  runner: (state, node) => {
70
74
  const span = document.createElement('span');
71
- span.innerHTML = node.attrs.html;
75
+ span.innerHTML = node.attrs['html'];
72
76
  const img = span.querySelector('img');
73
77
  const title = img?.title;
74
78
  span.remove();
package/src/picker.ts CHANGED
@@ -1,11 +1,13 @@
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 { Color, ThemeColor, ThemeFont } from '@milkdown/core';
4
+ import { Decoration, DecorationSet, EditorView, Plugin, PluginKey } from '@milkdown/prose';
4
5
  import { Utils } from '@milkdown/utils';
5
6
 
6
7
  import { parse } from './parse';
7
8
 
8
9
  const keyword = ':emoji:';
10
+ export const key = new PluginKey('MILKDOWN_PLUGIN_EMOJI_PICKER');
9
11
 
10
12
  const checkTrigger = (
11
13
  view: EditorView,
@@ -40,6 +42,7 @@ export const picker = (utils: Utils) => {
40
42
  };
41
43
 
42
44
  const plugin = new Plugin({
45
+ key,
43
46
  props: {
44
47
  handleKeyDown() {
45
48
  off();
@@ -71,7 +74,9 @@ export const picker = (utils: Utils) => {
71
74
  if (!parentNode) {
72
75
  throw new Error();
73
76
  }
74
- utils.getStyle(({ palette, font }, { injectGlobal }) => {
77
+ utils.getStyle((themeManager, { injectGlobal }) => {
78
+ const palette = (color: Color, opacity = 1) => themeManager.get(ThemeColor, [color, opacity]);
79
+ const typography = themeManager.get(ThemeFont, 'typography');
75
80
  const css = injectGlobal;
76
81
  css`
77
82
  .emoji-picker {
@@ -83,8 +88,8 @@ export const picker = (utils: Utils) => {
83
88
  --dark-blue-color: ${palette('primary')} !important;
84
89
  --dark-search-icon-color: ${palette('primary')} !important;
85
90
  --dark-category-button-color: ${palette('secondary', 0.4)} !important;
86
- --font: ${font.typography} !important;
87
- --font-size: 1rem !important;
91
+ --font: ${typography} !important;
92
+ --font-size: 1em !important;
88
93
  }
89
94
  `;
90
95
  });
@@ -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 xs = transform(node.children[i], i, node);
20
- if (xs) {
21
- for (let j = 0, m = xs.length; j < m; j++) {
22
- out.push(xs[j]);
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 (index > 0) {
47
- output.push({ ...node, value: str.slice(0, index) });
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 });
@@ -1 +0,0 @@
1
- {"version":3,"file":"constant.d.ts","sourceRoot":"","sources":["constant.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,IAAI,QAAqB,CAAC;AACvC,eAAO,MAAM,IAAI,QAAwB,CAAC;AAC1C,eAAO,MAAM,KAAK,QAAmB,CAAC;AACtC,eAAO,MAAM,OAAO,YAAY,CAAC"}
@@ -1 +0,0 @@
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 +0,0 @@
1
- import { Plugin } from '@milkdown/prose';
2
- import { Utils } from '@milkdown/utils';
3
- export declare const filter: (utils: Utils) => Plugin<any, any>;
4
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAyB,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAChE,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAMxC,eAAO,MAAM,MAAM,UAAW,KAAK,qBAwJlC,CAAC"}
@@ -1,3 +0,0 @@
1
- import type { Emotion, ThemeTool } from '@milkdown/core';
2
- export declare const injectStyle: ({ size, mixin, palette, font }: ThemeTool, { css, cx }: Emotion) => string;
3
- //# sourceMappingURL=style.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"style.d.ts","sourceRoot":"","sources":["style.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEzD,eAAO,MAAM,WAAW,mCAAoC,SAAS,eAAe,OAAO,WAsC1F,CAAC"}
@@ -1,4 +0,0 @@
1
- import { AtomList } from '@milkdown/utils';
2
- export declare const emoji: AtomList<import("@milkdown/utils/lib/src/types").Metadata<import("@milkdown/utils/lib/src/types").GetPlugin<string, import("@milkdown/utils").UnknownRecord>> & import("@milkdown/core").MilkdownPlugin>;
3
- export { emojiNode } from './node';
4
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAI3C,eAAO,MAAM,KAAK,0MAAiC,CAAC;AAEpD,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"node.d.ts","sourceRoot":"","sources":["node.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,SAAS;;;;EAmFpB,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["parse.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,KAAK,UAAW,MAAM,WAAsE,CAAC"}
@@ -1,4 +0,0 @@
1
- import { Plugin } from '@milkdown/prose';
2
- import { Utils } from '@milkdown/utils';
3
- export declare const picker: (utils: Utils) => Plugin<any, any>;
4
- //# sourceMappingURL=picker.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"picker.d.ts","sourceRoot":"","sources":["picker.ts"],"names":[],"mappings":"AAEA,OAAO,EAAyC,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAChF,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AA2BxC,eAAO,MAAM,MAAM,UAAW,KAAK,qBA8FlC,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"remark-twemoji.d.ts","sourceRoot":"","sources":["remark-twemoji.ts"],"names":[],"mappings":"AAEA,OAAO,EAAW,IAAI,EAAU,MAAM,OAAO,CAAC;AA8B9C,eAAO,MAAM,aAAa,eACK,IAAI,SAyBlC,CAAC"}