reactify autocomplete info

This commit is contained in:
Felix Roos 2023-02-09 18:37:29 +01:00
parent 0f18f5eb81
commit f497d7b212
3 changed files with 77 additions and 67 deletions

View File

@ -0,0 +1,72 @@
import { createRoot } from 'react-dom/client';
import jsdoc from '../../../../doc.json';
const getDocLabel = (doc) => doc.name || doc.longname;
export function Autocomplete({ doc }) {
return (
<div className="prose prose-invert max-h-[400px] overflow-auto">
<h3 className="pt-0 mt-0">{getDocLabel(doc)}</h3>
<div dangerouslySetInnerHTML={{ __html: doc.description }} />
<ul>
{doc.params?.map(({ name, type, description }, i) => (
<li key={i}>
{name} : {type.names?.join(' | ')} {description ? <> - {description}</> : ''}
</li>
))}
</ul>
<div>
{doc.examples?.map((example, i) => (
<div key={i}>
<pre
className="cursor-pointer"
onMouseDown={(e) => {
console.log('ola!');
navigator.clipboard.writeText(example);
e.stopPropagation();
}}
>
{example}
</pre>
</div>
))}
</div>
</div>
);
}
const jsdocCompletions = jsdoc.docs
.filter(
(doc) =>
getDocLabel(doc) &&
!getDocLabel(doc).startsWith('_') &&
!['package'].includes(doc.kind) &&
!['superdirtOnly', 'noAutocomplete'].some((tag) => doc.tags?.find((t) => t.originalTitle === tag)),
)
// https://codemirror.net/docs/ref/#autocomplete.Completion
.map((doc) /*: Completion */ => ({
label: getDocLabel(doc),
// detail: 'xxx', // An optional short piece of information to show (with a different style) after the label.
info: () => {
const node = document.createElement('div');
// if Autocomplete is non-interactive, it could also be rendered at build time..
// .. using renderToStaticMarkup
createRoot(node).render(<Autocomplete doc={doc} />);
return node;
},
type: 'function', // https://codemirror.net/docs/ref/#autocomplete.Completion.type
}));
export const strudelAutocomplete = (context /* : CompletionContext */) => {
let word = context.matchBefore(/\w*/);
if (word.from == word.to && !context.explicit) return null;
return {
from: word.from,
options: jsdocCompletions,
/* options: [
{ label: 'match', type: 'keyword' },
{ label: 'hello', type: 'variable', info: '(World)' },
{ label: 'magic', type: 'text', apply: '⠁⭒*.✩.*⭒⠁', detail: 'macro' },
], */
};
};

View File

@ -7,7 +7,7 @@ import strudelTheme from '../themes/strudel-theme';
import './style.css';
import { useCallback } from 'react';
import { autocompletion } from '@codemirror/autocomplete';
import jsdoc from '../../../../doc.json';
import { strudelAutocomplete } from './Autocomplete';
export const setFlash = StateEffect.define();
const flashField = StateField.define({
@ -81,72 +81,6 @@ const highlightField = StateField.define({
provide: (f) => EditorView.decorations.from(f),
});
const getDocLabel = (doc) => doc.name || doc.longname;
const jsdocCompletions = jsdoc.docs
.filter(
(doc) =>
getDocLabel(doc) &&
!getDocLabel(doc).startsWith('_') &&
!['package'].includes(doc.kind) &&
!['superdirtOnly', 'noAutocomplete'].some((tag) => doc.tags?.find((t) => t.originalTitle === tag)),
)
// https://codemirror.net/docs/ref/#autocomplete.Completion
.map((doc) /*: Completion */ => ({
label: getDocLabel(doc),
// detail: 'xxx', // An optional short piece of information to show (with a different style) after the label.
info: () => {
const heading = document.createElement('h3');
heading.innerText = getDocLabel(doc);
heading.style = 'padding-top:0;margin-top:0';
const description = document.createElement('div');
description.innerHTML = doc.description;
const params = document.createElement('ul');
doc.params?.forEach(({ name, type, description }) => {
const li = document.createElement('li');
const span = document.createElement('span');
span.innerText = name + ': ' + type.names?.join(' | ') + (description ? ' - ' : '');
const c = document.createElement('span');
c.innerHTML = description || '';
const comment = document.createElement('span');
comment.innerHTML = c.innerText;
li.appendChild(span);
li.appendChild(comment);
params.appendChild(li);
});
const examples = document.createElement('div');
doc.examples?.forEach((ex) => {
const code = document.createElement('pre');
code.style = 'font-size:14px';
code.innerText = ex;
examples.appendChild(code);
});
const node = document.createElement('div');
node.classList.add('prose');
node.classList.add('prose-invert');
node.style = 'max-width:500px;max-height:400px;overflow:auto';
node.appendChild(heading);
node.appendChild(description);
node.appendChild(params);
node.appendChild(examples);
return node;
}, // Additional info to show when the completion is selected
type: 'function', // https://codemirror.net/docs/ref/#autocomplete.Completion.type
}));
export const strudelAutocomplete = (context /* : CompletionContext */) => {
let word = context.matchBefore(/\w*/);
if (word.from == word.to && !context.explicit) return null;
return {
from: word.from,
options: jsdocCompletions,
/* options: [
{ label: 'match', type: 'keyword' },
{ label: 'hello', type: 'variable', info: '(World)' },
{ label: 'magic', type: 'text', apply: '⠁⭒*.✩.*⭒⠁', detail: 'macro' },
], */
};
};
const extensions = [
javascript(),
strudelTheme,

View File

@ -18,3 +18,7 @@
padding-top: 12px !important;
padding-left: 8px !important;
}
.cm-scroller {
padding-bottom: 50vh;
}