Merge pull request #783 from ilesinge/hover_tooltip
Implement optional hover tooltip with function documentation
This commit is contained in:
commit
62eb9ce598
7 changed files with 90 additions and 2 deletions
|
|
@ -26,7 +26,6 @@ export function Autocomplete({ doc }) {
|
||||||
<pre
|
<pre
|
||||||
className="cursor-pointer"
|
className="cursor-pointer"
|
||||||
onMouseDown={(e) => {
|
onMouseDown={(e) => {
|
||||||
console.log('ola!');
|
|
||||||
navigator.clipboard.writeText(example);
|
navigator.clipboard.writeText(example);
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
}}
|
}}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import _CodeMirror from '@uiw/react-codemirror';
|
||||||
import React, { useCallback, useMemo } from 'react';
|
import React, { useCallback, useMemo } from 'react';
|
||||||
import strudelTheme from '../themes/strudel-theme';
|
import strudelTheme from '../themes/strudel-theme';
|
||||||
import { strudelAutocomplete } from './Autocomplete';
|
import { strudelAutocomplete } from './Autocomplete';
|
||||||
|
import { strudelTooltip } from './Tooltip';
|
||||||
import {
|
import {
|
||||||
highlightExtension,
|
highlightExtension,
|
||||||
flashField,
|
flashField,
|
||||||
|
|
@ -33,6 +34,7 @@ export default function CodeMirror({
|
||||||
keybindings,
|
keybindings,
|
||||||
isLineNumbersDisplayed,
|
isLineNumbersDisplayed,
|
||||||
isAutoCompletionEnabled,
|
isAutoCompletionEnabled,
|
||||||
|
isTooltipEnabled,
|
||||||
isLineWrappingEnabled,
|
isLineWrappingEnabled,
|
||||||
fontSize = 18,
|
fontSize = 18,
|
||||||
fontFamily = 'monospace',
|
fontFamily = 'monospace',
|
||||||
|
|
@ -94,6 +96,10 @@ export default function CodeMirror({
|
||||||
_extensions.push(autocompletion({ override: [] }));
|
_extensions.push(autocompletion({ override: [] }));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isTooltipEnabled) {
|
||||||
|
_extensions.push(strudelTooltip);
|
||||||
|
}
|
||||||
|
|
||||||
_extensions.push([keymap.of({})]);
|
_extensions.push([keymap.of({})]);
|
||||||
|
|
||||||
if (isLineWrappingEnabled) {
|
if (isLineWrappingEnabled) {
|
||||||
|
|
@ -101,7 +107,7 @@ export default function CodeMirror({
|
||||||
}
|
}
|
||||||
|
|
||||||
return _extensions;
|
return _extensions;
|
||||||
}, [keybindings, isAutoCompletionEnabled, isLineWrappingEnabled]);
|
}, [keybindings, isAutoCompletionEnabled, isTooltipEnabled, isLineWrappingEnabled]);
|
||||||
|
|
||||||
const basicSetup = useMemo(() => ({ lineNumbers: isLineNumbersDisplayed }), [isLineNumbersDisplayed]);
|
const basicSetup = useMemo(() => ({ lineNumbers: isLineNumbersDisplayed }), [isLineNumbersDisplayed]);
|
||||||
|
|
||||||
|
|
|
||||||
69
packages/react/src/components/Tooltip.jsx
Normal file
69
packages/react/src/components/Tooltip.jsx
Normal file
|
|
@ -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(<Autocomplete doc={entry} />);
|
||||||
|
return { dom };
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
{ hoverTime: 10 },
|
||||||
|
);
|
||||||
|
|
@ -28,3 +28,7 @@
|
||||||
footer {
|
footer {
|
||||||
z-index: 0 !important;
|
z-index: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.strudel-tooltip {
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -385,6 +385,7 @@ function SettingsTab({ scheduler }) {
|
||||||
keybindings,
|
keybindings,
|
||||||
isLineNumbersDisplayed,
|
isLineNumbersDisplayed,
|
||||||
isAutoCompletionEnabled,
|
isAutoCompletionEnabled,
|
||||||
|
isTooltipEnabled,
|
||||||
isLineWrappingEnabled,
|
isLineWrappingEnabled,
|
||||||
fontSize,
|
fontSize,
|
||||||
fontFamily,
|
fontFamily,
|
||||||
|
|
@ -457,6 +458,11 @@ function SettingsTab({ scheduler }) {
|
||||||
onChange={(cbEvent) => settingsMap.setKey('isAutoCompletionEnabled', cbEvent.target.checked)}
|
onChange={(cbEvent) => settingsMap.setKey('isAutoCompletionEnabled', cbEvent.target.checked)}
|
||||||
value={isAutoCompletionEnabled}
|
value={isAutoCompletionEnabled}
|
||||||
/>
|
/>
|
||||||
|
<Checkbox
|
||||||
|
label="Enable tooltips on Ctrl and hover"
|
||||||
|
onChange={(cbEvent) => settingsMap.setKey('isTooltipEnabled', cbEvent.target.checked)}
|
||||||
|
value={isTooltipEnabled}
|
||||||
|
/>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label="Enable line wrapping"
|
label="Enable line wrapping"
|
||||||
onChange={(cbEvent) => settingsMap.setKey('isLineWrappingEnabled', cbEvent.target.checked)}
|
onChange={(cbEvent) => settingsMap.setKey('isLineWrappingEnabled', cbEvent.target.checked)}
|
||||||
|
|
|
||||||
|
|
@ -126,6 +126,7 @@ export function Repl({ embedded = false }) {
|
||||||
fontFamily,
|
fontFamily,
|
||||||
isLineNumbersDisplayed,
|
isLineNumbersDisplayed,
|
||||||
isAutoCompletionEnabled,
|
isAutoCompletionEnabled,
|
||||||
|
isTooltipEnabled,
|
||||||
isLineWrappingEnabled,
|
isLineWrappingEnabled,
|
||||||
panelPosition,
|
panelPosition,
|
||||||
isZen,
|
isZen,
|
||||||
|
|
@ -335,6 +336,7 @@ export function Repl({ embedded = false }) {
|
||||||
keybindings={keybindings}
|
keybindings={keybindings}
|
||||||
isLineNumbersDisplayed={isLineNumbersDisplayed}
|
isLineNumbersDisplayed={isLineNumbersDisplayed}
|
||||||
isAutoCompletionEnabled={isAutoCompletionEnabled}
|
isAutoCompletionEnabled={isAutoCompletionEnabled}
|
||||||
|
isTooltipEnabled={isTooltipEnabled}
|
||||||
isLineWrappingEnabled={isLineWrappingEnabled}
|
isLineWrappingEnabled={isLineWrappingEnabled}
|
||||||
fontSize={fontSize}
|
fontSize={fontSize}
|
||||||
fontFamily={fontFamily}
|
fontFamily={fontFamily}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ export const defaultSettings = {
|
||||||
keybindings: 'codemirror',
|
keybindings: 'codemirror',
|
||||||
isLineNumbersDisplayed: true,
|
isLineNumbersDisplayed: true,
|
||||||
isAutoCompletionEnabled: false,
|
isAutoCompletionEnabled: false,
|
||||||
|
isTooltipEnabled: false,
|
||||||
isLineWrappingEnabled: false,
|
isLineWrappingEnabled: false,
|
||||||
theme: 'strudelTheme',
|
theme: 'strudelTheme',
|
||||||
fontFamily: 'monospace',
|
fontFamily: 'monospace',
|
||||||
|
|
@ -26,6 +27,7 @@ export function useSettings() {
|
||||||
isZen: [true, 'true'].includes(state.isZen) ? true : false,
|
isZen: [true, 'true'].includes(state.isZen) ? true : false,
|
||||||
isLineNumbersDisplayed: [true, 'true'].includes(state.isLineNumbersDisplayed) ? true : false,
|
isLineNumbersDisplayed: [true, 'true'].includes(state.isLineNumbersDisplayed) ? true : false,
|
||||||
isAutoCompletionEnabled: [true, 'true'].includes(state.isAutoCompletionEnabled) ? 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,
|
isLineWrappingEnabled: [true, 'true'].includes(state.isLineWrappingEnabled) ? true : false,
|
||||||
fontSize: Number(state.fontSize),
|
fontSize: Number(state.fontSize),
|
||||||
panelPosition: state.activeFooter !== '' ? state.panelPosition : 'bottom',
|
panelPosition: state.activeFooter !== '' ? state.panelPosition : 'bottom',
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue