@milkdown/plugin-emoji 6.0.0-next.0 → 6.0.1

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/constant.d.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  export declare const part: RegExp;
2
2
  export declare const full: RegExp;
3
3
  export declare const input: RegExp;
4
- export declare const keyword = ":emoji:";
5
4
  //# sourceMappingURL=constant.d.ts.map
@@ -1 +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"}
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"}
@@ -1,5 +1,5 @@
1
1
  import { Plugin, PluginKey } from '@milkdown/prose';
2
2
  import { Utils } from '@milkdown/utils';
3
3
  export declare const key: PluginKey<any, any>;
4
- export declare const filter: (utils: Utils) => Plugin<any, any>;
4
+ export declare const filter: (utils: Utils, maxListSize: number) => Plugin<any, any>;
5
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +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"}
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,eAAe,MAAM,qBAuKvD,CAAC"}
package/lib/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
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';
2
+ export * from './node';
3
+ export declare const emoji: AtomList<import("@milkdown/utils/lib/types").Metadata<import("@milkdown/utils/lib/types").GetPlugin<string, import("./node").EmojiOptions>> & import("@milkdown/core").MilkdownPlugin>;
4
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAG3C,cAAc,QAAQ,CAAC;AAEvB,eAAO,MAAM,KAAK,wLAAiC,CAAC"}
package/lib/index.es.js CHANGED
@@ -18,18 +18,18 @@ 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 { PluginKey, Plugin, calculateNodePosition, DecorationSet, Decoration, InputRule } from "@milkdown/prose";
21
+ import { PluginKey, Plugin, calculateNodePosition, 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
25
  import { ThemeBorder, ThemeShadow, ThemeSize, ThemeFont, ThemeColor } from "@milkdown/core";
26
- import { EmojiButton } from "@joeattardi/emoji-button";
27
26
  import emojiRegex from "emoji-regex";
28
27
  const part = /:\+1|:-1|:[\w-]+/;
29
28
  const full = /:\+1:|:-1:|:[\w-]+:/;
30
29
  const input = /(:([^:\s]+):)$/;
31
- const parse = (emoji2) => twemoji.parse(emoji2, { attributes: (text) => ({ title: text }) });
32
- const checkTrigger$1 = (view, from, to, text, setRange, setSearch) => {
30
+ const setAttr = (text) => ({ title: text });
31
+ const parse = (emoji2) => twemoji.parse(emoji2, { attributes: setAttr });
32
+ const checkTrigger = (view, from, to, text, setRange, setSearch) => {
33
33
  if (view.composing)
34
34
  return false;
35
35
  const { state } = view;
@@ -135,8 +135,8 @@ const injectStyle = (themeManager, { css, cx }) => {
135
135
  `;
136
136
  return cx(border, shadow, style);
137
137
  };
138
- const key$1 = new PluginKey("MILKDOWN_PLUGIN_EMOJI_FILTER");
139
- const filter = (utils) => {
138
+ const key = new PluginKey("MILKDOWN_PLUGIN_EMOJI_FILTER");
139
+ const filter = (utils, maxListSize) => {
140
140
  let trigger = false;
141
141
  let _from = 0;
142
142
  let _search = "";
@@ -148,7 +148,7 @@ const filter = (utils) => {
148
148
  $active = null;
149
149
  };
150
150
  return new Plugin({
151
- key: key$1,
151
+ key,
152
152
  props: {
153
153
  handleKeyDown(_, event) {
154
154
  if (["Delete", "Backspace"].includes(event.key)) {
@@ -166,7 +166,7 @@ const filter = (utils) => {
166
166
  return true;
167
167
  },
168
168
  handleTextInput(view, from, to, text) {
169
- trigger = checkTrigger$1(view, from, to, text, (from2) => {
169
+ trigger = checkTrigger(view, from, to, text, (from2) => {
170
170
  _from = from2;
171
171
  }, (search2) => {
172
172
  _search = search2;
@@ -183,13 +183,15 @@ const filter = (utils) => {
183
183
  throw new Error();
184
184
  }
185
185
  const dropDown = document.createElement("div");
186
+ dropDown.classList.add("milkdown-emoji-filter", "hide");
186
187
  utils.themeManager.onFlush(() => {
187
- const style = utils.getStyle(injectStyle);
188
+ const className = dropDown.className.split(" ").filter((x) => ["hide", "milkdown-emoji-filter"].includes(x));
189
+ dropDown.className = className.join(" ");
190
+ const style = utils.getStyle((emotion) => injectStyle(utils.themeManager, emotion));
188
191
  if (style) {
189
192
  style.split(" ").forEach((x) => dropDown.classList.add(x));
190
193
  }
191
194
  });
192
- dropDown.classList.add("milkdown-emoji-filter", "hide");
193
195
  const replace = () => {
194
196
  var _a;
195
197
  if (!$active)
@@ -238,7 +240,7 @@ const filter = (utils) => {
238
240
  dropDown.classList.add("hide");
239
241
  return null;
240
242
  }
241
- const result = search(_search).slice(0, 5);
243
+ const result = search(_search).slice(0, maxListSize);
242
244
  const { node } = view.domAtPos(_from);
243
245
  if (result.length === 0 || !node) {
244
246
  dropDown.classList.add("hide");
@@ -275,116 +277,6 @@ const filter = (utils) => {
275
277
  }
276
278
  });
277
279
  };
278
- const keyword = ":emoji:";
279
- const key = new PluginKey("MILKDOWN_PLUGIN_EMOJI_PICKER");
280
- const checkTrigger = (view, from, to, text, setRange) => {
281
- if (view.composing)
282
- return false;
283
- const { state } = view;
284
- const $from = state.doc.resolve(from);
285
- if ($from.parent.type.spec.code)
286
- return false;
287
- const textBefore = $from.parent.textBetween($from.parentOffset - keyword.length + 1, $from.parentOffset, void 0, "\uFFFC") + text;
288
- if (textBefore === keyword) {
289
- setRange(from - keyword.length + 1, to + 1);
290
- return true;
291
- }
292
- return false;
293
- };
294
- const picker = (utils) => {
295
- let trigger = false;
296
- const holder = document.createElement("span");
297
- let _from = 0;
298
- let _to = 0;
299
- const off = () => {
300
- trigger = false;
301
- _from = 0;
302
- _to = 0;
303
- };
304
- const plugin = new Plugin({
305
- key,
306
- props: {
307
- handleKeyDown() {
308
- off();
309
- return false;
310
- },
311
- handleClick() {
312
- off();
313
- return false;
314
- },
315
- handleTextInput(view, from, to, text) {
316
- trigger = checkTrigger(view, from, to, text, (from2, to2) => {
317
- _from = from2;
318
- _to = to2;
319
- });
320
- if (!trigger) {
321
- off();
322
- }
323
- return false;
324
- },
325
- decorations(state) {
326
- if (!trigger)
327
- return null;
328
- return DecorationSet.create(state.doc, [Decoration.widget(state.selection.to, holder)]);
329
- }
330
- },
331
- view: (editorView) => {
332
- const { parentNode } = editorView.dom;
333
- if (!parentNode) {
334
- throw new Error();
335
- }
336
- utils.getStyle((themeManager, { injectGlobal }) => {
337
- const palette = (color, opacity = 1) => themeManager.get(ThemeColor, [color, opacity]);
338
- const typography = themeManager.get(ThemeFont, "typography");
339
- const css = injectGlobal;
340
- css`
341
- .emoji-picker {
342
- --dark-search-background-color: ${palette("surface")} !important;
343
- --dark-text-color: ${palette("neutral", 0.87)} !important;
344
- --dark-background-color: ${palette("background")} !important;
345
- --dark-border-color: ${palette("shadow")} !important;
346
- --dark-hover-color: ${palette("secondary", 0.12)} !important;
347
- --dark-blue-color: ${palette("primary")} !important;
348
- --dark-search-icon-color: ${palette("primary")} !important;
349
- --dark-category-button-color: ${palette("secondary", 0.4)} !important;
350
- --font: ${typography} !important;
351
- --font-size: 1em !important;
352
- }
353
- `;
354
- });
355
- const emojiPicker = new EmojiButton({
356
- rootElement: parentNode,
357
- autoFocusSearch: false,
358
- style: "twemoji",
359
- theme: "dark",
360
- zIndex: 99
361
- });
362
- emojiPicker.on("emoji", (selection) => {
363
- const start = _from;
364
- const end = _to;
365
- off();
366
- const html = parse(selection.emoji);
367
- const node = editorView.state.schema.node("emoji", { html });
368
- const { tr } = editorView.state;
369
- editorView.dispatch(tr.replaceRangeWith(start, end, node));
370
- });
371
- return {
372
- update: () => {
373
- if (!trigger) {
374
- emojiPicker.hidePicker();
375
- return null;
376
- }
377
- emojiPicker.showPicker(holder);
378
- return null;
379
- },
380
- destroy: () => {
381
- emojiPicker.destroyPicker();
382
- }
383
- };
384
- }
385
- });
386
- return plugin;
387
- };
388
280
  const regex = emojiRegex();
389
281
  const isParent = (node) => !!node.children;
390
282
  const isLiteral = (node) => !!node.value;
@@ -441,8 +333,8 @@ const twemojiPlugin = () => {
441
333
  }
442
334
  return transformer;
443
335
  };
444
- const emojiNode = createNode((utils) => {
445
- const getStyle = () => utils.getStyle((_, { css }) => css`
336
+ const emojiNode = createNode((utils, options) => {
337
+ const getStyle = () => utils.getStyle(({ css }) => css`
446
338
  display: inline-flex;
447
339
  justify-content: center;
448
340
  align-items: center;
@@ -478,6 +370,7 @@ const emojiNode = createNode((utils) => {
478
370
  ],
479
371
  toDOM: (node) => {
480
372
  const span = document.createElement("span");
373
+ span.classList.add("emoji-wrapper");
481
374
  span.dataset["type"] = "emoji";
482
375
  utils.themeManager.onFlush(() => {
483
376
  const style = getStyle();
@@ -485,7 +378,6 @@ const emojiNode = createNode((utils) => {
485
378
  span.classList.add(style);
486
379
  }
487
380
  });
488
- span.classList.add("emoji-wrapper");
489
381
  span.innerHTML = node.attrs["html"];
490
382
  return { dom: span };
491
383
  },
@@ -520,7 +412,10 @@ const emojiNode = createNode((utils) => {
520
412
  })
521
413
  ],
522
414
  remarkPlugins: () => [remarkEmoji, twemojiPlugin],
523
- prosePlugins: () => [picker(utils), filter(utils)]
415
+ prosePlugins: () => {
416
+ var _a;
417
+ return [filter(utils, (_a = options == null ? void 0 : options.maxListSize) != null ? _a : 6)];
418
+ }
524
419
  };
525
420
  });
526
421
  const emoji = AtomList.create([emojiNode()]);
@@ -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 && 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
+ {"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/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]+):)$/;\n","/* Copyright 2021, Milkdown by Mirone. */\nimport twemoji from 'twemoji';\n\nconst setAttr = (text: string) => ({ title: text });\n\nexport const parse = (emoji: string): string =>\n twemoji.parse(emoji, { attributes: setAttr as unknown as () => void }) as unknown as string;\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, maxListSize: number) => {\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 dropDown.classList.add('milkdown-emoji-filter', 'hide');\n\n utils.themeManager.onFlush(() => {\n const className = dropDown.className\n .split(' ')\n .filter((x) => ['hide', 'milkdown-emoji-filter'].includes(x));\n dropDown.className = className.join(' ');\n const style = utils.getStyle((emotion) => injectStyle(utils.themeManager, emotion));\n if (style) {\n style.split(' ').forEach((x) => dropDown.classList.add(x));\n }\n });\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, maxListSize);\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 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 { twemojiPlugin } from './remark-twemoji';\n\nexport type EmojiOptions = {\n maxListSize: number;\n};\n\nexport const emojiNode = createNode<string, EmojiOptions>((utils, options) => {\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.classList.add('emoji-wrapper');\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.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: () => [filter(utils, options?.maxListSize ?? 6)],\n };\n});\n","/* Copyright 2021, Milkdown by Mirone. */\nimport { AtomList } from '@milkdown/utils';\n\nimport { emojiNode } from './node';\nexport * from './node';\n\nexport const emoji = AtomList.create([emojiNode()]);\n"],"names":[],"mappings":"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"}
package/lib/node.d.ts CHANGED
@@ -1,4 +1,7 @@
1
- export declare const emojiNode: import("@milkdown/utils/lib/types").WithExtend<string, import("@milkdown/utils").UnknownRecord, import("prosemirror-model").NodeType<any>, {
1
+ export declare type EmojiOptions = {
2
+ maxListSize: number;
3
+ };
4
+ export declare const emojiNode: import("@milkdown/utils/lib/types").WithExtend<string, EmojiOptions, import("prosemirror-model").NodeType<any>, {
2
5
  id: string;
3
6
  schema: (ctx: import("@milkdown/core").Ctx) => import("@milkdown/core").NodeSchema;
4
7
  view?: ((ctx: import("@milkdown/core").Ctx) => import("@milkdown/prose").NodeViewFactory) | undefined;
package/lib/node.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,SAAS;;;;EAuFpB,CAAC"}
1
+ {"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AAYA,oBAAY,YAAY,GAAG;IACvB,WAAW,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,eAAO,MAAM,SAAS;;;;EAuFpB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,KAAK,UAAW,MAAM,WAAsE,CAAC"}
1
+ {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,KAAK,UAAW,MAAM,KAAG,MACyD,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@milkdown/plugin-emoji",
3
- "version": "6.0.0-next.0",
3
+ "version": "6.0.1",
4
4
  "type": "module",
5
5
  "main": "./lib/index.es.js",
6
6
  "types": "./lib/index.d.ts",
@@ -15,23 +15,21 @@
15
15
  "milkdown plugin"
16
16
  ],
17
17
  "devDependencies": {
18
- "@milkdown/core": "6.0.0-next.0",
19
- "@milkdown/prose": "6.0.0-next.0"
18
+ "@milkdown/core": "6.0.1",
19
+ "@milkdown/prose": "6.0.1"
20
20
  },
21
21
  "peerDependencies": {
22
- "@milkdown/core": "^6.0.0-next.0",
23
- "@milkdown/prose": "^6.0.0-next.0"
22
+ "@milkdown/core": "^6.0.1",
23
+ "@milkdown/prose": "^6.0.1"
24
24
  },
25
25
  "dependencies": {
26
- "@joeattardi/emoji-button": "^4.6.4",
27
- "@milkdown/utils": "6.0.0-next.0",
26
+ "@milkdown/utils": "6.0.1",
28
27
  "@types/node-emoji": "^1.8.1",
29
- "@types/twemoji": "^12.1.2",
30
28
  "emoji-regex": "^10.0.0",
31
29
  "node-emoji": "^1.10.0",
32
30
  "remark-emoji": "^3.0.1",
33
31
  "tslib": "^2.3.1",
34
- "twemoji": "~12.1.2",
32
+ "twemoji": "^14.0.1",
35
33
  "unist-util-visit": "^4.0.0"
36
34
  },
37
35
  "nx": {
package/src/constant.ts CHANGED
@@ -2,4 +2,3 @@
2
2
  export const part = /:\+1|:-1|:[\w-]+/;
3
3
  export const full = /:\+1:|:-1:|:[\w-]+:/;
4
4
  export const input = /(:([^:\s]+):)$/;
5
- export const keyword = ':emoji:';
@@ -9,7 +9,7 @@ import { injectStyle } from './style';
9
9
 
10
10
  export const key = new PluginKey('MILKDOWN_PLUGIN_EMOJI_FILTER');
11
11
 
12
- export const filter = (utils: Utils) => {
12
+ export const filter = (utils: Utils, maxListSize: number) => {
13
13
  let trigger = false;
14
14
  let _from = 0;
15
15
  let _search = '';
@@ -66,15 +66,19 @@ export const filter = (utils: Utils) => {
66
66
 
67
67
  const dropDown = document.createElement('div');
68
68
 
69
+ dropDown.classList.add('milkdown-emoji-filter', 'hide');
70
+
69
71
  utils.themeManager.onFlush(() => {
70
- const style = utils.getStyle(injectStyle);
72
+ const className = dropDown.className
73
+ .split(' ')
74
+ .filter((x) => ['hide', 'milkdown-emoji-filter'].includes(x));
75
+ dropDown.className = className.join(' ');
76
+ const style = utils.getStyle((emotion) => injectStyle(utils.themeManager, emotion));
71
77
  if (style) {
72
78
  style.split(' ').forEach((x) => dropDown.classList.add(x));
73
79
  }
74
80
  });
75
81
 
76
- dropDown.classList.add('milkdown-emoji-filter', 'hide');
77
-
78
82
  const replace = () => {
79
83
  if (!$active) return;
80
84
 
@@ -131,7 +135,7 @@ export const filter = (utils: Utils) => {
131
135
  dropDown.classList.add('hide');
132
136
  return null;
133
137
  }
134
- const result = search(_search).slice(0, 5);
138
+ const result = search(_search).slice(0, maxListSize);
135
139
  const { node } = view.domAtPos(_from);
136
140
  if (result.length === 0 || !node) {
137
141
  dropDown.classList.add('hide');
package/src/index.ts CHANGED
@@ -2,7 +2,6 @@
2
2
  import { AtomList } from '@milkdown/utils';
3
3
 
4
4
  import { emojiNode } from './node';
5
+ export * from './node';
5
6
 
6
7
  export const emoji = AtomList.create([emojiNode()]);
7
-
8
- export { emojiNode } from './node';
package/src/node.ts CHANGED
@@ -8,13 +8,16 @@ import remarkEmoji from 'remark-emoji';
8
8
  import { input } from './constant';
9
9
  import { filter } from './filter';
10
10
  import { parse } from './parse';
11
- import { picker } from './picker';
12
11
  import { twemojiPlugin } from './remark-twemoji';
13
12
 
14
- export const emojiNode = createNode((utils) => {
13
+ export type EmojiOptions = {
14
+ maxListSize: number;
15
+ };
16
+
17
+ export const emojiNode = createNode<string, EmojiOptions>((utils, options) => {
15
18
  const getStyle = () =>
16
19
  utils.getStyle(
17
- (_, { css }) => css`
20
+ ({ css }) => css`
18
21
  display: inline-flex;
19
22
  justify-content: center;
20
23
  align-items: center;
@@ -51,6 +54,7 @@ export const emojiNode = createNode((utils) => {
51
54
  ],
52
55
  toDOM: (node) => {
53
56
  const span = document.createElement('span');
57
+ span.classList.add('emoji-wrapper');
54
58
  span.dataset['type'] = 'emoji';
55
59
  utils.themeManager.onFlush(() => {
56
60
  const style = getStyle();
@@ -58,7 +62,6 @@ export const emojiNode = createNode((utils) => {
58
62
  span.classList.add(style);
59
63
  }
60
64
  });
61
- span.classList.add('emoji-wrapper');
62
65
  span.innerHTML = node.attrs['html'];
63
66
  return { dom: span };
64
67
  },
@@ -96,6 +99,6 @@ export const emojiNode = createNode((utils) => {
96
99
  }),
97
100
  ],
98
101
  remarkPlugins: () => [remarkEmoji as RemarkPlugin, twemojiPlugin],
99
- prosePlugins: () => [picker(utils), filter(utils)],
102
+ prosePlugins: () => [filter(utils, options?.maxListSize ?? 6)],
100
103
  };
101
104
  });
package/src/parse.ts CHANGED
@@ -1,4 +1,7 @@
1
1
  /* Copyright 2021, Milkdown by Mirone. */
2
2
  import twemoji from 'twemoji';
3
3
 
4
- export const parse = (emoji: string) => twemoji.parse(emoji, { attributes: (text) => ({ title: text }) });
4
+ const setAttr = (text: string) => ({ title: text });
5
+
6
+ export const parse = (emoji: string): string =>
7
+ twemoji.parse(emoji, { attributes: setAttr as unknown as () => void }) as unknown as string;
package/lib/picker.d.ts DELETED
@@ -1,5 +0,0 @@
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
@@ -1 +0,0 @@
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"}
package/src/picker.ts DELETED
@@ -1,130 +0,0 @@
1
- /* Copyright 2021, Milkdown by Mirone. */
2
- import { EmojiButton } from '@joeattardi/emoji-button';
3
- import { Color, ThemeColor, ThemeFont } from '@milkdown/core';
4
- import { Decoration, DecorationSet, EditorView, Plugin, PluginKey } from '@milkdown/prose';
5
- import { Utils } from '@milkdown/utils';
6
-
7
- import { parse } from './parse';
8
-
9
- const keyword = ':emoji:';
10
- export const key = new PluginKey('MILKDOWN_PLUGIN_EMOJI_PICKER');
11
-
12
- const checkTrigger = (
13
- view: EditorView,
14
- from: number,
15
- to: number,
16
- text: string,
17
- setRange: (from: number, to: number) => void,
18
- ) => {
19
- if (view.composing) return false;
20
- const { state } = view;
21
- const $from = state.doc.resolve(from);
22
- if ($from.parent.type.spec.code) return false;
23
- const textBefore =
24
- $from.parent.textBetween($from.parentOffset - keyword.length + 1, $from.parentOffset, undefined, '\ufffc') +
25
- text;
26
- if (textBefore === keyword) {
27
- setRange(from - keyword.length + 1, to + 1);
28
- return true;
29
- }
30
- return false;
31
- };
32
-
33
- export const picker = (utils: Utils) => {
34
- let trigger = false;
35
- const holder = document.createElement('span');
36
- let _from = 0;
37
- let _to = 0;
38
- const off = () => {
39
- trigger = false;
40
- _from = 0;
41
- _to = 0;
42
- };
43
-
44
- const plugin = new Plugin({
45
- key,
46
- props: {
47
- handleKeyDown() {
48
- off();
49
- return false;
50
- },
51
- handleClick() {
52
- off();
53
- return false;
54
- },
55
- handleTextInput(view, from, to, text) {
56
- trigger = checkTrigger(view, from, to, text, (from, to) => {
57
- _from = from;
58
- _to = to;
59
- });
60
-
61
- if (!trigger) {
62
- off();
63
- }
64
- return false;
65
- },
66
- decorations(state) {
67
- if (!trigger) return null;
68
-
69
- return DecorationSet.create(state.doc, [Decoration.widget(state.selection.to, holder)]);
70
- },
71
- },
72
- view: (editorView) => {
73
- const { parentNode } = editorView.dom;
74
- if (!parentNode) {
75
- throw new Error();
76
- }
77
- utils.getStyle((themeManager, { injectGlobal }) => {
78
- const palette = (color: Color, opacity = 1) => themeManager.get(ThemeColor, [color, opacity]);
79
- const typography = themeManager.get(ThemeFont, 'typography');
80
- const css = injectGlobal;
81
- css`
82
- .emoji-picker {
83
- --dark-search-background-color: ${palette('surface')} !important;
84
- --dark-text-color: ${palette('neutral', 0.87)} !important;
85
- --dark-background-color: ${palette('background')} !important;
86
- --dark-border-color: ${palette('shadow')} !important;
87
- --dark-hover-color: ${palette('secondary', 0.12)} !important;
88
- --dark-blue-color: ${palette('primary')} !important;
89
- --dark-search-icon-color: ${palette('primary')} !important;
90
- --dark-category-button-color: ${palette('secondary', 0.4)} !important;
91
- --font: ${typography} !important;
92
- --font-size: 1em !important;
93
- }
94
- `;
95
- });
96
- const emojiPicker = new EmojiButton({
97
- rootElement: parentNode as HTMLElement,
98
- autoFocusSearch: false,
99
- style: 'twemoji',
100
- theme: 'dark',
101
- zIndex: 99,
102
- });
103
- emojiPicker.on('emoji', (selection) => {
104
- const start = _from;
105
- const end = _to;
106
- off();
107
- const html = parse(selection.emoji);
108
- const node = editorView.state.schema.node('emoji', { html });
109
- const { tr } = editorView.state;
110
-
111
- editorView.dispatch(tr.replaceRangeWith(start, end, node));
112
- });
113
- return {
114
- update: () => {
115
- if (!trigger) {
116
- emojiPicker.hidePicker();
117
- return null;
118
- }
119
- emojiPicker.showPicker(holder);
120
- return null;
121
- },
122
- destroy: () => {
123
- emojiPicker.destroyPicker();
124
- },
125
- };
126
- },
127
- });
128
-
129
- return plugin;
130
- };