diff --git a/packages/react/src/components/Autocomplete.jsx b/packages/react/src/components/Autocomplete.jsx index 7ec81d2d..677baa6e 100644 --- a/packages/react/src/components/Autocomplete.jsx +++ b/packages/react/src/components/Autocomplete.jsx @@ -26,7 +26,6 @@ export function Autocomplete({ doc }) {
 {
-                console.log('ola!');
                 navigator.clipboard.writeText(example);
                 e.stopPropagation();
               }}
diff --git a/packages/react/src/components/CodeMirror6.jsx b/packages/react/src/components/CodeMirror6.jsx
index 63d4d5a1..667cd7e6 100644
--- a/packages/react/src/components/CodeMirror6.jsx
+++ b/packages/react/src/components/CodeMirror6.jsx
@@ -9,6 +9,7 @@ import _CodeMirror from '@uiw/react-codemirror';
 import React, { useCallback, useMemo } from 'react';
 import strudelTheme from '../themes/strudel-theme';
 import { strudelAutocomplete } from './Autocomplete';
+import { strudelTooltip } from './Tooltip';
 import {
   highlightExtension,
   flashField,
@@ -33,6 +34,7 @@ export default function CodeMirror({
   keybindings,
   isLineNumbersDisplayed,
   isAutoCompletionEnabled,
+  isTooltipEnabled,
   isLineWrappingEnabled,
   fontSize = 18,
   fontFamily = 'monospace',
@@ -94,6 +96,10 @@ export default function CodeMirror({
       _extensions.push(autocompletion({ override: [] }));
     }
 
+    if (isTooltipEnabled) {
+      _extensions.push(strudelTooltip);
+    }
+
     _extensions.push([keymap.of({})]);
 
     if (isLineWrappingEnabled) {
@@ -101,7 +107,7 @@ export default function CodeMirror({
     }
 
     return _extensions;
-  }, [keybindings, isAutoCompletionEnabled, isLineWrappingEnabled]);
+  }, [keybindings, isAutoCompletionEnabled, isTooltipEnabled, isLineWrappingEnabled]);
 
   const basicSetup = useMemo(() => ({ lineNumbers: isLineNumbersDisplayed }), [isLineNumbersDisplayed]);
 
diff --git a/packages/react/src/components/Tooltip.jsx b/packages/react/src/components/Tooltip.jsx
new file mode 100644
index 00000000..a443c123
--- /dev/null
+++ b/packages/react/src/components/Tooltip.jsx
@@ -0,0 +1,69 @@
+import { createRoot } from 'react-dom/client';
+import { hoverTooltip } from '@codemirror/view';
+import jsdoc from '../../../../doc.json';
+import { Autocomplete } from './Autocomplete';
+
+const getDocLabel = (doc) => doc.name || doc.longname;
+
+let ctrlDown = false;
+
+// Record Control key event to trigger or block the tooltip depending on the state
+window.addEventListener(
+  'keyup',
+  function (e) {
+    if (e.key == 'Control') {
+      ctrlDown = false;
+    }
+  },
+  true,
+);
+
+window.addEventListener(
+  'keydown',
+  function (e) {
+    if (e.key == 'Control') {
+      ctrlDown = true;
+    }
+  },
+  true,
+);
+
+export const strudelTooltip = hoverTooltip(
+  (view, pos, side) => {
+    // Word selection from CodeMirror Hover Tooltip example https://codemirror.net/examples/tooltip/#hover-tooltips
+    let { from, to, text } = view.state.doc.lineAt(pos);
+    let start = pos,
+      end = pos;
+    while (start > from && /\w/.test(text[start - from - 1])) {
+      start--;
+    }
+    while (end < to && /\w/.test(text[end - from])) {
+      end++;
+    }
+    if ((start == pos && side < 0) || (end == pos && side > 0)) {
+      return null;
+    }
+    let word = text.slice(start - from, end - from);
+    // Get entry from Strudel documentation
+    let entry = jsdoc.docs.filter((doc) => getDocLabel(doc) === word)[0];
+    if (!entry) {
+      return null;
+    }
+    if (!ctrlDown) {
+      return null;
+    }
+    return {
+      pos: start,
+      end,
+      above: false,
+      arrow: true,
+      create(view) {
+        let dom = document.createElement('div');
+        dom.className = 'strudel-tooltip';
+        createRoot(dom).render();
+        return { dom };
+      },
+    };
+  },
+  { hoverTime: 10 },
+);
diff --git a/packages/react/src/components/style.css b/packages/react/src/components/style.css
index d61c6619..6336bba3 100644
--- a/packages/react/src/components/style.css
+++ b/packages/react/src/components/style.css
@@ -28,3 +28,7 @@
 footer {
   z-index: 0 !important;
 }
+
+.strudel-tooltip {
+  padding: 5px;
+}
diff --git a/website/src/repl/Footer.jsx b/website/src/repl/Footer.jsx
index 9fb783a4..62dcbcdf 100644
--- a/website/src/repl/Footer.jsx
+++ b/website/src/repl/Footer.jsx
@@ -385,6 +385,7 @@ function SettingsTab({ scheduler }) {
     keybindings,
     isLineNumbersDisplayed,
     isAutoCompletionEnabled,
+    isTooltipEnabled,
     isLineWrappingEnabled,
     fontSize,
     fontFamily,
@@ -457,6 +458,11 @@ function SettingsTab({ scheduler }) {
           onChange={(cbEvent) => settingsMap.setKey('isAutoCompletionEnabled', cbEvent.target.checked)}
           value={isAutoCompletionEnabled}
         />
+         settingsMap.setKey('isTooltipEnabled', cbEvent.target.checked)}
+          value={isTooltipEnabled}
+        />
          settingsMap.setKey('isLineWrappingEnabled', cbEvent.target.checked)}
diff --git a/website/src/repl/Repl.jsx b/website/src/repl/Repl.jsx
index d9eb7001..41d4a35f 100644
--- a/website/src/repl/Repl.jsx
+++ b/website/src/repl/Repl.jsx
@@ -126,6 +126,7 @@ export function Repl({ embedded = false }) {
     fontFamily,
     isLineNumbersDisplayed,
     isAutoCompletionEnabled,
+    isTooltipEnabled,
     isLineWrappingEnabled,
     panelPosition,
     isZen,
@@ -335,6 +336,7 @@ export function Repl({ embedded = false }) {
               keybindings={keybindings}
               isLineNumbersDisplayed={isLineNumbersDisplayed}
               isAutoCompletionEnabled={isAutoCompletionEnabled}
+              isTooltipEnabled={isTooltipEnabled}
               isLineWrappingEnabled={isLineWrappingEnabled}
               fontSize={fontSize}
               fontFamily={fontFamily}
diff --git a/website/src/settings.mjs b/website/src/settings.mjs
index 5608b894..ab58494c 100644
--- a/website/src/settings.mjs
+++ b/website/src/settings.mjs
@@ -7,6 +7,7 @@ export const defaultSettings = {
   keybindings: 'codemirror',
   isLineNumbersDisplayed: true,
   isAutoCompletionEnabled: false,
+  isTooltipEnabled: false,
   isLineWrappingEnabled: false,
   theme: 'strudelTheme',
   fontFamily: 'monospace',
@@ -26,6 +27,7 @@ export function useSettings() {
     isZen: [true, 'true'].includes(state.isZen) ? true : false,
     isLineNumbersDisplayed: [true, 'true'].includes(state.isLineNumbersDisplayed) ? true : false,
     isAutoCompletionEnabled: [true, 'true'].includes(state.isAutoCompletionEnabled) ? true : false,
+    isTooltipEnabled: [true, 'true'].includes(state.isTooltipEnabled) ? true : false,
     isLineWrappingEnabled: [true, 'true'].includes(state.isLineWrappingEnabled) ? true : false,
     fontSize: Number(state.fontSize),
     panelPosition: state.activeFooter !== '' ? state.panelPosition : 'bottom',