@elabs-ai/components-editor 4.1.0 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-C62O7IOQ.js → chunk-FO5S3YZM.js} +241 -158
- package/dist/chunk-FO5S3YZM.js.map +1 -0
- package/dist/index.d.ts +5 -4
- package/dist/index.js +57 -39
- package/dist/index.js.map +1 -1
- package/dist/markdown/index.d.ts +2 -2
- package/dist/markdown/index.js +265 -188
- package/dist/markdown/index.js.map +1 -1
- package/dist/{markdown-editor-CBp_4eDv.d.ts → markdown-editor-Dn-0L_MM.d.ts} +8 -1
- package/dist/monaco.d.ts +2 -0
- package/dist/monaco.js +9 -0
- package/dist/monaco.js.map +1 -0
- package/package.json +9 -5
- package/src/ai-objects/decision-card.tsx +15 -9
- package/src/ai-objects/knowledge-card.tsx +18 -9
- package/src/barrel-monaco-lazy.test.ts +50 -0
- package/src/calc-block/calc-block.tsx +11 -7
- package/src/code-editor/code-editor.test.tsx +141 -14
- package/src/code-editor/code-editor.tsx +166 -35
- package/src/code-workspace/code-workspace.test.tsx +31 -12
- package/src/copy-button/copy-button.tsx +6 -3
- package/src/diff-editor/diff-editor.test.tsx +9 -3
- package/src/diff-editor/diff-editor.tsx +47 -23
- package/src/editor-toolbar/editor-toolbar.tsx +8 -2
- package/src/index.ts +4 -3
- package/src/markdown-academic/citations.tsx +14 -7
- package/src/markdown-academic/footnotes.tsx +1 -1
- package/src/markdown-academic/math.tsx +7 -4
- package/src/markdown-editor/completions/completions-menu.tsx +5 -2
- package/src/markdown-editor/directive-views.tsx +33 -19
- package/src/markdown-editor/markdown-editor.stories.tsx +9 -3
- package/src/markdown-editor/slash/slash-menu.tsx +5 -2
- package/src/markdown-editor/table-view.tsx +28 -15
- package/src/markdown-iteration/iteration-builder-dialog.tsx +39 -18
- package/src/markdown-iteration/template-dialog.tsx +25 -7
- package/src/markdown-outline/document-outline.tsx +6 -2
- package/src/markdown-preview/markdown-preview-academic.test.tsx +3 -3
- package/src/markdown-toolbar/markdown-toolbar.tsx +42 -24
- package/src/markdown-workspace/markdown-workspace.test.tsx +22 -3
- package/src/markdown-workspace/markdown-workspace.tsx +6 -3
- package/src/mermaid-diagram/mermaid-diagram-fixes.test.tsx +130 -0
- package/src/mermaid-diagram/mermaid-diagram.test.tsx +2 -1
- package/src/mermaid-diagram/mermaid-diagram.tsx +89 -40
- package/src/mermaid-diagram/mermaid-viewer.tsx +21 -20
- package/src/monaco.ts +21 -0
- package/dist/chunk-C62O7IOQ.js.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { E as EditorContentAccess, M as MonacoCodeEditor } from './markdown-editor-
|
|
2
|
-
export { C as CodeEditor, a as CodeEditorProps, b as EditorAction, c as EditorSelection, d as EmbedAssetFn, e as MarkdownEditor, f as MarkdownEditorHandle, g as MarkdownEditorProps, m as monacoContentAccess } from './markdown-editor-
|
|
1
|
+
import { E as EditorContentAccess, M as MonacoCodeEditor } from './markdown-editor-Dn-0L_MM.js';
|
|
2
|
+
export { C as CodeEditor, a as CodeEditorProps, b as EditorAction, c as EditorSelection, d as EmbedAssetFn, e as MarkdownEditor, f as MarkdownEditorHandle, g as MarkdownEditorProps, m as monacoContentAccess } from './markdown-editor-Dn-0L_MM.js';
|
|
3
3
|
import * as react from 'react';
|
|
4
4
|
import { HTMLAttributes, ReactNode, ComponentProps } from 'react';
|
|
5
5
|
import * as monaco from 'monaco-editor';
|
|
6
|
-
export { monaco };
|
|
7
6
|
import { Button } from '@elabs-ai/components-ui';
|
|
8
7
|
import { ThemeName } from '@elabs-ai/components-tokens';
|
|
9
8
|
import '@milkdown/kit/ctx';
|
|
@@ -11,6 +10,8 @@ import '@milkdown/kit/prose/model';
|
|
|
11
10
|
import '@milkdown/kit/prose/state';
|
|
12
11
|
|
|
13
12
|
type MonacoDiffEditor = monaco.editor.IStandaloneDiffEditor;
|
|
13
|
+
/** Same pattern as `code-editor.tsx`'s `MonacoNamespace`. */
|
|
14
|
+
type MonacoNamespace = typeof monaco;
|
|
14
15
|
interface DiffEditorProps extends Omit<HTMLAttributes<HTMLDivElement>, "defaultValue"> {
|
|
15
16
|
/** Left/original document. */
|
|
16
17
|
original: string;
|
|
@@ -27,7 +28,7 @@ interface DiffEditorProps extends Omit<HTMLAttributes<HTMLDivElement>, "defaultV
|
|
|
27
28
|
/** Passthrough Monaco diff options (merged over the defaults). */
|
|
28
29
|
options?: monaco.editor.IStandaloneDiffEditorConstructionOptions;
|
|
29
30
|
/** Called once the diff editor + monaco namespace are ready. */
|
|
30
|
-
onMount?: (editor: MonacoDiffEditor, monacoApi:
|
|
31
|
+
onMount?: (editor: MonacoDiffEditor, monacoApi: MonacoNamespace) => void;
|
|
31
32
|
}
|
|
32
33
|
/**
|
|
33
34
|
* A token-themed Monaco diff editor (original ↔ modified). Same theming bridge
|
package/dist/index.js
CHANGED
|
@@ -10,10 +10,9 @@ import {
|
|
|
10
10
|
buildBrandThemeData,
|
|
11
11
|
monacoContentAccess,
|
|
12
12
|
useDataTheme
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-FO5S3YZM.js";
|
|
14
14
|
|
|
15
15
|
// src/diff-editor/diff-editor.tsx
|
|
16
|
-
import * as monaco from "monaco-editor";
|
|
17
16
|
import { cn } from "@elabs-ai/components-ui/lib/cn";
|
|
18
17
|
import {
|
|
19
18
|
forwardRef,
|
|
@@ -46,59 +45,72 @@ var DiffEditor = forwardRef(function DiffEditor2({
|
|
|
46
45
|
...props
|
|
47
46
|
}, ref) {
|
|
48
47
|
const containerRef = useRef(null);
|
|
49
|
-
const [
|
|
48
|
+
const [editor, setEditor] = useState(null);
|
|
50
49
|
const { theme, revision } = useDataTheme();
|
|
50
|
+
const monacoRef = useRef(null);
|
|
51
51
|
const onMountRef = useRef(onMount);
|
|
52
52
|
onMountRef.current = onMount;
|
|
53
|
-
useImperativeHandle(ref, () =>
|
|
54
|
-
|
|
53
|
+
useImperativeHandle(ref, () => editor, [
|
|
54
|
+
editor
|
|
55
55
|
]);
|
|
56
56
|
useEffect(() => {
|
|
57
57
|
const container = containerRef.current;
|
|
58
58
|
if (!container) return;
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
59
|
+
let cancelled = false;
|
|
60
|
+
let instance = null;
|
|
61
|
+
let originalModel = null;
|
|
62
|
+
let modifiedModel = null;
|
|
63
|
+
import("monaco-editor").then((monacoApi) => {
|
|
64
|
+
if (cancelled) return;
|
|
65
|
+
monacoRef.current = monacoApi;
|
|
66
|
+
instance = monacoApi.editor.createDiffEditor(container, {
|
|
67
|
+
...BASE_OPTIONS,
|
|
68
|
+
readOnly,
|
|
69
|
+
renderSideBySide,
|
|
70
|
+
...options
|
|
71
|
+
});
|
|
72
|
+
originalModel = monacoApi.editor.createModel(original, language);
|
|
73
|
+
modifiedModel = monacoApi.editor.createModel(modified, language);
|
|
74
|
+
instance.setModel({ original: originalModel, modified: modifiedModel });
|
|
75
|
+
setEditor(instance);
|
|
76
|
+
onMountRef.current?.(instance, monacoApi);
|
|
64
77
|
});
|
|
65
|
-
const originalModel = monaco.editor.createModel(original, language);
|
|
66
|
-
const modifiedModel = monaco.editor.createModel(modified, language);
|
|
67
|
-
instance.setModel({ original: originalModel, modified: modifiedModel });
|
|
68
|
-
setEditor(instance);
|
|
69
|
-
onMountRef.current?.(instance, monaco);
|
|
70
78
|
return () => {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
79
|
+
cancelled = true;
|
|
80
|
+
instance?.dispose();
|
|
81
|
+
originalModel?.dispose();
|
|
82
|
+
modifiedModel?.dispose();
|
|
83
|
+
monacoRef.current = null;
|
|
74
84
|
setEditor(null);
|
|
75
85
|
};
|
|
76
86
|
}, []);
|
|
77
87
|
useEffect(() => {
|
|
78
|
-
const original_ =
|
|
88
|
+
const original_ = editor?.getModel()?.original;
|
|
79
89
|
if (original_ && original_.getValue() !== original) original_.setValue(original);
|
|
80
|
-
}, [
|
|
90
|
+
}, [editor, original]);
|
|
81
91
|
useEffect(() => {
|
|
82
|
-
const modified_ =
|
|
92
|
+
const modified_ = editor?.getModel()?.modified;
|
|
83
93
|
if (modified_ && modified_.getValue() !== modified) modified_.setValue(modified);
|
|
84
|
-
}, [
|
|
94
|
+
}, [editor, modified]);
|
|
85
95
|
useEffect(() => {
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
96
|
+
const monacoApi = monacoRef.current;
|
|
97
|
+
const models = editor?.getModel();
|
|
98
|
+
if (!models || !monacoApi) return;
|
|
99
|
+
monacoApi.editor.setModelLanguage(models.original, language);
|
|
100
|
+
monacoApi.editor.setModelLanguage(models.modified, language);
|
|
101
|
+
}, [editor, language]);
|
|
91
102
|
useEffect(() => {
|
|
92
|
-
|
|
93
|
-
}, [
|
|
103
|
+
editor?.updateOptions({ readOnly, renderSideBySide });
|
|
104
|
+
}, [editor, readOnly, renderSideBySide]);
|
|
94
105
|
useEffect(() => {
|
|
95
|
-
|
|
106
|
+
const monacoApi = monacoRef.current;
|
|
107
|
+
if (!editor || !monacoApi) return;
|
|
96
108
|
try {
|
|
97
|
-
applyBrandTheme(
|
|
109
|
+
applyBrandTheme(monacoApi, theme);
|
|
98
110
|
} catch (err) {
|
|
99
111
|
console.error("[@elabs-ai/components-editor] failed to apply brand theme", err);
|
|
100
112
|
}
|
|
101
|
-
}, [
|
|
113
|
+
}, [editor, theme, revision]);
|
|
102
114
|
const resolvedStyle = {
|
|
103
115
|
height: typeof height === "number" ? `${height}px` : height,
|
|
104
116
|
...style
|
|
@@ -292,7 +304,7 @@ var CodeWorkspace = forwardRef2(
|
|
|
292
304
|
value: file.value,
|
|
293
305
|
readOnly,
|
|
294
306
|
onChange: (next) => onFileChange?.(file.path, next),
|
|
295
|
-
onMount: (
|
|
307
|
+
onMount: (editor) => setActiveEditor(editor),
|
|
296
308
|
height: "100%"
|
|
297
309
|
},
|
|
298
310
|
file.path
|
|
@@ -316,7 +328,8 @@ import {
|
|
|
316
328
|
SelectContent,
|
|
317
329
|
SelectItem,
|
|
318
330
|
SelectTrigger,
|
|
319
|
-
SelectValue
|
|
331
|
+
SelectValue,
|
|
332
|
+
useLocale
|
|
320
333
|
} from "@elabs-ai/components-ui";
|
|
321
334
|
import { cn as cn3 } from "@elabs-ai/components-ui/lib/cn";
|
|
322
335
|
import { forwardRef as forwardRef3 } from "react";
|
|
@@ -353,6 +366,7 @@ var EditorToolbar = forwardRef3(function EditorToolbar2({
|
|
|
353
366
|
className,
|
|
354
367
|
...props
|
|
355
368
|
}, ref) {
|
|
369
|
+
const { t } = useLocale();
|
|
356
370
|
return /* @__PURE__ */ jsxs2(
|
|
357
371
|
"div",
|
|
358
372
|
{
|
|
@@ -367,7 +381,15 @@ var EditorToolbar = forwardRef3(function EditorToolbar2({
|
|
|
367
381
|
/* @__PURE__ */ jsxs2("div", { className: "ml-auto flex items-center gap-1.5", children: [
|
|
368
382
|
actions,
|
|
369
383
|
onLanguageChange ? /* @__PURE__ */ jsxs2(Select, { value: language, onValueChange: onLanguageChange, children: [
|
|
370
|
-
/* @__PURE__ */ jsx3(
|
|
384
|
+
/* @__PURE__ */ jsx3(
|
|
385
|
+
SelectTrigger,
|
|
386
|
+
{
|
|
387
|
+
size: "sm",
|
|
388
|
+
className: "h-7 w-[140px]",
|
|
389
|
+
"aria-label": t("editor.editorToolbar.language"),
|
|
390
|
+
children: /* @__PURE__ */ jsx3(SelectValue, { placeholder: t("editor.editorToolbar.language") })
|
|
391
|
+
}
|
|
392
|
+
),
|
|
371
393
|
/* @__PURE__ */ jsx3(SelectContent, { children: languages.map((l) => /* @__PURE__ */ jsx3(SelectItem, { value: l.id, children: l.label }, l.id)) })
|
|
372
394
|
] }) : null,
|
|
373
395
|
copyValue != null ? /* @__PURE__ */ jsx3(CopyButton, { value: copyValue }) : null
|
|
@@ -376,9 +398,6 @@ var EditorToolbar = forwardRef3(function EditorToolbar2({
|
|
|
376
398
|
}
|
|
377
399
|
);
|
|
378
400
|
});
|
|
379
|
-
|
|
380
|
-
// src/index.ts
|
|
381
|
-
import * as monaco2 from "monaco-editor";
|
|
382
401
|
export {
|
|
383
402
|
CodeEditor,
|
|
384
403
|
CodeWorkspace,
|
|
@@ -392,7 +411,6 @@ export {
|
|
|
392
411
|
brandThemeId,
|
|
393
412
|
buildBrandThemeData,
|
|
394
413
|
languageLabel,
|
|
395
|
-
monaco2 as monaco,
|
|
396
414
|
monacoContentAccess,
|
|
397
415
|
useDataTheme
|
|
398
416
|
};
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/diff-editor/diff-editor.tsx","../src/code-workspace/code-workspace.tsx","../src/editor-toolbar/editor-toolbar.tsx","../src/lib/languages.ts","../src/index.ts"],"sourcesContent":["\"use client\";\n\nimport * as monaco from \"monaco-editor\";\nimport { cn } from \"@elabs-ai/components-ui/lib/cn\";\nimport {\n forwardRef,\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n type CSSProperties,\n type HTMLAttributes,\n} from \"react\";\nimport { applyBrandTheme } from \"../lib/monaco-theme-bridge\";\nimport { useDataTheme } from \"../lib/use-data-theme\";\n\nexport type MonacoDiffEditor = monaco.editor.IStandaloneDiffEditor;\n\nexport interface DiffEditorProps extends Omit<HTMLAttributes<HTMLDivElement>, \"defaultValue\"> {\n /** Left/original document. */\n original: string;\n /** Right/modified document. */\n modified: string;\n /** Monaco language id applied to both sides. Defaults to \"typescript\". */\n language?: string;\n /** Read-only (diffs are read-only by default). */\n readOnly?: boolean;\n /** Side-by-side (true) vs inline (false) diff. Defaults to side-by-side. */\n renderSideBySide?: boolean;\n /** Editor height. Number → px. Defaults to \"100%\". */\n height?: number | string;\n /** Passthrough Monaco diff options (merged over the defaults). */\n options?: monaco.editor.IStandaloneDiffEditorConstructionOptions;\n /** Called once the diff editor + monaco namespace are ready. */\n onMount?: (editor: MonacoDiffEditor, monacoApi: typeof monaco) => void;\n}\n\nconst BASE_OPTIONS: monaco.editor.IStandaloneDiffEditorConstructionOptions = {\n automaticLayout: true,\n minimap: { enabled: false },\n scrollBeyondLastLine: false,\n fontSize: 13,\n ignoreTrimWhitespace: false,\n padding: { top: 12, bottom: 12 },\n scrollbar: { verticalScrollbarSize: 10, horizontalScrollbarSize: 10 },\n};\n\n/**\n * A token-themed Monaco diff editor (original ↔ modified). Same theming bridge\n * and chrome story as {@link CodeEditor}; reads as a side-by-side or inline diff.\n */\nexport const DiffEditor = forwardRef<MonacoDiffEditor | null, DiffEditorProps>(function DiffEditor(\n {\n original,\n modified,\n language = \"typescript\",\n readOnly = true,\n renderSideBySide = true,\n height = \"100%\",\n options,\n onMount,\n className,\n style,\n ...props\n },\n ref,\n) {\n const containerRef = useRef<HTMLDivElement>(null);\n const [editor, setEditor] = useState<MonacoDiffEditor | null>(null);\n const { theme, revision } = useDataTheme();\n\n const onMountRef = useRef(onMount);\n onMountRef.current = onMount;\n\n useImperativeHandle<MonacoDiffEditor | null, MonacoDiffEditor | null>(ref, () => editor, [\n editor,\n ]);\n\n // Mount once.\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n\n const instance = monaco.editor.createDiffEditor(container, {\n ...BASE_OPTIONS,\n readOnly,\n renderSideBySide,\n ...options,\n });\n const originalModel = monaco.editor.createModel(original, language);\n const modifiedModel = monaco.editor.createModel(modified, language);\n instance.setModel({ original: originalModel, modified: modifiedModel });\n // Theme is applied by the effect below once `setEditor` runs.\n setEditor(instance);\n onMountRef.current?.(instance, monaco);\n\n return () => {\n instance.dispose();\n originalModel.dispose();\n modifiedModel.dispose();\n setEditor(null);\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n const original_ = editor?.getModel()?.original;\n if (original_ && original_.getValue() !== original) original_.setValue(original);\n }, [editor, original]);\n\n useEffect(() => {\n const modified_ = editor?.getModel()?.modified;\n if (modified_ && modified_.getValue() !== modified) modified_.setValue(modified);\n }, [editor, modified]);\n\n useEffect(() => {\n const models = editor?.getModel();\n if (!models) return;\n monaco.editor.setModelLanguage(models.original, language);\n monaco.editor.setModelLanguage(models.modified, language);\n }, [editor, language]);\n\n useEffect(() => {\n editor?.updateOptions({ readOnly, renderSideBySide });\n }, [editor, readOnly, renderSideBySide]);\n\n useEffect(() => {\n if (!editor) return;\n try {\n applyBrandTheme(monaco, theme);\n } catch (err) {\n console.error(\"[@elabs-ai/components-editor] failed to apply brand theme\", err);\n }\n // `revision` re-applies once the data-theme attribute settles. See CodeEditor.\n }, [editor, theme, revision]);\n\n const resolvedStyle: CSSProperties = {\n height: typeof height === \"number\" ? `${height}px` : height,\n ...style,\n };\n\n return (\n <div\n ref={containerRef}\n data-testid=\"diff-editor\"\n className={cn(\"h-full w-full overflow-hidden bg-background text-foreground\", className)}\n style={resolvedStyle}\n {...props}\n />\n );\n});\n","\"use client\";\n\nimport { Tabs, TabsContent, TabsList, TabsTrigger } from \"@elabs-ai/components-ui\";\nimport { cn } from \"@elabs-ai/components-ui/lib/cn\";\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n type CSSProperties,\n type HTMLAttributes,\n} from \"react\";\nimport { CodeEditor, type MonacoCodeEditor } from \"../code-editor\";\nimport { CopyButton } from \"../copy-button\";\nimport {\n monacoContentAccess,\n type EditorContentAccess,\n type EditorSelection,\n} from \"../lib/editor-content-access\";\n\nexport interface EditorFile {\n /** Unique path/name; shown (basename) on the tab and used as the model path. */\n path: string;\n /** Monaco language id. Inferred from the extension when omitted. */\n language?: string;\n /** File content. */\n value: string;\n}\n\nexport interface CodeWorkspaceProps extends Omit<\n HTMLAttributes<HTMLDivElement>,\n \"onChange\" | \"defaultValue\"\n> {\n /** Open files, one tab each. */\n files: EditorFile[];\n /** Controlled active file path. */\n activePath?: string;\n /** Initial active path for uncontrolled use. Defaults to the first file. */\n defaultActivePath?: string;\n /** Called when the active tab changes. */\n onActivePathChange?: (path: string) => void;\n /** Called on every edit with the file path + new content. */\n onFileChange?: (path: string, value: string) => void;\n /** Render all files read-only. */\n readOnly?: boolean;\n /** Workspace height. Number → px. Defaults to \"100%\". */\n height?: number | string;\n}\n\nconst EXT_LANGUAGE: Record<string, string> = {\n ts: \"typescript\",\n tsx: \"typescript\",\n mts: \"typescript\",\n cts: \"typescript\",\n js: \"javascript\",\n jsx: \"javascript\",\n mjs: \"javascript\",\n cjs: \"javascript\",\n json: \"json\",\n css: \"css\",\n scss: \"scss\",\n less: \"less\",\n html: \"html\",\n md: \"markdown\",\n py: \"python\",\n sql: \"sql\",\n yml: \"yaml\",\n yaml: \"yaml\",\n xml: \"xml\",\n sh: \"shell\",\n};\n\nconst basename = (path: string) => path.split(\"/\").pop() || path;\n\n/**\n * Radix composes each `TabsContent`'s DOM id from the `Tabs`/`TabsTrigger`\n * `value` (see #154): a raw `file.path` leaks `/`, `.`, spaces and non-ASCII\n * characters straight into that id, which is what a screen reader gets back\n * via `aria-controls`. `path` stays the display label and the lookup key in\n * component state (`active`); this is only ever a DOM-id-safe Tabs value.\n *\n * The encoding is INJECTIVE and depends only on the path — never on the\n * file's position in `files`. Every character outside `[A-Za-z0-9-]` becomes\n * `_<hex code point>_`, and `_` itself is never emitted literally, so the\n * mapping is reversible and two distinct paths can never produce the same\n * value (\"a/b\" → `tab-a_2f_b`, \"a.b\" → `tab-a_2e_b`). An index-derived value\n * would have been collision-safe too, but it changes when the list is\n * reordered or a file is inserted, which re-keys the active `TabsContent` and\n * throws away Monaco's selection, scroll position and undo history on an\n * otherwise harmless `files` update.\n */\nfunction tabIdForFile(path: string): string {\n let out = \"\";\n for (const char of path) {\n out += /[A-Za-z0-9-]/.test(char) ? char : `_${char.codePointAt(0)!.toString(16)}_`;\n }\n return `tab-${out}`;\n}\n\nfunction inferLanguage(file: EditorFile): string {\n if (file.language) return file.language;\n const ext = file.path.split(\".\").pop()?.toLowerCase() ?? \"\";\n return EXT_LANGUAGE[ext] ?? \"plaintext\";\n}\n\n/**\n * Imperative handle exposed via `CodeWorkspace`'s `ref`.\n *\n * **Migration note:** the forwarded `ref` type changed from `HTMLDivElement` to\n * `CodeWorkspaceHandle` (mirrors the #273 `MarkdownWorkspaceHandle` precedent).\n * Replace any `ref.current` / `ref.current.scrollIntoView()` DOM access with\n * `ref.current?.getElement()`. This is the only breaking change in this work.\n */\nexport interface CodeWorkspaceHandle extends EditorContentAccess {\n /**\n * The live Monaco editor for the currently active tab, or `null` while booting\n * or when no files are open. Consumers needing the full Monaco API can use this\n * and pass it to `monacoContentAccess(handle.getActiveEditor()!)`.\n */\n getActiveEditor(): MonacoCodeEditor | null;\n /**\n * The workspace root DOM element. Preserves the old `HTMLDivElement` ref access\n * that existed before the ref-type change (#273 `MarkdownWorkspace` playbook).\n */\n getElement(): HTMLDivElement | null;\n}\n\n/** No-op EditorContentAccess returned when no Monaco editor is mounted. */\nconst NULL_ACCESS: EditorContentAccess = {\n getText: () => \"\",\n getSelection: () => ({ text: \"\", empty: true }),\n replaceSelection: () => undefined,\n insertAtCursor: () => undefined,\n focus: () => undefined,\n onSelectionChange: () => () => undefined,\n};\n\n/**\n * Multi-file editor shell: brand-ui `Tabs` for the file bar above a single\n * {@link CodeEditor} that swaps to the active file. This is the \"reuse our\n * components for the chrome\" surface — Tabs/Button are ours; the editing surface\n * is Monaco. Edits bubble through `onFileChange`.\n *\n * The forwarded `ref` exposes a {@link CodeWorkspaceHandle} (not `HTMLDivElement`).\n * Use `ref.current?.getElement()` to access the root DOM node.\n */\nexport const CodeWorkspace = forwardRef<CodeWorkspaceHandle, CodeWorkspaceProps>(\n function CodeWorkspace(\n {\n files,\n activePath,\n defaultActivePath,\n onActivePathChange,\n onFileChange,\n readOnly = false,\n height = \"100%\",\n className,\n style,\n ...props\n },\n ref,\n ) {\n const [internalActive, setInternalActive] = useState(defaultActivePath ?? files[0]?.path ?? \"\");\n const isControlled = activePath !== undefined;\n const requested = isControlled ? activePath : internalActive;\n const activeFile = files.find((f) => f.path === requested) ?? files[0];\n const active = activeFile?.path ?? \"\";\n\n // DOM-id-safe Tabs value per file (#154); `path` stays the lookup key.\n const tabs = files.map((file) => ({ file, id: tabIdForFile(file.path) }));\n const activeTabId = tabs.find((t) => t.file.path === active)?.id ?? \"\";\n\n // The root div ref (getElement() preserves old HTMLDivElement access).\n const rootRef = useRef<HTMLDivElement | null>(null);\n\n // The live Monaco editor for the active tab. Nulled when there is no active file.\n const [activeEditor, setActiveEditor] = useState<MonacoCodeEditor | null>(null);\n\n // Defensive: if the active file is removed (no `activeFile`), null the held instance\n // so getActiveEditor() and content-access methods don't act on a disposed editor.\n useEffect(() => {\n if (!activeFile) setActiveEditor(null);\n }, [activeFile]);\n\n // A STABLE listener set for onSelectionChange. The handle adds/removes here;\n // the binding effect below forwards the ACTIVE editor's selection changes into\n // it. This is what makes a subscribe-in-mount-effect survive the editor's async\n // mount (and tab swaps): the consumer subscribes once; binding re-attaches as\n // `activeEditor` changes. (Delegating onSelectionChange to a call-time snapshot\n // would bind to the not-yet-mounted editor and silently never fire.)\n const [selectionListeners] = useState(() => new Set<(sel: EditorSelection) => void>());\n useEffect(() => {\n if (!activeEditor) return;\n const unsub = monacoContentAccess(activeEditor).onSelectionChange((sel) =>\n selectionListeners.forEach((l) => l(sel)),\n );\n return unsub;\n }, [activeEditor, selectionListeners]);\n\n const selectTab = useCallback(\n (path: string) => {\n if (!isControlled) setInternalActive(path);\n onActivePathChange?.(path);\n },\n [isControlled, onActivePathChange],\n );\n\n useImperativeHandle(ref, () => {\n const access = activeEditor ? monacoContentAccess(activeEditor) : NULL_ACCESS;\n return {\n getActiveEditor: () => activeEditor,\n getElement: () => rootRef.current,\n getText: () => access.getText(),\n getSelection: () => access.getSelection(),\n replaceSelection: (text: string) => access.replaceSelection(text),\n insertAtCursor: (text: string) => access.insertAtCursor(text),\n focus: () => access.focus(),\n // Stable set (not the call-time `access`) so a subscription survives the\n // editor's async mount + tab swaps; the binding effect forwards events.\n onSelectionChange: (listener) => {\n selectionListeners.add(listener);\n return () => selectionListeners.delete(listener);\n },\n };\n }, [activeEditor, selectionListeners]);\n\n const resolvedStyle: CSSProperties = {\n height: typeof height === \"number\" ? `${height}px` : height,\n ...style,\n };\n\n return (\n <div\n ref={rootRef}\n className={cn(\n \"flex flex-col overflow-hidden rounded-lg border border-border bg-surface\",\n className,\n )}\n style={resolvedStyle}\n {...props}\n >\n <Tabs\n value={activeTabId}\n onValueChange={(id) => {\n const found = tabs.find((t) => t.id === id);\n if (found) selectTab(found.file.path);\n }}\n className=\"flex min-h-0 flex-1 flex-col gap-0\"\n >\n <div className=\"flex items-center border-b border-border bg-surface\">\n <TabsList className=\"h-9 flex-1 justify-start gap-0 rounded-none bg-transparent p-0\">\n {tabs.map(({ file, id }) => (\n <TabsTrigger\n key={id}\n value={id}\n className=\"h-9 rounded-none border-e border-border px-3 text-xs data-[state=active]:bg-background data-[state=active]:shadow-none\"\n >\n {basename(file.path)}\n </TabsTrigger>\n ))}\n </TabsList>\n {activeFile ? <CopyButton value={activeFile.value} className=\"me-1.5\" /> : null}\n </div>\n\n {tabs.map(({ file, id }) => {\n const isActive = file.path === activeFile?.path;\n return (\n // `forceMount` keeps every tab's content in the DOM so each\n // trigger's `aria-controls` resolves to a real element, not only\n // the active one (#154). Radix derives its own `hidden` from\n // `forceMount || isSelected`, so under `forceMount` it hides\n // NOTHING: without the explicit `hidden` below every inactive\n // panel stays a visible `flex-1` child and the editor height is\n // split across all of them. `tabIndex={-1}` keeps the empty\n // panels out of the tab sequence for the same reason. Only the\n // active file mounts a (single) Monaco instance.\n <TabsContent\n key={id}\n value={id}\n forceMount\n hidden={!isActive}\n tabIndex={isActive ? 0 : -1}\n className=\"mt-0 min-h-0 flex-1\"\n >\n {isActive ? (\n <CodeEditor\n key={file.path}\n path={file.path}\n language={inferLanguage(file)}\n value={file.value}\n readOnly={readOnly}\n onChange={(next) => onFileChange?.(file.path, next)}\n onMount={(editor) => setActiveEditor(editor)}\n height=\"100%\"\n />\n ) : null}\n </TabsContent>\n );\n })}\n </Tabs>\n </div>\n );\n },\n);\n","\"use client\";\n\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"@elabs-ai/components-ui\";\nimport { cn } from \"@elabs-ai/components-ui/lib/cn\";\nimport { forwardRef, type HTMLAttributes, type ReactNode } from \"react\";\nimport { CopyButton } from \"../copy-button\";\nimport { EDITOR_LANGUAGES, type EditorLanguage } from \"../lib/languages\";\n\nexport interface EditorToolbarProps extends HTMLAttributes<HTMLDivElement> {\n /** Filename shown on the left (e.g. \"index.ts\"). */\n filename?: ReactNode;\n /** Active language id; shows a language picker when `onLanguageChange` is set. */\n language?: string;\n /** Called when the user picks a language. Omit to hide the picker. */\n onLanguageChange?: (language: string) => void;\n /** Languages offered in the picker. Defaults to {@link EDITOR_LANGUAGES}. */\n languages?: EditorLanguage[];\n /** Text copied by the copy button. Omit to hide the button. */\n copyValue?: string;\n /** Extra actions rendered before the copy button (brand-ui buttons, etc.). */\n actions?: ReactNode;\n}\n\n/**\n * Brand-ui chrome for the editors — the part that genuinely reuses our\n * components. Renders a filename label, an optional language `Select` and a copy\n * `Button`. The editing surface itself is Monaco; this is the frame around it.\n */\nexport const EditorToolbar = forwardRef<HTMLDivElement, EditorToolbarProps>(function EditorToolbar(\n {\n filename,\n language,\n onLanguageChange,\n languages = EDITOR_LANGUAGES,\n copyValue,\n actions,\n className,\n ...props\n },\n ref,\n) {\n return (\n <div\n ref={ref}\n className={cn(\n \"flex h-10 shrink-0 items-center gap-2 border-b border-border bg-surface px-3\",\n className,\n )}\n {...props}\n >\n {filename != null ? (\n <span className=\"truncate text-sm font-medium text-foreground\">{filename}</span>\n ) : null}\n\n <div className=\"ml-auto flex items-center gap-1.5\">\n {actions}\n\n {onLanguageChange ? (\n <Select value={language} onValueChange={onLanguageChange}>\n <SelectTrigger size=\"sm\" className=\"h-7 w-[140px]\" aria-label=\"Language\">\n <SelectValue placeholder=\"Language\" />\n </SelectTrigger>\n <SelectContent>\n {languages.map((l) => (\n <SelectItem key={l.id} value={l.id}>\n {l.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n ) : null}\n\n {copyValue != null ? <CopyButton value={copyValue} /> : null}\n </div>\n </div>\n );\n});\n","/**\n * Curated language list for the editor toolbar's language picker. Ids are\n * Monaco's built-in language ids (`monaco.languages.getLanguages()`), so they\n * map straight onto `setModelLanguage` / model creation.\n */\nexport interface EditorLanguage {\n /** Monaco language id (e.g. \"typescript\"). */\n id: string;\n /** Human-readable label for the picker. */\n label: string;\n}\n\nexport const EDITOR_LANGUAGES: EditorLanguage[] = [\n { id: \"typescript\", label: \"TypeScript\" },\n { id: \"javascript\", label: \"JavaScript\" },\n { id: \"json\", label: \"JSON\" },\n { id: \"html\", label: \"HTML\" },\n { id: \"css\", label: \"CSS\" },\n { id: \"scss\", label: \"SCSS\" },\n { id: \"markdown\", label: \"Markdown\" },\n { id: \"python\", label: \"Python\" },\n { id: \"sql\", label: \"SQL\" },\n { id: \"yaml\", label: \"YAML\" },\n { id: \"xml\", label: \"XML\" },\n { id: \"shell\", label: \"Shell\" },\n { id: \"plaintext\", label: \"Plain text\" },\n];\n\n/** Look up a language's label, falling back to the raw id. */\nexport function languageLabel(id: string): string {\n return EDITOR_LANGUAGES.find((l) => l.id === id)?.label ?? id;\n}\n","/**\n * @elabs-ai/components-editor — a token-themed Monaco (VS Code) editor wrapped as brand-ui\n * components.\n *\n * Monaco is a self-rendering editor engine; this package wraps it the way\n * @elabs-ai/components-flow wraps React Flow and @elabs-ai/components-data wraps TanStack. The editing\n * surface + widgets are Monaco's, recolored from the active brand theme via the\n * theming bridge; the chrome (toolbar, file tabs, copy button) is brand-ui.\n *\n * Worker setup (for completions/diagnostics) — import ONCE at the app entry:\n * import \"@elabs-ai/components-editor/monaco-environment\"; // Vite apps\n */\nexport {\n CodeEditor,\n type CodeEditorProps,\n type MonacoCodeEditor,\n type EditorAction,\n} from \"./code-editor\";\nexport { DiffEditor, type DiffEditorProps, type MonacoDiffEditor } from \"./diff-editor\";\nexport {\n MarkdownEditor,\n type MarkdownEditorProps,\n type MarkdownEditorHandle,\n type EmbedAssetFn,\n} from \"./markdown-editor\";\nexport {\n CodeWorkspace,\n type CodeWorkspaceHandle,\n type CodeWorkspaceProps,\n type EditorFile,\n} from \"./code-workspace\";\nexport {\n monacoContentAccess,\n type EditorContentAccess,\n type EditorSelection,\n} from \"./lib/editor-content-access\";\nexport { EditorToolbar, type EditorToolbarProps } from \"./editor-toolbar\";\nexport { EditorContextMenu, type EditorContextMenuProps } from \"./editor-context-menu\";\nexport { CopyButton, type CopyButtonProps } from \"./copy-button\";\n\n// Theming bridge + language helpers (advanced consumers / custom chrome).\nexport { applyBrandTheme, buildBrandThemeData, brandThemeId } from \"./lib/monaco-theme-bridge\";\nexport { useDataTheme, type DataThemeState } from \"./lib/use-data-theme\";\nexport { EDITOR_LANGUAGES, languageLabel, type EditorLanguage } from \"./lib/languages\";\n\n// Re-export the monaco namespace so consumers can build custom editors / wire\n// commands without adding a direct dependency.\nexport * as monaco from \"monaco-editor\";\n"],"mappings":"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","names":["DiffEditor","editor","cn","forwardRef","useEffect","useImperativeHandle","useRef","useState","jsx","forwardRef","CodeWorkspace","useState","useRef","useEffect","useImperativeHandle","cn","editor","cn","forwardRef","jsx","jsxs","forwardRef","EditorToolbar","cn","monaco"]}
|
|
1
|
+
{"version":3,"sources":["../src/diff-editor/diff-editor.tsx","../src/code-workspace/code-workspace.tsx","../src/editor-toolbar/editor-toolbar.tsx","../src/lib/languages.ts"],"sourcesContent":["\"use client\";\n\n// Type-only — see the matching note in `../code-editor/code-editor.tsx`. The\n// engine loads at RUNTIME via `import(\"monaco-editor\")` in the mount effect\n// below (`monacoRef`), so importing this module (e.g. transitively, via the\n// barrel) never evaluates Monaco.\nimport type * as monaco from \"monaco-editor\";\nimport { cn } from \"@elabs-ai/components-ui/lib/cn\";\nimport {\n forwardRef,\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n type CSSProperties,\n type HTMLAttributes,\n} from \"react\";\nimport { applyBrandTheme } from \"../lib/monaco-theme-bridge\";\nimport { useDataTheme } from \"../lib/use-data-theme\";\n\nexport type MonacoDiffEditor = monaco.editor.IStandaloneDiffEditor;\n\n/** Same pattern as `code-editor.tsx`'s `MonacoNamespace`. */\ntype MonacoNamespace = typeof monaco;\n\nexport interface DiffEditorProps extends Omit<HTMLAttributes<HTMLDivElement>, \"defaultValue\"> {\n /** Left/original document. */\n original: string;\n /** Right/modified document. */\n modified: string;\n /** Monaco language id applied to both sides. Defaults to \"typescript\". */\n language?: string;\n /** Read-only (diffs are read-only by default). */\n readOnly?: boolean;\n /** Side-by-side (true) vs inline (false) diff. Defaults to side-by-side. */\n renderSideBySide?: boolean;\n /** Editor height. Number → px. Defaults to \"100%\". */\n height?: number | string;\n /** Passthrough Monaco diff options (merged over the defaults). */\n options?: monaco.editor.IStandaloneDiffEditorConstructionOptions;\n /** Called once the diff editor + monaco namespace are ready. */\n onMount?: (editor: MonacoDiffEditor, monacoApi: MonacoNamespace) => void;\n}\n\nconst BASE_OPTIONS: monaco.editor.IStandaloneDiffEditorConstructionOptions = {\n automaticLayout: true,\n minimap: { enabled: false },\n scrollBeyondLastLine: false,\n fontSize: 13,\n ignoreTrimWhitespace: false,\n padding: { top: 12, bottom: 12 },\n scrollbar: { verticalScrollbarSize: 10, horizontalScrollbarSize: 10 },\n};\n\n/**\n * A token-themed Monaco diff editor (original ↔ modified). Same theming bridge\n * and chrome story as {@link CodeEditor}; reads as a side-by-side or inline diff.\n */\nexport const DiffEditor = forwardRef<MonacoDiffEditor | null, DiffEditorProps>(function DiffEditor(\n {\n original,\n modified,\n language = \"typescript\",\n readOnly = true,\n renderSideBySide = true,\n height = \"100%\",\n options,\n onMount,\n className,\n style,\n ...props\n },\n ref,\n) {\n const containerRef = useRef<HTMLDivElement>(null);\n const [editor, setEditor] = useState<MonacoDiffEditor | null>(null);\n const { theme, revision } = useDataTheme();\n // Populated once the dynamic `import(\"monaco-editor\")` below resolves.\n // `editor` (React state) is only ever set AFTER this ref, so every other\n // effect that reads both may assume: `editor` truthy implies this truthy.\n const monacoRef = useRef<MonacoNamespace | null>(null);\n\n const onMountRef = useRef(onMount);\n onMountRef.current = onMount;\n\n useImperativeHandle<MonacoDiffEditor | null, MonacoDiffEditor | null>(ref, () => editor, [\n editor,\n ]);\n\n // Mount once. Monaco itself loads lazily (see the top-of-file note) — merely\n // importing this module never evaluates the engine.\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n let cancelled = false;\n let instance: MonacoDiffEditor | null = null;\n let originalModel: monaco.editor.ITextModel | null = null;\n let modifiedModel: monaco.editor.ITextModel | null = null;\n\n import(\"monaco-editor\").then((monacoApi) => {\n if (cancelled) return;\n monacoRef.current = monacoApi;\n instance = monacoApi.editor.createDiffEditor(container, {\n ...BASE_OPTIONS,\n readOnly,\n renderSideBySide,\n ...options,\n });\n originalModel = monacoApi.editor.createModel(original, language);\n modifiedModel = monacoApi.editor.createModel(modified, language);\n instance.setModel({ original: originalModel, modified: modifiedModel });\n // Theme is applied by the effect below once `setEditor` runs.\n setEditor(instance);\n onMountRef.current?.(instance, monacoApi);\n });\n\n return () => {\n cancelled = true;\n instance?.dispose();\n originalModel?.dispose();\n modifiedModel?.dispose();\n monacoRef.current = null;\n setEditor(null);\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n const original_ = editor?.getModel()?.original;\n if (original_ && original_.getValue() !== original) original_.setValue(original);\n }, [editor, original]);\n\n useEffect(() => {\n const modified_ = editor?.getModel()?.modified;\n if (modified_ && modified_.getValue() !== modified) modified_.setValue(modified);\n }, [editor, modified]);\n\n useEffect(() => {\n const monacoApi = monacoRef.current;\n const models = editor?.getModel();\n if (!models || !monacoApi) return;\n monacoApi.editor.setModelLanguage(models.original, language);\n monacoApi.editor.setModelLanguage(models.modified, language);\n }, [editor, language]);\n\n useEffect(() => {\n editor?.updateOptions({ readOnly, renderSideBySide });\n }, [editor, readOnly, renderSideBySide]);\n\n useEffect(() => {\n const monacoApi = monacoRef.current;\n if (!editor || !monacoApi) return;\n try {\n applyBrandTheme(monacoApi, theme);\n } catch (err) {\n console.error(\"[@elabs-ai/components-editor] failed to apply brand theme\", err);\n }\n // `revision` re-applies once the data-theme attribute settles. See CodeEditor.\n }, [editor, theme, revision]);\n\n const resolvedStyle: CSSProperties = {\n height: typeof height === \"number\" ? `${height}px` : height,\n ...style,\n };\n\n return (\n <div\n ref={containerRef}\n data-testid=\"diff-editor\"\n className={cn(\"h-full w-full overflow-hidden bg-background text-foreground\", className)}\n style={resolvedStyle}\n {...props}\n />\n );\n});\n","\"use client\";\n\nimport { Tabs, TabsContent, TabsList, TabsTrigger } from \"@elabs-ai/components-ui\";\nimport { cn } from \"@elabs-ai/components-ui/lib/cn\";\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n type CSSProperties,\n type HTMLAttributes,\n} from \"react\";\nimport { CodeEditor, type MonacoCodeEditor } from \"../code-editor\";\nimport { CopyButton } from \"../copy-button\";\nimport {\n monacoContentAccess,\n type EditorContentAccess,\n type EditorSelection,\n} from \"../lib/editor-content-access\";\n\nexport interface EditorFile {\n /** Unique path/name; shown (basename) on the tab and used as the model path. */\n path: string;\n /** Monaco language id. Inferred from the extension when omitted. */\n language?: string;\n /** File content. */\n value: string;\n}\n\nexport interface CodeWorkspaceProps extends Omit<\n HTMLAttributes<HTMLDivElement>,\n \"onChange\" | \"defaultValue\"\n> {\n /** Open files, one tab each. */\n files: EditorFile[];\n /** Controlled active file path. */\n activePath?: string;\n /** Initial active path for uncontrolled use. Defaults to the first file. */\n defaultActivePath?: string;\n /** Called when the active tab changes. */\n onActivePathChange?: (path: string) => void;\n /** Called on every edit with the file path + new content. */\n onFileChange?: (path: string, value: string) => void;\n /** Render all files read-only. */\n readOnly?: boolean;\n /** Workspace height. Number → px. Defaults to \"100%\". */\n height?: number | string;\n}\n\nconst EXT_LANGUAGE: Record<string, string> = {\n ts: \"typescript\",\n tsx: \"typescript\",\n mts: \"typescript\",\n cts: \"typescript\",\n js: \"javascript\",\n jsx: \"javascript\",\n mjs: \"javascript\",\n cjs: \"javascript\",\n json: \"json\",\n css: \"css\",\n scss: \"scss\",\n less: \"less\",\n html: \"html\",\n md: \"markdown\",\n py: \"python\",\n sql: \"sql\",\n yml: \"yaml\",\n yaml: \"yaml\",\n xml: \"xml\",\n sh: \"shell\",\n};\n\nconst basename = (path: string) => path.split(\"/\").pop() || path;\n\n/**\n * Radix composes each `TabsContent`'s DOM id from the `Tabs`/`TabsTrigger`\n * `value` (see #154): a raw `file.path` leaks `/`, `.`, spaces and non-ASCII\n * characters straight into that id, which is what a screen reader gets back\n * via `aria-controls`. `path` stays the display label and the lookup key in\n * component state (`active`); this is only ever a DOM-id-safe Tabs value.\n *\n * The encoding is INJECTIVE and depends only on the path — never on the\n * file's position in `files`. Every character outside `[A-Za-z0-9-]` becomes\n * `_<hex code point>_`, and `_` itself is never emitted literally, so the\n * mapping is reversible and two distinct paths can never produce the same\n * value (\"a/b\" → `tab-a_2f_b`, \"a.b\" → `tab-a_2e_b`). An index-derived value\n * would have been collision-safe too, but it changes when the list is\n * reordered or a file is inserted, which re-keys the active `TabsContent` and\n * throws away Monaco's selection, scroll position and undo history on an\n * otherwise harmless `files` update.\n */\nfunction tabIdForFile(path: string): string {\n let out = \"\";\n for (const char of path) {\n out += /[A-Za-z0-9-]/.test(char) ? char : `_${char.codePointAt(0)!.toString(16)}_`;\n }\n return `tab-${out}`;\n}\n\nfunction inferLanguage(file: EditorFile): string {\n if (file.language) return file.language;\n const ext = file.path.split(\".\").pop()?.toLowerCase() ?? \"\";\n return EXT_LANGUAGE[ext] ?? \"plaintext\";\n}\n\n/**\n * Imperative handle exposed via `CodeWorkspace`'s `ref`.\n *\n * **Migration note:** the forwarded `ref` type changed from `HTMLDivElement` to\n * `CodeWorkspaceHandle` (mirrors the #273 `MarkdownWorkspaceHandle` precedent).\n * Replace any `ref.current` / `ref.current.scrollIntoView()` DOM access with\n * `ref.current?.getElement()`. This is the only breaking change in this work.\n */\nexport interface CodeWorkspaceHandle extends EditorContentAccess {\n /**\n * The live Monaco editor for the currently active tab, or `null` while booting\n * or when no files are open. Consumers needing the full Monaco API can use this\n * and pass it to `monacoContentAccess(handle.getActiveEditor()!)`.\n */\n getActiveEditor(): MonacoCodeEditor | null;\n /**\n * The workspace root DOM element. Preserves the old `HTMLDivElement` ref access\n * that existed before the ref-type change (#273 `MarkdownWorkspace` playbook).\n */\n getElement(): HTMLDivElement | null;\n}\n\n/** No-op EditorContentAccess returned when no Monaco editor is mounted. */\nconst NULL_ACCESS: EditorContentAccess = {\n getText: () => \"\",\n getSelection: () => ({ text: \"\", empty: true }),\n replaceSelection: () => undefined,\n insertAtCursor: () => undefined,\n focus: () => undefined,\n onSelectionChange: () => () => undefined,\n};\n\n/**\n * Multi-file editor shell: brand-ui `Tabs` for the file bar above a single\n * {@link CodeEditor} that swaps to the active file. This is the \"reuse our\n * components for the chrome\" surface — Tabs/Button are ours; the editing surface\n * is Monaco. Edits bubble through `onFileChange`.\n *\n * The forwarded `ref` exposes a {@link CodeWorkspaceHandle} (not `HTMLDivElement`).\n * Use `ref.current?.getElement()` to access the root DOM node.\n */\nexport const CodeWorkspace = forwardRef<CodeWorkspaceHandle, CodeWorkspaceProps>(\n function CodeWorkspace(\n {\n files,\n activePath,\n defaultActivePath,\n onActivePathChange,\n onFileChange,\n readOnly = false,\n height = \"100%\",\n className,\n style,\n ...props\n },\n ref,\n ) {\n const [internalActive, setInternalActive] = useState(defaultActivePath ?? files[0]?.path ?? \"\");\n const isControlled = activePath !== undefined;\n const requested = isControlled ? activePath : internalActive;\n const activeFile = files.find((f) => f.path === requested) ?? files[0];\n const active = activeFile?.path ?? \"\";\n\n // DOM-id-safe Tabs value per file (#154); `path` stays the lookup key.\n const tabs = files.map((file) => ({ file, id: tabIdForFile(file.path) }));\n const activeTabId = tabs.find((t) => t.file.path === active)?.id ?? \"\";\n\n // The root div ref (getElement() preserves old HTMLDivElement access).\n const rootRef = useRef<HTMLDivElement | null>(null);\n\n // The live Monaco editor for the active tab. Nulled when there is no active file.\n const [activeEditor, setActiveEditor] = useState<MonacoCodeEditor | null>(null);\n\n // Defensive: if the active file is removed (no `activeFile`), null the held instance\n // so getActiveEditor() and content-access methods don't act on a disposed editor.\n useEffect(() => {\n if (!activeFile) setActiveEditor(null);\n }, [activeFile]);\n\n // A STABLE listener set for onSelectionChange. The handle adds/removes here;\n // the binding effect below forwards the ACTIVE editor's selection changes into\n // it. This is what makes a subscribe-in-mount-effect survive the editor's async\n // mount (and tab swaps): the consumer subscribes once; binding re-attaches as\n // `activeEditor` changes. (Delegating onSelectionChange to a call-time snapshot\n // would bind to the not-yet-mounted editor and silently never fire.)\n const [selectionListeners] = useState(() => new Set<(sel: EditorSelection) => void>());\n useEffect(() => {\n if (!activeEditor) return;\n const unsub = monacoContentAccess(activeEditor).onSelectionChange((sel) =>\n selectionListeners.forEach((l) => l(sel)),\n );\n return unsub;\n }, [activeEditor, selectionListeners]);\n\n const selectTab = useCallback(\n (path: string) => {\n if (!isControlled) setInternalActive(path);\n onActivePathChange?.(path);\n },\n [isControlled, onActivePathChange],\n );\n\n useImperativeHandle(ref, () => {\n const access = activeEditor ? monacoContentAccess(activeEditor) : NULL_ACCESS;\n return {\n getActiveEditor: () => activeEditor,\n getElement: () => rootRef.current,\n getText: () => access.getText(),\n getSelection: () => access.getSelection(),\n replaceSelection: (text: string) => access.replaceSelection(text),\n insertAtCursor: (text: string) => access.insertAtCursor(text),\n focus: () => access.focus(),\n // Stable set (not the call-time `access`) so a subscription survives the\n // editor's async mount + tab swaps; the binding effect forwards events.\n onSelectionChange: (listener) => {\n selectionListeners.add(listener);\n return () => selectionListeners.delete(listener);\n },\n };\n }, [activeEditor, selectionListeners]);\n\n const resolvedStyle: CSSProperties = {\n height: typeof height === \"number\" ? `${height}px` : height,\n ...style,\n };\n\n return (\n <div\n ref={rootRef}\n className={cn(\n \"flex flex-col overflow-hidden rounded-lg border border-border bg-surface\",\n className,\n )}\n style={resolvedStyle}\n {...props}\n >\n <Tabs\n value={activeTabId}\n onValueChange={(id) => {\n const found = tabs.find((t) => t.id === id);\n if (found) selectTab(found.file.path);\n }}\n className=\"flex min-h-0 flex-1 flex-col gap-0\"\n >\n <div className=\"flex items-center border-b border-border bg-surface\">\n <TabsList className=\"h-9 flex-1 justify-start gap-0 rounded-none bg-transparent p-0\">\n {tabs.map(({ file, id }) => (\n <TabsTrigger\n key={id}\n value={id}\n className=\"h-9 rounded-none border-e border-border px-3 text-xs data-[state=active]:bg-background data-[state=active]:shadow-none\"\n >\n {basename(file.path)}\n </TabsTrigger>\n ))}\n </TabsList>\n {activeFile ? <CopyButton value={activeFile.value} className=\"me-1.5\" /> : null}\n </div>\n\n {tabs.map(({ file, id }) => {\n const isActive = file.path === activeFile?.path;\n return (\n // `forceMount` keeps every tab's content in the DOM so each\n // trigger's `aria-controls` resolves to a real element, not only\n // the active one (#154). Radix derives its own `hidden` from\n // `forceMount || isSelected`, so under `forceMount` it hides\n // NOTHING: without the explicit `hidden` below every inactive\n // panel stays a visible `flex-1` child and the editor height is\n // split across all of them. `tabIndex={-1}` keeps the empty\n // panels out of the tab sequence for the same reason. Only the\n // active file mounts a (single) Monaco instance.\n <TabsContent\n key={id}\n value={id}\n forceMount\n hidden={!isActive}\n tabIndex={isActive ? 0 : -1}\n className=\"mt-0 min-h-0 flex-1\"\n >\n {isActive ? (\n <CodeEditor\n key={file.path}\n path={file.path}\n language={inferLanguage(file)}\n value={file.value}\n readOnly={readOnly}\n onChange={(next) => onFileChange?.(file.path, next)}\n onMount={(editor) => setActiveEditor(editor)}\n height=\"100%\"\n />\n ) : null}\n </TabsContent>\n );\n })}\n </Tabs>\n </div>\n );\n },\n);\n","\"use client\";\n\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n useLocale,\n} from \"@elabs-ai/components-ui\";\nimport { cn } from \"@elabs-ai/components-ui/lib/cn\";\nimport { forwardRef, type HTMLAttributes, type ReactNode } from \"react\";\nimport { CopyButton } from \"../copy-button\";\nimport { EDITOR_LANGUAGES, type EditorLanguage } from \"../lib/languages\";\n\nexport interface EditorToolbarProps extends HTMLAttributes<HTMLDivElement> {\n /** Filename shown on the left (e.g. \"index.ts\"). */\n filename?: ReactNode;\n /** Active language id; shows a language picker when `onLanguageChange` is set. */\n language?: string;\n /** Called when the user picks a language. Omit to hide the picker. */\n onLanguageChange?: (language: string) => void;\n /** Languages offered in the picker. Defaults to {@link EDITOR_LANGUAGES}. */\n languages?: EditorLanguage[];\n /** Text copied by the copy button. Omit to hide the button. */\n copyValue?: string;\n /** Extra actions rendered before the copy button (brand-ui buttons, etc.). */\n actions?: ReactNode;\n}\n\n/**\n * Brand-ui chrome for the editors — the part that genuinely reuses our\n * components. Renders a filename label, an optional language `Select` and a copy\n * `Button`. The editing surface itself is Monaco; this is the frame around it.\n */\nexport const EditorToolbar = forwardRef<HTMLDivElement, EditorToolbarProps>(function EditorToolbar(\n {\n filename,\n language,\n onLanguageChange,\n languages = EDITOR_LANGUAGES,\n copyValue,\n actions,\n className,\n ...props\n },\n ref,\n) {\n const { t } = useLocale();\n return (\n <div\n ref={ref}\n className={cn(\n \"flex h-10 shrink-0 items-center gap-2 border-b border-border bg-surface px-3\",\n className,\n )}\n {...props}\n >\n {filename != null ? (\n <span className=\"truncate text-sm font-medium text-foreground\">{filename}</span>\n ) : null}\n\n <div className=\"ml-auto flex items-center gap-1.5\">\n {actions}\n\n {onLanguageChange ? (\n <Select value={language} onValueChange={onLanguageChange}>\n <SelectTrigger\n size=\"sm\"\n className=\"h-7 w-[140px]\"\n aria-label={t(\"editor.editorToolbar.language\")}\n >\n <SelectValue placeholder={t(\"editor.editorToolbar.language\")} />\n </SelectTrigger>\n <SelectContent>\n {languages.map((l) => (\n <SelectItem key={l.id} value={l.id}>\n {l.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n ) : null}\n\n {copyValue != null ? <CopyButton value={copyValue} /> : null}\n </div>\n </div>\n );\n});\n","/**\n * Curated language list for the editor toolbar's language picker. Ids are\n * Monaco's built-in language ids (`monaco.languages.getLanguages()`), so they\n * map straight onto `setModelLanguage` / model creation.\n */\nexport interface EditorLanguage {\n /** Monaco language id (e.g. \"typescript\"). */\n id: string;\n /** Human-readable label for the picker. */\n label: string;\n}\n\nexport const EDITOR_LANGUAGES: EditorLanguage[] = [\n { id: \"typescript\", label: \"TypeScript\" },\n { id: \"javascript\", label: \"JavaScript\" },\n { id: \"json\", label: \"JSON\" },\n { id: \"html\", label: \"HTML\" },\n { id: \"css\", label: \"CSS\" },\n { id: \"scss\", label: \"SCSS\" },\n { id: \"markdown\", label: \"Markdown\" },\n { id: \"python\", label: \"Python\" },\n { id: \"sql\", label: \"SQL\" },\n { id: \"yaml\", label: \"YAML\" },\n { id: \"xml\", label: \"XML\" },\n { id: \"shell\", label: \"Shell\" },\n { id: \"plaintext\", label: \"Plain text\" },\n];\n\n/** Look up a language's label, falling back to the raw id. */\nexport function languageLabel(id: string): string {\n return EDITOR_LANGUAGES.find((l) => l.id === id)?.label ?? id;\n}\n"],"mappings":"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","names":["DiffEditor","cn","forwardRef","useEffect","useImperativeHandle","useRef","useState","jsx","forwardRef","CodeWorkspace","useState","useRef","useEffect","useImperativeHandle","cn","cn","forwardRef","jsx","jsxs","forwardRef","EditorToolbar","cn"]}
|
package/dist/markdown/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { S as SlashCommand, I as IterationEditHandler, c as EditorSelection, E as EditorContentAccess, h as EditorCompletionProvider, M as MonacoCodeEditor, i as CalcEditorHooks, d as EmbedAssetFn, j as EvaluateCalc, k as CalcValue, l as CalcTokenKind } from '../markdown-editor-
|
|
2
|
-
export { B as BRAND_SLASH_COMMANDS, n as BasicBlockId, o as CALC_FENCE_SEED, p as CalcComplete, q as CalcCompletion, r as CalcCompletionContext, s as CalcCompletionKind, t as CalcContext, u as CalcLineResult, v as CalcRule, w as CalcSheet, x as CalcTint, y as CalcToken, z as CalcTokenize, A as CalcValueKind, D as CompletionMatch, F as CompletionReplaceRange, G as EditorCompletionContext, H as EditorCompletionItem, J as InsertableDirective, K as IterationEditContext, L as IterationEditRequest, e as MarkdownEditor, f as MarkdownEditorHandle, g as MarkdownEditorProps, N as SlashInsertContext, O as SlashRange, P as SourceSlashContext, Q as collectCompletions, R as filterSlashCommands, T as groupSlashCommands, U as insertBasicBlock, V as insertBrandDirective, W as insertCalcFence, m as monacoContentAccess, X as resolveCalcInsert, Y as resolveReplaceRange, Z as triggerQueryStart } from '../markdown-editor-
|
|
1
|
+
import { S as SlashCommand, I as IterationEditHandler, c as EditorSelection, E as EditorContentAccess, h as EditorCompletionProvider, M as MonacoCodeEditor, i as CalcEditorHooks, d as EmbedAssetFn, j as EvaluateCalc, k as CalcValue, l as CalcTokenKind } from '../markdown-editor-Dn-0L_MM.js';
|
|
2
|
+
export { B as BRAND_SLASH_COMMANDS, n as BasicBlockId, o as CALC_FENCE_SEED, p as CalcComplete, q as CalcCompletion, r as CalcCompletionContext, s as CalcCompletionKind, t as CalcContext, u as CalcLineResult, v as CalcRule, w as CalcSheet, x as CalcTint, y as CalcToken, z as CalcTokenize, A as CalcValueKind, D as CompletionMatch, F as CompletionReplaceRange, G as EditorCompletionContext, H as EditorCompletionItem, J as InsertableDirective, K as IterationEditContext, L as IterationEditRequest, e as MarkdownEditor, f as MarkdownEditorHandle, g as MarkdownEditorProps, N as SlashInsertContext, O as SlashRange, P as SourceSlashContext, Q as collectCompletions, R as filterSlashCommands, T as groupSlashCommands, U as insertBasicBlock, V as insertBrandDirective, W as insertCalcFence, m as monacoContentAccess, X as resolveCalcInsert, Y as resolveReplaceRange, Z as triggerQueryStart } from '../markdown-editor-Dn-0L_MM.js';
|
|
3
3
|
import { MilkdownPlugin } from '@milkdown/kit/ctx';
|
|
4
4
|
import { EditorView } from '@milkdown/kit/prose/view';
|
|
5
5
|
import * as monaco from 'monaco-editor';
|