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',