EmojiPickerHelper.ts 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. import { CSSProperties } from 'react';
  2. import { Position } from 'codemirror';
  3. import i18n from 'i18next';
  4. // https://regex101.com/r/x5LbOZ/1
  5. const EMOJI_PATTERN = new RegExp(/^:[a-z0-9-+_]+$/);
  6. export default class EmojiPickerHelper {
  7. editor;
  8. pattern: string;
  9. constructor(editor) {
  10. this.editor = editor;
  11. }
  12. setStyle = (): CSSProperties => {
  13. const offset = 20;
  14. const emojiPickerHeight = 420;
  15. const cursorPos = this.editor.cursorCoords(true);
  16. const editorPos = this.editor.getWrapperElement().getBoundingClientRect();
  17. // Emoji Picker bottom position exceed editor's bottom position
  18. if (cursorPos.bottom + emojiPickerHeight > editorPos.bottom) {
  19. return {
  20. top: editorPos.bottom - emojiPickerHeight,
  21. left: cursorPos.left + offset,
  22. position: 'fixed',
  23. };
  24. }
  25. return {
  26. top: cursorPos.top + offset,
  27. left: cursorPos.left + offset,
  28. position: 'fixed',
  29. };
  30. };
  31. shouldModeTurnOn = (char: string): Position | null | undefined => {
  32. if (char !== ':') {
  33. return null;
  34. }
  35. const currentPos = this.editor.getCursor();
  36. const sc = this.editor.getSearchCursor(':', currentPos, { multiline: false });
  37. if (sc.findPrevious()) {
  38. return sc.pos.from;
  39. }
  40. };
  41. shouldOpen = (startPos: Position): boolean => {
  42. const currentPos = this.editor.getCursor();
  43. const rangeStr = this.editor.getRange(startPos, currentPos);
  44. return EMOJI_PATTERN.test(rangeStr);
  45. };
  46. getInitialSearchingText = (startPos: Position): void => {
  47. const currentPos = this.editor.getCursor();
  48. const rangeStr = this.editor.getRange(startPos, currentPos);
  49. return rangeStr.slice(1); // return without the heading ':'
  50. };
  51. addEmoji = (emoji: { colons: string }, startPosToReplace: Position|null): void => {
  52. const currentPos = this.editor.getCursor();
  53. const from = startPosToReplace ?? currentPos;
  54. const to = currentPos;
  55. const doc = this.editor.getDoc();
  56. doc.replaceRange(`${emoji.colons} `, from, to);
  57. this.editor.focus();
  58. this.editor.refresh();
  59. };
  60. }
  61. export const getEmojiTranslation = () => {
  62. const categories = {};
  63. [
  64. 'search',
  65. 'recent',
  66. 'smileys',
  67. 'people',
  68. 'nature',
  69. 'foods',
  70. 'activity',
  71. 'places',
  72. 'objects',
  73. 'symbols',
  74. 'flags',
  75. 'custom',
  76. ].forEach((category) => {
  77. categories[category] = i18n.t(`emoji.categories.${category}`);
  78. });
  79. const skintones = {};
  80. (Array.from(Array(6).keys())).forEach((tone) => {
  81. skintones[tone + 1] = i18n.t(`emoji.skintones.${tone + 1}`);
  82. });
  83. const translation = {
  84. search: i18n.t('emoji.search'),
  85. clear: i18n.t('emoji.clear'),
  86. notfound: i18n.t('emoji.notfound'),
  87. skintext: i18n.t('emoji.skintext'),
  88. categories,
  89. categorieslabel: i18n.t('emoji.categorieslabel'),
  90. skintones,
  91. title: i18n.t('emoji.title'),
  92. };
  93. return translation;
  94. };