Sfoglia il codice sorgente

set position of emojiPicker

https://youtrack.weseek.co.jp/issue/GW-7750
- Clear emojiSearchText on modal close
- Move getEmojiTranslation to emojiPickerHelper
- Disable fade effect of Modal
- Remove focus on editor after modal opened
- Change emojiPicker position to fixed
- Add space after emoji-colons
Mudana-Grune 4 anni fa
parent
commit
737b139747

+ 23 - 23
packages/app/src/components/PageEditor/CodeMirrorEditor.jsx

@@ -1,37 +1,37 @@
 import React from 'react';
-import PropTypes from 'prop-types';
 
-import urljoin from 'url-join';
+import { createValidator } from '@growi/codemirror-textlint';
 import * as codemirror from 'codemirror';
-import { Button } from 'reactstrap';
-
 import { JSHINT } from 'jshint';
-
-import * as loadScript from 'simple-load-script';
 import * as loadCssSync from 'load-css-file';
+import PropTypes from 'prop-types';
+import { Button } from 'reactstrap';
+import * as loadScript from 'simple-load-script';
+import urljoin from 'url-join';
 
-import { createValidator } from '@growi/codemirror-textlint';
-import EmojiPicker from './EmojiPicker';
-import EmojiPickerHelper from './EmojiPickerHelper';
 import InterceptorManager from '~/services/interceptor-manager';
 import loggerFactory from '~/utils/logger';
 
-import AbstractEditor from './AbstractEditor';
-import SimpleCheatsheet from './SimpleCheatsheet';
+import { UncontrolledCodeMirror } from '../UncontrolledCodeMirror';
 
-import pasteHelper from './PasteHelper';
-import PreventMarkdownListInterceptor from './PreventMarkdownListInterceptor';
-import MarkdownTableInterceptor from './MarkdownTableInterceptor';
-import mlu from './MarkdownLinkUtil';
-import mtu from './MarkdownTableUtil';
-import mdu from './MarkdownDrawioUtil';
-import geu from './GridEditorUtil';
+import AbstractEditor from './AbstractEditor';
+import DrawioModal from './DrawioModal';
+import EditorIcon from './EditorIcon';
+import EmojiPicker from './EmojiPicker';
+import EmojiPickerHelper from './EmojiPickerHelper';
 import GridEditModal from './GridEditModal';
-import LinkEditModal from './LinkEditModal';
+import geu from './GridEditorUtil';
 import HandsontableModal from './HandsontableModal';
-import EditorIcon from './EditorIcon';
-import DrawioModal from './DrawioModal';
-import { UncontrolledCodeMirror } from '../UncontrolledCodeMirror';
+import LinkEditModal from './LinkEditModal';
+import mdu from './MarkdownDrawioUtil';
+import mlu from './MarkdownLinkUtil';
+import MarkdownTableInterceptor from './MarkdownTableInterceptor';
+import mtu from './MarkdownTableUtil';
+import pasteHelper from './PasteHelper';
+import PreventMarkdownListInterceptor from './PreventMarkdownListInterceptor';
+import SimpleCheatsheet from './SimpleCheatsheet';
+
+
 // Textlint
 window.JSHINT = JSHINT;
 window.kuromojin = { dicPath: '/static/dict' };
@@ -695,7 +695,7 @@ export default class CodeMirrorEditor extends AbstractEditor {
         <div className="text-left">
           <div className="mb-2 d-none d-md-block">
             <EmojiPicker
-              onClose={() => this.setState({ isEmojiPickerShown: false })}
+              onClose={() => this.setState({ isEmojiPickerShown: false, emojiSearchText: null })}
               emojiSearchText={emojiSearchText}
               editor={this.getCodeMirror()}
               emojiPickerHelper={this.emojiPickerHelper}

+ 6 - 49
packages/app/src/components/PageEditor/EmojiPicker.tsx

@@ -1,12 +1,11 @@
-import React, { FC, useState } from 'react';
+import React, { FC } from 'react';
 
 import { Picker } from 'emoji-mart';
-import i18n from 'i18next';
 import { Modal } from 'reactstrap';
 
 import { isDarkMode } from '~/client/util/color-scheme';
 
-import EmojiPickerHelper from './EmojiPickerHelper';
+import EmojiPickerHelper, { getEmojiTranslation } from './EmojiPickerHelper';
 
 type Props = {
   onClose: () => void,
@@ -22,7 +21,6 @@ const EmojiPicker: FC<Props> = (props: Props) => {
     onClose, emojiSearchText, emojiPickerHelper, isOpen,
   } = props;
 
-  const [style, setStyle] = useState({});
   // Set search emoji input and trigger search
   const searchEmoji = () => {
     if (emojiSearchText !== null) {
@@ -32,8 +30,6 @@ const EmojiPicker: FC<Props> = (props: Props) => {
       const event = new Event('input', { bubbles: true });
       input.dispatchEvent(event);
       input.focus();
-      const emojiPickerHeight = window.document.querySelector('[id^="emoji-mart-search"]')?.clientHeight;
-      setStyle(emojiPickerHelper.getCursorCoords(emojiPickerHeight));
     }
   };
 
@@ -48,60 +44,21 @@ const EmojiPicker: FC<Props> = (props: Props) => {
   };
 
 
-  const getEmojiTranslation = () => {
-
-    const categories = {};
-    [
-      'search',
-      'recent',
-      'smileys',
-      'people',
-      'nature',
-      'foods',
-      'activity',
-      'places',
-      'objects',
-      'symbols',
-      'flags',
-      'custom',
-    ].forEach((category) => {
-      categories[category] = i18n.t(`emoji.categories.${category}`);
-    });
-
-    const skintones = {};
-    (Array.from(Array(6).keys())).forEach((tone) => {
-      skintones[tone + 1] = i18n.t(`emoji.skintones.${tone + 1}`);
-    });
-
-    const translation = {
-      search: i18n.t('emoji.search'),
-      clear: i18n.t('emoji.clear'),
-      notfound: i18n.t('emoji.notfound'),
-      skintext: i18n.t('emoji.skintext'),
-      categories,
-      categorieslabel: i18n.t('emoji.categorieslabel'),
-      skintones,
-      title: i18n.t('emoji.title'),
-    };
-
-    return translation;
-  };
-
   const translation = getEmojiTranslation();
   const theme = isDarkMode() ? 'dark' : 'light';
 
-  return Object.keys(style).length !== 0 ? (
-    <Modal isOpen={isOpen} toggle={onClose} onOpened={searchEmoji}>
+  return (
+    <Modal isOpen={isOpen} toggle={onClose} onOpened={searchEmoji} fade={false}>
       <Picker
         onSelect={selectEmoji}
         i18n={translation}
         title={translation.title}
         emojiTooltip
-        style={{ position: 'absolute' }}
+        style={emojiPickerHelper.setStyle()}
         theme={theme}
       />
     </Modal>
-  ) : <></>;
+  );
 };
 
 export default EmojiPicker;

+ 51 - 10
packages/app/src/components/PageEditor/EmojiPickerHelper.ts

@@ -1,5 +1,7 @@
 import { CSSProperties } from 'react';
 
+import i18n from 'i18next';
+
 export default class EmojiPickerHelper {
 
 editor;
@@ -11,27 +13,27 @@ constructor(editor) {
   this.pattern = /:[^:\s]+/;
 }
 
-getCursorCoords = (emojiPickerHeight):CSSProperties => {
-  const offset = 30;
+setStyle = ():CSSProperties => {
+  const offset = 20;
+  const emojiPickerHeight = 420;
   const cursorPos = this.editor.cursorCoords(true);
   const editorPos = this.editor.getWrapperElement().getBoundingClientRect();
-  this.editor.focus();
   // Emoji Picker bottom position exceed editor's bottom position
   if (cursorPos.bottom + emojiPickerHeight > editorPos.bottom) {
     return {
       top: editorPos.bottom - emojiPickerHeight,
-      left: cursorPos.left,
-      position: 'absolute',
+      left: cursorPos.left + offset,
+      position: 'fixed',
     };
   }
   return {
     top: cursorPos.top + offset,
-    left: cursorPos.left,
-    position: 'absolute',
+    left: cursorPos.left + offset,
+    position: 'fixed',
   };
 }
 
-getSearchCursor() {
+getSearchCursor =() => {
   const currentPos = this.editor.getCursor();
   const sc = this.editor.getSearchCursor(this.pattern, currentPos, { multiline: false });
   return sc;
@@ -42,7 +44,7 @@ addEmojiOnSearch = (emoji) => {
   const currentPos = this.editor.getCursor();
   const sc = this.getSearchCursor();
   if (sc.findPrevious()) {
-    sc.replace(emoji.colons, this.editor.getTokenAt(currentPos).string);
+    sc.replace(`${emoji.colons} `, this.editor.getTokenAt(currentPos).string);
     this.editor.focus();
     this.editor.refresh();
   }
@@ -53,7 +55,7 @@ addEmojiOnSearch = (emoji) => {
 addEmoji = (emoji) => {
   const currentPos = this.editor.getCursor();
   const doc = this.editor.getDoc();
-  doc.replaceRange(emoji.colons, currentPos);
+  doc.replaceRange(`${emoji.colons} `, currentPos);
   this.editor.focus();
   this.editor.refresh();
 }
@@ -81,3 +83,42 @@ getEmoji = () => {
 }
 
 }
+
+export const getEmojiTranslation = () => {
+
+  const categories = {};
+  [
+    'search',
+    'recent',
+    'smileys',
+    'people',
+    'nature',
+    'foods',
+    'activity',
+    'places',
+    'objects',
+    'symbols',
+    'flags',
+    'custom',
+  ].forEach((category) => {
+    categories[category] = i18n.t(`emoji.categories.${category}`);
+  });
+
+  const skintones = {};
+  (Array.from(Array(6).keys())).forEach((tone) => {
+    skintones[tone + 1] = i18n.t(`emoji.skintones.${tone + 1}`);
+  });
+
+  const translation = {
+    search: i18n.t('emoji.search'),
+    clear: i18n.t('emoji.clear'),
+    notfound: i18n.t('emoji.notfound'),
+    skintext: i18n.t('emoji.skintext'),
+    categories,
+    categorieslabel: i18n.t('emoji.categorieslabel'),
+    skintones,
+    title: i18n.t('emoji.title'),
+  };
+
+  return translation;
+};