diff --git a/packages/react/src/components/Autocomplete.jsx b/packages/react/src/components/Autocomplete.jsx
new file mode 100644
index 00000000..54babd32
--- /dev/null
+++ b/packages/react/src/components/Autocomplete.jsx
@@ -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 (
+
+
{getDocLabel(doc)}
+
+
+ {doc.params?.map(({ name, type, description }, i) => (
+ -
+ {name} : {type.names?.join(' | ')} {description ? <> - {description}> : ''}
+
+ ))}
+
+
+ {doc.examples?.map((example, i) => (
+
+
{
+ console.log('ola!');
+ navigator.clipboard.writeText(example);
+ e.stopPropagation();
+ }}
+ >
+ {example}
+
+
+ ))}
+
+
+ );
+}
+
+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();
+ 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' },
+ ], */
+ };
+};
diff --git a/packages/react/src/components/CodeMirror6.jsx b/packages/react/src/components/CodeMirror6.jsx
index 51573fee..e198e8ab 100644
--- a/packages/react/src/components/CodeMirror6.jsx
+++ b/packages/react/src/components/CodeMirror6.jsx
@@ -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,
diff --git a/website/src/repl/Repl.css b/website/src/repl/Repl.css
index 91132464..1ed44eaa 100644
--- a/website/src/repl/Repl.css
+++ b/website/src/repl/Repl.css
@@ -18,3 +18,7 @@
padding-top: 12px !important;
padding-left: 8px !important;
}
+
+.cm-scroller {
+ padding-bottom: 50vh;
+}