From 299c4d93597b3065e6a1017ebe692cde66fc5e39 Mon Sep 17 00:00:00 2001
From: Kristóf Marussy <kristof@marussy.com>
Date: Mon, 11 Oct 2021 01:03:21 +0200
Subject: feat(web): experiment with Lezer parser

---
 language-web/src/main/js/editor/EditorArea.tsx | 49 ++++++++++++++++++--------
 1 file changed, 35 insertions(+), 14 deletions(-)

(limited to 'language-web/src/main/js/editor/EditorArea.tsx')

diff --git a/language-web/src/main/js/editor/EditorArea.tsx b/language-web/src/main/js/editor/EditorArea.tsx
index 58d65184..460005ce 100644
--- a/language-web/src/main/js/editor/EditorArea.tsx
+++ b/language-web/src/main/js/editor/EditorArea.tsx
@@ -1,8 +1,14 @@
 import { Command, EditorView } from '@codemirror/view';
 import { closeSearchPanel, openSearchPanel } from '@codemirror/search';
 import { closeLintPanel, openLintPanel } from '@codemirror/lint';
+
 import { observer } from 'mobx-react-lite';
-import React, { useEffect, useRef, useState } from 'react';
+import React, {
+  useCallback,
+  useEffect,
+  useRef,
+  useState,
+} from 'react';
 
 import { EditorParent } from './EditorParent';
 import { getLogger } from '../logging';
@@ -11,36 +17,49 @@ import { useRootStore } from '../RootStore';
 const log = getLogger('EditorArea');
 
 function usePanel(
-  label: string,
+  panelId: string,
   stateToSet: boolean,
   editorView: EditorView | null,
   openCommand: Command,
   closeCommand: Command,
+  closeCallback: () => void,
 ) {
   const [cachedViewState, setCachedViewState] = useState<boolean>(false);
   useEffect(() => {
     if (editorView === null || cachedViewState === stateToSet) {
       return;
     }
-    const success = stateToSet ? openCommand(editorView) : closeCommand(editorView);
-    if (!success) {
-      log.error(
-        'Failed to synchronize',
-        label,
-        'panel state - store state:',
-        cachedViewState,
-        'view state:',
-        stateToSet,
-      );
+    if (stateToSet) {
+      openCommand(editorView);
+      const buttonQuery = `.cm-${panelId}.cm-panel button[name="close"]`;
+      const closeButton = editorView.dom.querySelector(buttonQuery);
+      if (closeButton) {
+        log.debug('Addig close button callback to', panelId, 'panel');
+        // We must remove the event listener added by CodeMirror from the button
+        // that dispatches a transaction without going through `EditorStorre`.
+        // Cloning a DOM node removes event listeners,
+        // see https://stackoverflow.com/a/9251864
+        const closeButtonWithoutListeners = closeButton.cloneNode(true);
+        closeButtonWithoutListeners.addEventListener('click', (event) => {
+          closeCallback();
+          event.preventDefault();
+        });
+        closeButton.replaceWith(closeButtonWithoutListeners);
+      } else {
+        log.error('Opened', panelId, 'panel has no close button');
+      }
+    } else {
+      closeCommand(editorView);
     }
     setCachedViewState(stateToSet);
   }, [
     stateToSet,
     editorView,
     cachedViewState,
-    label,
+    panelId,
     openCommand,
     closeCommand,
+    closeCallback,
   ]);
   return setCachedViewState;
 }
@@ -56,14 +75,16 @@ export const EditorArea = observer(() => {
     editorViewState,
     openSearchPanel,
     closeSearchPanel,
+    useCallback(() => editorStore.setSearchPanelOpen(false), [editorStore]),
   );
 
   const setLintPanelOpen = usePanel(
-    'lint',
+    'panel-lint',
     editorStore.showLintPanel,
     editorViewState,
     openLintPanel,
     closeLintPanel,
+    useCallback(() => editorStore.setLintPanelOpen(false), [editorStore]),
   );
 
   useEffect(() => {
-- 
cgit v1.2.3-70-g09d2

