@elabs-ai/components-editor 4.0.0 → 4.2.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/README.md +6 -7
- package/dist/{chunk-LBC5VJBD.js → chunk-FO5S3YZM.js} +349 -177
- package/dist/chunk-FO5S3YZM.js.map +1 -0
- package/dist/index.css +4 -2
- package/dist/index.css.map +1 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.js +112 -57
- package/dist/index.js.map +1 -1
- package/dist/markdown/index.css +4 -2
- package/dist/markdown/index.css.map +1 -1
- package/dist/markdown/index.d.ts +2 -2
- package/dist/markdown/index.js +268 -191
- package/dist/markdown/index.js.map +1 -1
- package/dist/{markdown-editor-DfBZibAn.d.ts → markdown-editor-Dn-0L_MM.d.ts} +9 -2
- package/dist/monaco.d.ts +2 -0
- package/dist/monaco.js +9 -0
- package/dist/monaco.js.map +1 -0
- package/package.json +10 -6
- package/src/ai-objects/decision-card.tsx +15 -9
- package/src/ai-objects/entity.tsx +1 -1
- 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 +10 -4
- package/src/calc-block/calc-editor.css +1 -1
- package/src/code-editor/code-editor.stories.tsx +76 -1
- package/src/code-editor/code-editor.test.tsx +141 -14
- package/src/code-editor/code-editor.tsx +167 -36
- package/src/code-workspace/code-workspace.test.tsx +113 -11
- package/src/code-workspace/code-workspace.tsx +73 -20
- package/src/copy-button/copy-button.tsx +6 -3
- package/src/diff-editor/diff-editor.stories.tsx +9 -1
- 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/lib/monaco-deep-imports.d.ts +59 -0
- package/src/lib/monaco-theme-bridge.test.ts +307 -0
- package/src/lib/monaco-theme-bridge.ts +154 -10
- package/src/markdown-academic/citations.tsx +14 -7
- package/src/markdown-academic/footnotes.tsx +2 -2
- package/src/markdown-academic/math.tsx +7 -4
- package/src/markdown-academic/toc.tsx +1 -1
- package/src/markdown-editor/completions/completions-menu.tsx +5 -2
- package/src/markdown-editor/directive-views.tsx +35 -24
- package/src/markdown-editor/markdown-editor.css +26 -3
- package/src/markdown-editor/markdown-editor.focus.test.ts +49 -0
- package/src/markdown-editor/markdown-editor.stories.tsx +128 -7
- package/src/markdown-editor/markdown-editor.tsx +8 -5
- package/src/markdown-editor/milkdown-react/use-get-editor.timer-leak.test.ts +80 -0
- package/src/markdown-editor/milkdown-react/use-get-editor.ts +37 -1
- package/src/markdown-editor/paste-embed.ts +2 -1
- package/src/markdown-editor/slash/slash-menu.stories.tsx +8 -3
- package/src/markdown-editor/slash/slash-menu.test.tsx +27 -0
- package/src/markdown-editor/slash/slash-menu.tsx +18 -3
- package/src/markdown-editor/table-view.tsx +31 -17
- package/src/markdown-iteration/iteration-builder-dialog.stories.tsx +57 -19
- 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.stories.tsx +1 -1
- package/src/markdown-outline/document-outline.tsx +7 -3
- package/src/markdown-preview/markdown-preview-academic.test.tsx +3 -3
- package/src/markdown-preview/markdown-preview-transclusion.test.tsx +1 -1
- package/src/markdown-preview/markdown-preview.stories.tsx +24 -2
- package/src/markdown-preview/markdown-preview.test.tsx +20 -3
- package/src/markdown-toolbar/markdown-toolbar.stories.tsx +3 -0
- package/src/markdown-toolbar/markdown-toolbar.tsx +42 -24
- package/src/markdown-workspace/markdown-workspace.test.tsx +53 -4
- 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 +22 -21
- package/src/monaco.ts +21 -0
- package/src/prose/prose.stories.tsx +3 -0
- package/src/prose/prose.test.ts +54 -0
- package/src/prose/prose.tsx +7 -0
- package/dist/chunk-LBC5VJBD.js.map +0 -1
|
@@ -11,12 +11,12 @@ import {
|
|
|
11
11
|
} from "@elabs-ai/components-ui";
|
|
12
12
|
import "react";
|
|
13
13
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
14
|
-
function EditorContextMenu({ editor
|
|
14
|
+
function EditorContextMenu({ editor, readOnly = false, children }) {
|
|
15
15
|
const selection = () => {
|
|
16
|
-
if (!
|
|
17
|
-
const model =
|
|
18
|
-
const sel =
|
|
19
|
-
return model && sel ? { editor
|
|
16
|
+
if (!editor) return null;
|
|
17
|
+
const model = editor.getModel();
|
|
18
|
+
const sel = editor.getSelection();
|
|
19
|
+
return model && sel ? { editor, model, sel } : null;
|
|
20
20
|
};
|
|
21
21
|
const copy = async () => {
|
|
22
22
|
const ctx2 = selection();
|
|
@@ -51,8 +51,8 @@ function EditorContextMenu({ editor: editor2, readOnly = false, children }) {
|
|
|
51
51
|
ctx2.editor.focus();
|
|
52
52
|
};
|
|
53
53
|
const runAction = (id) => {
|
|
54
|
-
|
|
55
|
-
void
|
|
54
|
+
editor?.focus();
|
|
55
|
+
void editor?.getAction(id)?.run();
|
|
56
56
|
};
|
|
57
57
|
return /* @__PURE__ */ jsxs(ContextMenu, { children: [
|
|
58
58
|
/* @__PURE__ */ jsx(ContextMenuTrigger, { asChild: true, children }),
|
|
@@ -130,6 +130,7 @@ function withAlpha(hex, alpha) {
|
|
|
130
130
|
const base = hex.slice(0, 7);
|
|
131
131
|
return `${base}${byte(Math.round(clamp01(alpha) * 255))}`;
|
|
132
132
|
}
|
|
133
|
+
var LINE_HIGHLIGHT_ALPHA = 0.05;
|
|
133
134
|
function bare(hex) {
|
|
134
135
|
return hex.replace("#", "").slice(0, 6).padEnd(6, "0");
|
|
135
136
|
}
|
|
@@ -146,6 +147,13 @@ function contrast(a, b) {
|
|
|
146
147
|
const lb = luminance(b);
|
|
147
148
|
return (Math.max(la, lb) + 0.05) / (Math.min(la, lb) + 0.05);
|
|
148
149
|
}
|
|
150
|
+
function flattenOver(overlayHexWithAlpha, groundHex) {
|
|
151
|
+
const overlayBase = overlayHexWithAlpha.slice(0, 7);
|
|
152
|
+
const alphaHex = overlayHexWithAlpha.length >= 9 ? overlayHexWithAlpha.slice(7, 9) : "ff";
|
|
153
|
+
const alpha = clamp01((parseInt(alphaHex, 16) || 0) / 255);
|
|
154
|
+
const blend = (i) => Math.round(channel(overlayBase, i) * alpha + channel(groundHex, i) * (1 - alpha));
|
|
155
|
+
return `#${byte(blend(0))}${byte(blend(1))}${byte(blend(2))}`;
|
|
156
|
+
}
|
|
149
157
|
function mixHex(hex, target, t) {
|
|
150
158
|
const lerp = (i) => Math.round(channel(hex, i) + (channel(target, i) - channel(hex, i)) * t);
|
|
151
159
|
return `#${byte(lerp(0))}${byte(lerp(1))}${byte(lerp(2))}`;
|
|
@@ -174,6 +182,8 @@ function buildBrandThemeData(rootEl) {
|
|
|
174
182
|
const border = read("--border", muted);
|
|
175
183
|
const primary = read("--primary", foreground);
|
|
176
184
|
const ring = read("--ring", primary);
|
|
185
|
+
const ringContour = read("--ring-contour", ring);
|
|
186
|
+
const focusBorder = contrast(ringContour, background) > contrast(ring, background) ? ringContour : ring;
|
|
177
187
|
const popover = read("--popover", background);
|
|
178
188
|
const popoverFg = read("--popover-foreground", foreground);
|
|
179
189
|
const input = read("--input", border);
|
|
@@ -183,7 +193,9 @@ function buildBrandThemeData(rootEl) {
|
|
|
183
193
|
const chart4 = read("--chart-4", primary);
|
|
184
194
|
const success = read("--success", chart2);
|
|
185
195
|
const destructive = read("--destructive", "#ff0000");
|
|
186
|
-
const
|
|
196
|
+
const lineHighlight = withAlpha(foreground, LINE_HIGHLIGHT_ALPHA);
|
|
197
|
+
const tokenGround = flattenOver(lineHighlight, background);
|
|
198
|
+
const calcResult = ensureReadable(read("--calc-result", primary), tokenGround, 4.5);
|
|
187
199
|
const colors = {
|
|
188
200
|
"editor.background": background,
|
|
189
201
|
"editor.foreground": foreground,
|
|
@@ -194,7 +206,7 @@ function buildBrandThemeData(rootEl) {
|
|
|
194
206
|
"editor.selectionBackground": withAlpha(primary, 0.28),
|
|
195
207
|
"editor.inactiveSelectionBackground": withAlpha(primary, 0.14),
|
|
196
208
|
"editor.selectionHighlightBackground": withAlpha(primary, 0.14),
|
|
197
|
-
"editor.lineHighlightBackground":
|
|
209
|
+
"editor.lineHighlightBackground": lineHighlight,
|
|
198
210
|
"editor.lineHighlightBorder": "#00000000",
|
|
199
211
|
"editorIndentGuide.background1": withAlpha(border, 0.6),
|
|
200
212
|
"editorIndentGuide.activeBackground1": mutedFg,
|
|
@@ -220,7 +232,7 @@ function buildBrandThemeData(rootEl) {
|
|
|
220
232
|
"input.background": input,
|
|
221
233
|
"input.foreground": foreground,
|
|
222
234
|
"input.border": border,
|
|
223
|
-
focusBorder
|
|
235
|
+
focusBorder,
|
|
224
236
|
"dropdown.background": popover,
|
|
225
237
|
"dropdown.foreground": popoverFg,
|
|
226
238
|
"dropdown.border": border,
|
|
@@ -261,7 +273,8 @@ function buildBrandThemeData(rootEl) {
|
|
|
261
273
|
"diffEditorOverview.removedForeground": withAlpha(destructive, 0.6),
|
|
262
274
|
"diffEditor.border": border
|
|
263
275
|
};
|
|
264
|
-
const
|
|
276
|
+
const AA_MARGIN = 0.15;
|
|
277
|
+
const ink = (hex, ratio = 4.5) => bare(ensureReadable(hex, tokenGround, ratio + AA_MARGIN));
|
|
265
278
|
const rules = [
|
|
266
279
|
{ token: "", foreground: bare(foreground), background: bare(background) },
|
|
267
280
|
{ token: "comment", foreground: ink(mutedFg, 3.2), fontStyle: "italic" },
|
|
@@ -286,19 +299,73 @@ function buildBrandThemeData(rootEl) {
|
|
|
286
299
|
{ token: "string.key", foreground: ink(chart1) },
|
|
287
300
|
{ token: "string.value", foreground: ink(chart2) },
|
|
288
301
|
{ token: "invalid", foreground: ink(destructive) },
|
|
289
|
-
{ token: "namespace", foreground: ink(success) }
|
|
302
|
+
{ token: "namespace", foreground: ink(success) },
|
|
303
|
+
// Monaco's built-in `vs`/`vs-dark` bases (inherited at `inherit: true`,
|
|
304
|
+
// below) ship LANGUAGE-SUFFIXED rules — `string.key.json`,
|
|
305
|
+
// `string.value.json`, `keyword.json`, `string.yaml`, `delimiter.html`, …
|
|
306
|
+
// — and Monaco's token-theme trie resolves the DEEPEST matching scope
|
|
307
|
+
// (`ThemeTrieElement.match`), with rules sorted lexicographically before
|
|
308
|
+
// insertion. A shorter brand scope (e.g. `string.key`, above) can
|
|
309
|
+
// therefore NEVER override a longer base scope: every scope a base theme
|
|
310
|
+
// specialises must be re-declared here, or that language renders in
|
|
311
|
+
// stock VS colours (#90). Keep this list in sync with the base themes —
|
|
312
|
+
// `IGNORED_BASE_SCOPES` + the drift guard in `monaco-theme-bridge.test.ts`
|
|
313
|
+
// fail CI if a future `monaco-editor` upgrade adds a new one.
|
|
314
|
+
{ token: "string.key.json", foreground: ink(chart1) },
|
|
315
|
+
// pairs with `key`
|
|
316
|
+
{ token: "string.value.json", foreground: ink(chart2) },
|
|
317
|
+
// pairs with `string`
|
|
318
|
+
{ token: "keyword.json", foreground: ink(primary) },
|
|
319
|
+
// pairs with `keyword`
|
|
320
|
+
// Closes the class, not just JSON — the same base-specialisation gap
|
|
321
|
+
// reaches YAML/HTML/SQL/XML/CSS/SCSS (#90 evidence #7).
|
|
322
|
+
{ token: "string.html", foreground: ink(chart2) },
|
|
323
|
+
{ token: "string.sql", foreground: ink(chart2) },
|
|
324
|
+
{ token: "string.yaml", foreground: ink(chart2) },
|
|
325
|
+
{ token: "delimiter.html", foreground: ink(mutedFg, 3.2) },
|
|
326
|
+
{ token: "delimiter.xml", foreground: ink(mutedFg, 3.2) },
|
|
327
|
+
{ token: "attribute.value.html", foreground: ink(chart2) },
|
|
328
|
+
{ token: "attribute.value.xml", foreground: ink(chart2) },
|
|
329
|
+
{ token: "attribute.value.number", foreground: ink(chart4) },
|
|
330
|
+
{ token: "attribute.value.unit", foreground: ink(chart4) },
|
|
331
|
+
{ token: "attribute.value.number.css", foreground: ink(chart4) },
|
|
332
|
+
{ token: "attribute.value.unit.css", foreground: ink(chart4) },
|
|
333
|
+
{ token: "attribute.value.hex.css", foreground: ink(chart4) },
|
|
334
|
+
{ token: "number.hex", foreground: ink(chart4) },
|
|
335
|
+
{ token: "keyword.flow", foreground: ink(primary) },
|
|
336
|
+
{ token: "keyword.flow.scss", foreground: ink(primary) },
|
|
337
|
+
{ token: "operator.scss", foreground: ink(primary) },
|
|
338
|
+
{ token: "operator.sql", foreground: ink(primary) },
|
|
339
|
+
{ token: "operator.swift", foreground: ink(primary) },
|
|
340
|
+
{ token: "predefined.sql", foreground: ink(chart3) },
|
|
341
|
+
{ token: "metatag", foreground: ink(chart3) },
|
|
342
|
+
{ token: "metatag.html", foreground: ink(chart3) },
|
|
343
|
+
{ token: "metatag.xml", foreground: ink(chart3) },
|
|
344
|
+
{ token: "metatag.content.html", foreground: ink(chart3) },
|
|
345
|
+
{ token: "meta.scss", foreground: ink(chart1) },
|
|
346
|
+
{ token: "meta.tag", foreground: ink(chart1) },
|
|
347
|
+
// `CodeEditorProps.language` is a plain, unrestricted `string` passed
|
|
348
|
+
// straight to `monaco.editor.setModelLanguage` (`code-editor.tsx`) — NOT
|
|
349
|
+
// limited to `EDITOR_LANGUAGES` — so a consumer really can reach these
|
|
350
|
+
// pug/handlebars scopes (PR #119 review thread 2). See
|
|
351
|
+
// `IGNORED_BASE_SCOPES` below for the one scope that stays un-overridden.
|
|
352
|
+
{ token: "tag.id.pug", foreground: ink(primary) },
|
|
353
|
+
// pairs with `tag`
|
|
354
|
+
{ token: "tag.class.pug", foreground: ink(primary) },
|
|
355
|
+
{ token: "variable.parameter", foreground: bare(foreground) }
|
|
356
|
+
// pairs with `variable`
|
|
290
357
|
];
|
|
291
358
|
return { base: "vs", inherit: true, colors, rules };
|
|
292
359
|
}
|
|
293
360
|
function brandThemeId(theme) {
|
|
294
361
|
return `brand-${theme}`;
|
|
295
362
|
}
|
|
296
|
-
function applyBrandTheme(
|
|
363
|
+
function applyBrandTheme(monaco, theme, rootEl) {
|
|
297
364
|
const id = brandThemeId(theme);
|
|
298
365
|
const data = buildBrandThemeData(rootEl);
|
|
299
366
|
data.base = builtinBase(rootEl);
|
|
300
|
-
|
|
301
|
-
|
|
367
|
+
monaco.editor.defineTheme(id, data);
|
|
368
|
+
monaco.editor.setTheme(id);
|
|
302
369
|
return id;
|
|
303
370
|
}
|
|
304
371
|
|
|
@@ -335,7 +402,6 @@ function useDataTheme(target) {
|
|
|
335
402
|
}
|
|
336
403
|
|
|
337
404
|
// src/code-editor/code-editor.tsx
|
|
338
|
-
import * as monaco from "monaco-editor";
|
|
339
405
|
import { cn } from "@elabs-ai/components-ui/lib/cn";
|
|
340
406
|
import {
|
|
341
407
|
forwardRef,
|
|
@@ -345,6 +411,20 @@ import {
|
|
|
345
411
|
useState as useState2
|
|
346
412
|
} from "react";
|
|
347
413
|
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
414
|
+
function computeMinimalEdit(oldValue, newValue) {
|
|
415
|
+
const maxCommon = Math.min(oldValue.length, newValue.length);
|
|
416
|
+
let start = 0;
|
|
417
|
+
while (start < maxCommon && oldValue.charCodeAt(start) === newValue.charCodeAt(start)) {
|
|
418
|
+
start++;
|
|
419
|
+
}
|
|
420
|
+
let endOld = oldValue.length;
|
|
421
|
+
let endNew = newValue.length;
|
|
422
|
+
while (endOld > start && endNew > start && oldValue.charCodeAt(endOld - 1) === newValue.charCodeAt(endNew - 1)) {
|
|
423
|
+
endOld--;
|
|
424
|
+
endNew--;
|
|
425
|
+
}
|
|
426
|
+
return { start, endOld, text: newValue.slice(start, endNew) };
|
|
427
|
+
}
|
|
348
428
|
var BASE_OPTIONS = {
|
|
349
429
|
automaticLayout: true,
|
|
350
430
|
minimap: { enabled: false },
|
|
@@ -376,70 +456,123 @@ var CodeEditor = forwardRef(function CodeEditor2({
|
|
|
376
456
|
...props
|
|
377
457
|
}, ref) {
|
|
378
458
|
const containerRef = useRef(null);
|
|
379
|
-
const [
|
|
459
|
+
const [editor, setEditor] = useState2(null);
|
|
380
460
|
const { theme, revision } = useDataTheme();
|
|
461
|
+
const modelRef = useRef(null);
|
|
462
|
+
const monacoRef = useRef(null);
|
|
381
463
|
const onChangeRef = useRef(onChange);
|
|
382
464
|
onChangeRef.current = onChange;
|
|
383
465
|
const onMountRef = useRef(onMount);
|
|
384
466
|
onMountRef.current = onMount;
|
|
385
|
-
useImperativeHandle(ref, () =>
|
|
386
|
-
|
|
467
|
+
useImperativeHandle(ref, () => editor, [
|
|
468
|
+
editor
|
|
387
469
|
]);
|
|
388
470
|
useEffect2(() => {
|
|
389
471
|
const container = containerRef.current;
|
|
390
472
|
if (!container) return;
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
)
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
473
|
+
let cancelled = false;
|
|
474
|
+
let instance = null;
|
|
475
|
+
let model = null;
|
|
476
|
+
let sub = null;
|
|
477
|
+
import("monaco-editor").then((monacoApi) => {
|
|
478
|
+
if (cancelled) return;
|
|
479
|
+
monacoRef.current = monacoApi;
|
|
480
|
+
model = monacoApi.editor.createModel(
|
|
481
|
+
value ?? defaultValue ?? "",
|
|
482
|
+
language,
|
|
483
|
+
path ? monacoApi.Uri.parse(`inmemory://brand/${path}`) : void 0
|
|
484
|
+
);
|
|
485
|
+
modelRef.current = model;
|
|
486
|
+
instance = monacoApi.editor.create(container, {
|
|
487
|
+
...BASE_OPTIONS,
|
|
488
|
+
readOnly,
|
|
489
|
+
// Disable Monaco's own menu unless explicitly opted into; "brand" renders
|
|
490
|
+
// brand-ui's ContextMenu around the editor instead.
|
|
491
|
+
contextmenu: contextMenu === "monaco",
|
|
492
|
+
// Monaco's accessible name comes from this construction option (it writes it
|
|
493
|
+
// onto its inner screen-reader <textarea>), not from a wrapper-div attribute.
|
|
494
|
+
...ariaLabel !== void 0 ? { ariaLabel } : null,
|
|
495
|
+
model,
|
|
496
|
+
...options
|
|
497
|
+
});
|
|
498
|
+
sub = instance.onDidChangeModelContent(() => {
|
|
499
|
+
onChangeRef.current?.(instance.getValue());
|
|
500
|
+
});
|
|
501
|
+
const textarea = instance.getDomNode()?.querySelector("textarea");
|
|
502
|
+
if (textarea) {
|
|
503
|
+
if (ariaLabel !== void 0) textarea.setAttribute("aria-label", ariaLabel);
|
|
504
|
+
if (ariaInvalid !== void 0) textarea.setAttribute("aria-invalid", String(ariaInvalid));
|
|
505
|
+
if (ariaDescribedBy !== void 0)
|
|
506
|
+
textarea.setAttribute("aria-describedby", ariaDescribedBy);
|
|
507
|
+
}
|
|
508
|
+
setEditor(instance);
|
|
509
|
+
onMountRef.current?.(instance, monacoApi);
|
|
410
510
|
});
|
|
411
|
-
setEditor(instance);
|
|
412
|
-
onMountRef.current?.(instance, monaco);
|
|
413
511
|
return () => {
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
512
|
+
cancelled = true;
|
|
513
|
+
sub?.dispose();
|
|
514
|
+
instance?.dispose();
|
|
515
|
+
model?.dispose();
|
|
516
|
+
modelRef.current = null;
|
|
517
|
+
monacoRef.current = null;
|
|
417
518
|
setEditor(null);
|
|
418
519
|
};
|
|
419
520
|
}, []);
|
|
420
521
|
useEffect2(() => {
|
|
421
|
-
|
|
422
|
-
if (
|
|
423
|
-
|
|
522
|
+
const monacoApi = monacoRef.current;
|
|
523
|
+
if (!editor || !monacoApi) return;
|
|
524
|
+
const current = modelRef.current;
|
|
525
|
+
const currentUri = current?.uri?.toString();
|
|
526
|
+
const nextUri = path ? monacoApi.Uri.parse(`inmemory://brand/${path}`).toString() : void 0;
|
|
527
|
+
if (currentUri === nextUri) return;
|
|
528
|
+
const nextModel = monacoApi.editor.createModel(
|
|
529
|
+
current?.getValue() ?? value ?? defaultValue ?? "",
|
|
530
|
+
language,
|
|
531
|
+
path ? monacoApi.Uri.parse(`inmemory://brand/${path}`) : void 0
|
|
532
|
+
);
|
|
533
|
+
editor.setModel(nextModel);
|
|
534
|
+
modelRef.current = nextModel;
|
|
535
|
+
current?.dispose();
|
|
536
|
+
}, [editor, path]);
|
|
537
|
+
useEffect2(() => {
|
|
538
|
+
const monacoApi = monacoRef.current;
|
|
539
|
+
if (!editor || !monacoApi || value === void 0) return;
|
|
540
|
+
const model = editor.getModel();
|
|
541
|
+
if (!model) return;
|
|
542
|
+
const current = model.getValue();
|
|
543
|
+
if (value === current) return;
|
|
544
|
+
const { start, endOld, text } = computeMinimalEdit(current, value);
|
|
545
|
+
const range = monacoApi.Range.fromPositions(
|
|
546
|
+
model.getPositionAt(start),
|
|
547
|
+
model.getPositionAt(endOld)
|
|
548
|
+
);
|
|
549
|
+
editor.executeEdits("controlled-value-sync", [{ range, text }]);
|
|
550
|
+
}, [editor, value]);
|
|
424
551
|
useEffect2(() => {
|
|
425
|
-
const
|
|
426
|
-
|
|
427
|
-
|
|
552
|
+
const monacoApi = monacoRef.current;
|
|
553
|
+
const model = editor?.getModel();
|
|
554
|
+
if (model && monacoApi) monacoApi.editor.setModelLanguage(model, language);
|
|
555
|
+
}, [editor, language]);
|
|
428
556
|
useEffect2(() => {
|
|
429
|
-
|
|
430
|
-
}, [
|
|
557
|
+
editor?.updateOptions({ readOnly, contextmenu: contextMenu === "monaco" });
|
|
558
|
+
}, [editor, readOnly, contextMenu]);
|
|
431
559
|
useEffect2(() => {
|
|
432
|
-
if (!
|
|
560
|
+
if (!editor || !options) return;
|
|
561
|
+
editor.updateOptions(options);
|
|
562
|
+
}, [editor, options]);
|
|
563
|
+
useEffect2(() => {
|
|
564
|
+
const monacoApi = monacoRef.current;
|
|
565
|
+
if (!editor || !monacoApi) return;
|
|
433
566
|
try {
|
|
434
|
-
applyBrandTheme(
|
|
567
|
+
applyBrandTheme(monacoApi, theme);
|
|
435
568
|
} catch (err) {
|
|
436
569
|
console.error("[@elabs-ai/components-editor] failed to apply brand theme", err);
|
|
437
570
|
}
|
|
438
|
-
}, [
|
|
571
|
+
}, [editor, theme, revision]);
|
|
439
572
|
useEffect2(() => {
|
|
440
|
-
if (!
|
|
441
|
-
if (ariaLabel !== void 0)
|
|
442
|
-
const textarea =
|
|
573
|
+
if (!editor) return;
|
|
574
|
+
if (ariaLabel !== void 0) editor.updateOptions({ ariaLabel });
|
|
575
|
+
const textarea = editor.getDomNode()?.querySelector("textarea");
|
|
443
576
|
if (!textarea) return;
|
|
444
577
|
if (ariaLabel === void 0) textarea.removeAttribute("aria-label");
|
|
445
578
|
else textarea.setAttribute("aria-label", ariaLabel);
|
|
@@ -447,12 +580,12 @@ var CodeEditor = forwardRef(function CodeEditor2({
|
|
|
447
580
|
else textarea.setAttribute("aria-invalid", String(ariaInvalid));
|
|
448
581
|
if (ariaDescribedBy === void 0) textarea.removeAttribute("aria-describedby");
|
|
449
582
|
else textarea.setAttribute("aria-describedby", ariaDescribedBy);
|
|
450
|
-
}, [
|
|
583
|
+
}, [editor, ariaLabel, ariaInvalid, ariaDescribedBy]);
|
|
451
584
|
useEffect2(() => {
|
|
452
|
-
if (!
|
|
453
|
-
const disposables = actions.map((a) =>
|
|
585
|
+
if (!editor || !actions || actions.length === 0) return;
|
|
586
|
+
const disposables = actions.map((a) => editor.addAction(a));
|
|
454
587
|
return () => disposables.forEach((d) => d.dispose());
|
|
455
|
-
}, [
|
|
588
|
+
}, [editor, actions]);
|
|
456
589
|
const resolvedStyle = {
|
|
457
590
|
height: typeof height === "number" ? `${height}px` : height,
|
|
458
591
|
...style
|
|
@@ -468,7 +601,7 @@ var CodeEditor = forwardRef(function CodeEditor2({
|
|
|
468
601
|
}
|
|
469
602
|
);
|
|
470
603
|
if (contextMenu === "brand") {
|
|
471
|
-
return /* @__PURE__ */ jsx2(EditorContextMenu, { editor
|
|
604
|
+
return /* @__PURE__ */ jsx2(EditorContextMenu, { editor, readOnly, children: editorEl });
|
|
472
605
|
}
|
|
473
606
|
return editorEl;
|
|
474
607
|
});
|
|
@@ -883,6 +1016,7 @@ function parseMarkdownOutline(markdown) {
|
|
|
883
1016
|
}
|
|
884
1017
|
|
|
885
1018
|
// src/markdown-outline/document-outline.tsx
|
|
1019
|
+
import { useLocale } from "@elabs-ai/components-ui";
|
|
886
1020
|
import { cn as cn2 } from "@elabs-ai/components-ui/lib/cn";
|
|
887
1021
|
import { forwardRef as forwardRef2, useMemo } from "react";
|
|
888
1022
|
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
@@ -891,12 +1025,13 @@ function useMarkdownOutline(markdown) {
|
|
|
891
1025
|
}
|
|
892
1026
|
var DocumentOutline = forwardRef2(
|
|
893
1027
|
function DocumentOutline2({ items, activeId, onSelect, itemActions, className, ...props }, ref) {
|
|
1028
|
+
const { t } = useLocale();
|
|
894
1029
|
const minLevel = items.reduce((min, it) => Math.min(min, it.level), 6);
|
|
895
1030
|
return /* @__PURE__ */ jsxs2(
|
|
896
1031
|
"nav",
|
|
897
1032
|
{
|
|
898
1033
|
ref,
|
|
899
|
-
"aria-label": "
|
|
1034
|
+
"aria-label": t("editor.documentOutline.label"),
|
|
900
1035
|
className: cn2("text-body", className),
|
|
901
1036
|
...props,
|
|
902
1037
|
children: [
|
|
@@ -912,7 +1047,7 @@ var DocumentOutline = forwardRef2(
|
|
|
912
1047
|
className: cn2(
|
|
913
1048
|
"-ms-px block w-full truncate border-s-2 py-1 pe-2 text-start text-caption",
|
|
914
1049
|
"transition-colors duration-fast ease-standard motion-reduce:transition-none",
|
|
915
|
-
"focus-
|
|
1050
|
+
"focus-ring-inset",
|
|
916
1051
|
item.id === activeId ? "border-s-primary font-medium text-foreground" : "border-s-transparent text-muted-foreground hover:border-s-border-strong hover:text-foreground",
|
|
917
1052
|
actions && "pe-8"
|
|
918
1053
|
),
|
|
@@ -923,7 +1058,7 @@ var DocumentOutline = forwardRef2(
|
|
|
923
1058
|
actions ? /* @__PURE__ */ jsx3("span", { className: "absolute end-0.5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity duration-fast ease-standard focus-within:opacity-100 group-hover/outline-item:opacity-100 has-[[aria-pressed=true]]:opacity-100 motion-reduce:transition-none", children: actions }) : null
|
|
924
1059
|
] }, item.id);
|
|
925
1060
|
}) }),
|
|
926
|
-
items.length === 0 ? /* @__PURE__ */ jsx3("p", { className: "px-2 py-1 text-caption text-muted-foreground", children: "
|
|
1061
|
+
items.length === 0 ? /* @__PURE__ */ jsx3("p", { className: "px-2 py-1 text-caption text-muted-foreground", children: t("editor.documentOutline.empty") }) : null
|
|
927
1062
|
]
|
|
928
1063
|
}
|
|
929
1064
|
);
|
|
@@ -1698,6 +1833,7 @@ function groupSlashCommands(commands) {
|
|
|
1698
1833
|
}
|
|
1699
1834
|
|
|
1700
1835
|
// src/markdown-editor/slash/slash-menu.tsx
|
|
1836
|
+
import { useLocale as useLocale2 } from "@elabs-ai/components-ui";
|
|
1701
1837
|
import { cn as cn4 } from "@elabs-ai/components-ui/lib/cn";
|
|
1702
1838
|
import { forwardRef as forwardRef4 } from "react";
|
|
1703
1839
|
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
@@ -1709,23 +1845,41 @@ var SlashMenu = forwardRef4(function SlashMenu2({
|
|
|
1709
1845
|
activeId,
|
|
1710
1846
|
onSelect,
|
|
1711
1847
|
idPrefix = "brand-slash",
|
|
1712
|
-
emptyLabel
|
|
1848
|
+
emptyLabel: emptyLabelProp,
|
|
1713
1849
|
className,
|
|
1714
1850
|
...props
|
|
1715
1851
|
}, ref) {
|
|
1852
|
+
const { t } = useLocale2();
|
|
1853
|
+
const emptyLabel = emptyLabelProp ?? t("editor.slashMenu.noMatchingBlocks");
|
|
1716
1854
|
const groups = groupSlashCommands(commands);
|
|
1717
1855
|
return /* @__PURE__ */ jsx5(
|
|
1718
1856
|
"div",
|
|
1719
1857
|
{
|
|
1720
1858
|
ref,
|
|
1721
1859
|
role: "listbox",
|
|
1722
|
-
"aria-label": "
|
|
1860
|
+
"aria-label": t("editor.slashMenu.insertBlock"),
|
|
1723
1861
|
className: cn4(
|
|
1724
1862
|
"max-h-[min(320px,60vh)] w-72 overflow-y-auto overflow-x-hidden rounded-md bg-popover p-1 text-popover-foreground shadow-ring-md",
|
|
1725
1863
|
className
|
|
1726
1864
|
),
|
|
1727
1865
|
...props,
|
|
1728
|
-
children: commands.length === 0 ?
|
|
1866
|
+
children: commands.length === 0 ? (
|
|
1867
|
+
// A `role="listbox"` may only own `option`/`group` children (WCAG 1.3.1,
|
|
1868
|
+
// #157): a bare `<div>` here is an unannounced, dangling message — an
|
|
1869
|
+
// AT user who types a query matching nothing gets silence. Shaping it
|
|
1870
|
+
// as a disabled, unselectable option keeps the listbox contract AND
|
|
1871
|
+
// makes the message reachable by an accessible-name query.
|
|
1872
|
+
/* @__PURE__ */ jsx5(
|
|
1873
|
+
"div",
|
|
1874
|
+
{
|
|
1875
|
+
role: "option",
|
|
1876
|
+
"aria-disabled": "true",
|
|
1877
|
+
"aria-selected": "false",
|
|
1878
|
+
className: "cursor-default select-none px-2 py-6 text-center text-caption text-muted-foreground",
|
|
1879
|
+
children: emptyLabel
|
|
1880
|
+
}
|
|
1881
|
+
)
|
|
1882
|
+
) : groups.map(({ group, commands: groupCommands }) => /* @__PURE__ */ jsxs4("div", { role: "group", "aria-label": group, className: "overflow-hidden p-1", children: [
|
|
1729
1883
|
/* @__PURE__ */ jsx5("div", { className: "px-2 py-1.5 text-meta font-medium text-muted-foreground", children: group }),
|
|
1730
1884
|
groupCommands.map((command) => {
|
|
1731
1885
|
const selected = command.id === activeId;
|
|
@@ -2252,6 +2406,7 @@ import { useWidgetViewContext as useWidgetViewContext2 } from "@prosemirror-adap
|
|
|
2252
2406
|
import { useLayoutEffect as useLayoutEffect2, useRef as useRef3 } from "react";
|
|
2253
2407
|
|
|
2254
2408
|
// src/markdown-editor/completions/completions-menu.tsx
|
|
2409
|
+
import { useLocale as useLocale3 } from "@elabs-ai/components-ui";
|
|
2255
2410
|
import { cn as cn5 } from "@elabs-ai/components-ui/lib/cn";
|
|
2256
2411
|
import { forwardRef as forwardRef5 } from "react";
|
|
2257
2412
|
import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
@@ -2264,16 +2419,18 @@ var CompletionMenu = forwardRef5(
|
|
|
2264
2419
|
activeIndex,
|
|
2265
2420
|
onSelect,
|
|
2266
2421
|
idPrefix = "brand-completions",
|
|
2267
|
-
emptyLabel
|
|
2422
|
+
emptyLabel: emptyLabelProp,
|
|
2268
2423
|
className,
|
|
2269
2424
|
...props
|
|
2270
2425
|
}, ref) {
|
|
2426
|
+
const { t } = useLocale3();
|
|
2427
|
+
const emptyLabel = emptyLabelProp ?? t("editor.completions.noSuggestions");
|
|
2271
2428
|
return /* @__PURE__ */ jsx7(
|
|
2272
2429
|
"div",
|
|
2273
2430
|
{
|
|
2274
2431
|
ref,
|
|
2275
2432
|
role: "listbox",
|
|
2276
|
-
"aria-label": "
|
|
2433
|
+
"aria-label": t("editor.completions.suggestions"),
|
|
2277
2434
|
className: cn5(
|
|
2278
2435
|
"max-h-[min(280px,50vh)] w-64 overflow-y-auto overflow-x-hidden rounded-md bg-popover p-1 text-popover-foreground shadow-ring-md",
|
|
2279
2436
|
className
|
|
@@ -2391,7 +2548,8 @@ import {
|
|
|
2391
2548
|
DropdownMenuSub,
|
|
2392
2549
|
DropdownMenuSubContent,
|
|
2393
2550
|
DropdownMenuSubTrigger,
|
|
2394
|
-
DropdownMenuTrigger
|
|
2551
|
+
DropdownMenuTrigger,
|
|
2552
|
+
useLocale as useLocale4
|
|
2395
2553
|
} from "@elabs-ai/components-ui";
|
|
2396
2554
|
import { cn as cn6 } from "@elabs-ai/components-ui/lib/cn";
|
|
2397
2555
|
import { editorViewCtx as editorViewCtx2, parserCtx as parserCtx2, serializerCtx } from "@milkdown/kit/core";
|
|
@@ -2414,6 +2572,7 @@ import { useMemo as useMemo2, useRef as useRef5, useState as useState3 } from "r
|
|
|
2414
2572
|
// src/markdown-editor/milkdown-react/use-get-editor.ts
|
|
2415
2573
|
import { createContext as createContext2, useContext, useEffect as useEffect3, useRef as useRef4 } from "react";
|
|
2416
2574
|
var editorInfoContext = createContext2({});
|
|
2575
|
+
var pendingDestroys = /* @__PURE__ */ new Set();
|
|
2417
2576
|
function useGetEditor() {
|
|
2418
2577
|
const {
|
|
2419
2578
|
dom,
|
|
@@ -2427,16 +2586,20 @@ function useGetEditor() {
|
|
|
2427
2586
|
if (!getEditor) return;
|
|
2428
2587
|
if (!div) return;
|
|
2429
2588
|
dom.current = div;
|
|
2430
|
-
const
|
|
2431
|
-
if (!
|
|
2589
|
+
const editor = getEditor(div);
|
|
2590
|
+
if (!editor) return;
|
|
2432
2591
|
setLoading(true);
|
|
2433
|
-
|
|
2434
|
-
editorRef.current =
|
|
2592
|
+
editor.create().then((editor2) => {
|
|
2593
|
+
editorRef.current = editor2;
|
|
2435
2594
|
}).finally(() => {
|
|
2436
2595
|
setLoading(false);
|
|
2437
2596
|
}).catch(console.error);
|
|
2438
2597
|
return () => {
|
|
2439
|
-
|
|
2598
|
+
const destroyPromise = editor.destroy().catch(console.error);
|
|
2599
|
+
pendingDestroys.add(destroyPromise);
|
|
2600
|
+
void destroyPromise.finally(() => {
|
|
2601
|
+
pendingDestroys.delete(destroyPromise);
|
|
2602
|
+
});
|
|
2440
2603
|
};
|
|
2441
2604
|
}, [dom, editorRef, getEditor, setLoading]);
|
|
2442
2605
|
return domRef;
|
|
@@ -2451,10 +2614,10 @@ var Milkdown = () => {
|
|
|
2451
2614
|
var MilkdownProvider = ({ children }) => {
|
|
2452
2615
|
const dom = useRef5(void 0);
|
|
2453
2616
|
const [editorFactory, setEditorFactory] = useState3(void 0);
|
|
2454
|
-
const
|
|
2617
|
+
const editor = useRef5(void 0);
|
|
2455
2618
|
const [loading, setLoading] = useState3(true);
|
|
2456
2619
|
const editorInfoCtx = useMemo2(
|
|
2457
|
-
() => ({ loading, dom, editor
|
|
2620
|
+
() => ({ loading, dom, editor, setLoading, editorFactory, setEditorFactory }),
|
|
2458
2621
|
[loading, editorFactory]
|
|
2459
2622
|
);
|
|
2460
2623
|
return /* @__PURE__ */ jsx9(editorInfoContext.Provider, { value: editorInfoCtx, children });
|
|
@@ -2549,14 +2712,12 @@ function InlineEdit({ value, onCommit, ariaLabel, placeholder, className }) {
|
|
|
2549
2712
|
spellCheck: false,
|
|
2550
2713
|
onBlur: commit,
|
|
2551
2714
|
onKeyDown,
|
|
2552
|
-
className: cn6(
|
|
2553
|
-
"brand-inline-edit rounded-sm outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
2554
|
-
className
|
|
2555
|
-
)
|
|
2715
|
+
className: cn6("brand-inline-edit rounded-sm focus-ring", className)
|
|
2556
2716
|
}
|
|
2557
2717
|
);
|
|
2558
2718
|
}
|
|
2559
2719
|
function ContainerDirectiveView() {
|
|
2720
|
+
const { t } = useLocale4();
|
|
2560
2721
|
const { contentRef } = useNodeViewContext();
|
|
2561
2722
|
const { name, attributes, update } = useDirectiveAttrs();
|
|
2562
2723
|
const body = /* @__PURE__ */ jsx10("div", { className: "brand-directive__body", ref: contentRef });
|
|
@@ -2565,8 +2726,8 @@ function ContainerDirectiveView() {
|
|
|
2565
2726
|
/* @__PURE__ */ jsx10(CardHeader, { className: "pb-3", children: /* @__PURE__ */ jsx10(CardTitle, { children: /* @__PURE__ */ jsx10(
|
|
2566
2727
|
InlineEdit,
|
|
2567
2728
|
{
|
|
2568
|
-
ariaLabel: "
|
|
2569
|
-
placeholder: "
|
|
2729
|
+
ariaLabel: t("editor.directiveViews.cardTitle"),
|
|
2730
|
+
placeholder: t("editor.directiveViews.cardTitle"),
|
|
2570
2731
|
value: attributes.title ?? "",
|
|
2571
2732
|
onCommit: (v) => update("title", v)
|
|
2572
2733
|
}
|
|
@@ -2586,7 +2747,7 @@ function ContainerDirectiveView() {
|
|
|
2586
2747
|
/* @__PURE__ */ jsx10("div", { className: "mb-1 font-medium leading-none tracking-tight", children: /* @__PURE__ */ jsx10(
|
|
2587
2748
|
InlineEdit,
|
|
2588
2749
|
{
|
|
2589
|
-
ariaLabel: "
|
|
2750
|
+
ariaLabel: t("editor.directiveViews.calloutTitle"),
|
|
2590
2751
|
placeholder: capitalize(attributes.type ?? "note"),
|
|
2591
2752
|
value: attributes.title ?? "",
|
|
2592
2753
|
onCommit: (v) => update("title", v)
|
|
@@ -2611,10 +2772,7 @@ function ContainerDirectiveView() {
|
|
|
2611
2772
|
className: "brand-directive brand-directive--unknown",
|
|
2612
2773
|
"data-brand-directive": name,
|
|
2613
2774
|
children: [
|
|
2614
|
-
/* @__PURE__ */
|
|
2615
|
-
"Unknown block: ",
|
|
2616
|
-
name
|
|
2617
|
-
] }),
|
|
2775
|
+
/* @__PURE__ */ jsx10("div", { className: "mb-1 font-medium leading-none tracking-tight", children: t("editor.directiveViews.unknownBlock", { name }) }),
|
|
2618
2776
|
/* @__PURE__ */ jsx10(AlertDescription, { children: body })
|
|
2619
2777
|
]
|
|
2620
2778
|
}
|
|
@@ -2622,9 +2780,9 @@ function ContainerDirectiveView() {
|
|
|
2622
2780
|
}
|
|
2623
2781
|
function readBodyMarkdown(getInstance, node) {
|
|
2624
2782
|
try {
|
|
2625
|
-
const
|
|
2626
|
-
if (!
|
|
2627
|
-
return
|
|
2783
|
+
const editor = getInstance();
|
|
2784
|
+
if (!editor) return node.textContent;
|
|
2785
|
+
return editor.action((ctx2) => {
|
|
2628
2786
|
const serialize = ctx2.get(
|
|
2629
2787
|
serializerCtx
|
|
2630
2788
|
);
|
|
@@ -2637,10 +2795,10 @@ function readBodyMarkdown(getInstance, node) {
|
|
|
2637
2795
|
}
|
|
2638
2796
|
function writeBodyMarkdown(getInstance, getPos, template) {
|
|
2639
2797
|
try {
|
|
2640
|
-
const
|
|
2798
|
+
const editor = getInstance();
|
|
2641
2799
|
const pos = getPos();
|
|
2642
|
-
if (!
|
|
2643
|
-
|
|
2800
|
+
if (!editor || pos == null) return;
|
|
2801
|
+
editor.action((ctx2) => {
|
|
2644
2802
|
const parse = ctx2.get(
|
|
2645
2803
|
parserCtx2
|
|
2646
2804
|
);
|
|
@@ -2668,10 +2826,10 @@ function mergeAttrsOmittingEmpty(attrs, next) {
|
|
|
2668
2826
|
function replaceNodeWithMarkdown(getInstance, getPos, markdown) {
|
|
2669
2827
|
if (!markdown.trim()) return;
|
|
2670
2828
|
try {
|
|
2671
|
-
const
|
|
2829
|
+
const editor = getInstance();
|
|
2672
2830
|
const pos = getPos();
|
|
2673
|
-
if (!
|
|
2674
|
-
|
|
2831
|
+
if (!editor || pos == null) return;
|
|
2832
|
+
editor.action((ctx2) => {
|
|
2675
2833
|
const parse = ctx2.get(
|
|
2676
2834
|
parserCtx2
|
|
2677
2835
|
);
|
|
@@ -2721,6 +2879,7 @@ function IterationMenuItems({
|
|
|
2721
2879
|
}) });
|
|
2722
2880
|
}
|
|
2723
2881
|
function IterationDirectiveView() {
|
|
2882
|
+
const { t } = useLocale4();
|
|
2724
2883
|
const { contentRef, node, getPos, setAttrs } = useNodeViewContext();
|
|
2725
2884
|
const { name, attributes } = useDirectiveAttrs();
|
|
2726
2885
|
const [, getInstance] = useInstance();
|
|
@@ -2775,7 +2934,7 @@ function IterationDirectiveView() {
|
|
|
2775
2934
|
as: attributes.as || "item",
|
|
2776
2935
|
attributes
|
|
2777
2936
|
}).cells.length > 0;
|
|
2778
|
-
const disabledHint = "
|
|
2937
|
+
const disabledHint = t("editor.directiveViews.needsEmbeddedValues");
|
|
2779
2938
|
const convertToStatic = () => {
|
|
2780
2939
|
const template = readBodyMarkdown(getInstance, node);
|
|
2781
2940
|
const value = builderValueFromParts(kind, attributes, template);
|
|
@@ -2785,14 +2944,14 @@ function IterationDirectiveView() {
|
|
|
2785
2944
|
{
|
|
2786
2945
|
type: "item",
|
|
2787
2946
|
id: "edit",
|
|
2788
|
-
label: "
|
|
2947
|
+
label: t("editor.directiveViews.editIteration"),
|
|
2789
2948
|
icon: /* @__PURE__ */ jsx10(Pencil, { className: "size-4", "aria-hidden": "true" }),
|
|
2790
2949
|
onSelect: requestEdit
|
|
2791
2950
|
},
|
|
2792
2951
|
{
|
|
2793
2952
|
type: "layout",
|
|
2794
2953
|
id: "layout",
|
|
2795
|
-
label: "
|
|
2954
|
+
label: t("editor.directiveViews.changeLayout"),
|
|
2796
2955
|
icon: /* @__PURE__ */ jsx10(LayoutGrid, { className: "size-4", "aria-hidden": "true" }),
|
|
2797
2956
|
value: attributes.layout || ITERATION_LAYOUTS[kind][0],
|
|
2798
2957
|
options: ITERATION_LAYOUTS[kind],
|
|
@@ -2802,7 +2961,7 @@ function IterationDirectiveView() {
|
|
|
2802
2961
|
{
|
|
2803
2962
|
type: "item",
|
|
2804
2963
|
id: "transpose",
|
|
2805
|
-
label: hasEmbeddedData ? "
|
|
2964
|
+
label: hasEmbeddedData ? t("editor.directiveViews.transpose") : `${t("editor.directiveViews.transpose")} ${disabledHint}`,
|
|
2806
2965
|
icon: /* @__PURE__ */ jsx10(ArrowLeftRight, { className: "size-4", "aria-hidden": "true" }),
|
|
2807
2966
|
onSelect: transpose,
|
|
2808
2967
|
disabled: !hasEmbeddedData
|
|
@@ -2811,7 +2970,7 @@ function IterationDirectiveView() {
|
|
|
2811
2970
|
{
|
|
2812
2971
|
type: "item",
|
|
2813
2972
|
id: "convert-to-static",
|
|
2814
|
-
label: hasEmbeddedData ? "
|
|
2973
|
+
label: hasEmbeddedData ? t("editor.directiveViews.convertToStatic") : `${t("editor.directiveViews.convertToStatic")} ${disabledHint}`,
|
|
2815
2974
|
icon: /* @__PURE__ */ jsx10(FileText, { className: "size-4", "aria-hidden": "true" }),
|
|
2816
2975
|
onSelect: convertToStatic,
|
|
2817
2976
|
disabled: !hasEmbeddedData
|
|
@@ -2819,21 +2978,18 @@ function IterationDirectiveView() {
|
|
|
2819
2978
|
];
|
|
2820
2979
|
const header = /* @__PURE__ */ jsxs6("div", { className: "mb-1.5 flex items-center gap-1.5 text-meta font-medium text-info-text", children: [
|
|
2821
2980
|
/* @__PURE__ */ jsx10(Icon, { className: "size-3.5 shrink-0", "aria-hidden": "true" }),
|
|
2822
|
-
/* @__PURE__ */ jsx10("span", { children: isPivot ? "
|
|
2823
|
-
!isPivot && attributes.as ? /* @__PURE__ */
|
|
2824
|
-
|
|
2825
|
-
attributes.as
|
|
2826
|
-
] }) : null,
|
|
2827
|
-
/* @__PURE__ */ jsx10("span", { className: "font-normal text-muted-foreground", children: "\u2014 template" }),
|
|
2981
|
+
/* @__PURE__ */ jsx10("span", { children: isPivot ? t("editor.directiveViews.pivot") : t("editor.directiveViews.iterate") }),
|
|
2982
|
+
!isPivot && attributes.as ? /* @__PURE__ */ jsx10("span", { className: "font-normal text-muted-foreground", children: t("editor.directiveViews.perItem", { as: attributes.as }) }) : null,
|
|
2983
|
+
/* @__PURE__ */ jsx10("span", { className: "font-normal text-muted-foreground", children: t("editor.directiveViews.templateSuffix") }),
|
|
2828
2984
|
onEdit ? /* @__PURE__ */ jsxs6(DropdownMenu, { children: [
|
|
2829
2985
|
/* @__PURE__ */ jsx10(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx10(
|
|
2830
2986
|
"button",
|
|
2831
2987
|
{
|
|
2832
2988
|
type: "button",
|
|
2833
2989
|
"data-directive-chrome": "",
|
|
2834
|
-
"aria-label": "
|
|
2835
|
-
title: "
|
|
2836
|
-
className: "ms-auto inline-flex size-5 items-center justify-center rounded-sm text-muted-foreground hover:bg-accent hover:text-foreground focus-
|
|
2990
|
+
"aria-label": t("editor.directiveViews.iterationActions"),
|
|
2991
|
+
title: t("editor.directiveViews.iterationActionsTitle"),
|
|
2992
|
+
className: "ms-auto inline-flex size-5 items-center justify-center rounded-sm text-muted-foreground hover:bg-accent hover:text-foreground focus-ring",
|
|
2837
2993
|
children: /* @__PURE__ */ jsx10(MoreHorizontal, { className: "size-4", "aria-hidden": "true" })
|
|
2838
2994
|
}
|
|
2839
2995
|
) }),
|
|
@@ -2873,6 +3029,7 @@ function IterationDirectiveView() {
|
|
|
2873
3029
|
] });
|
|
2874
3030
|
}
|
|
2875
3031
|
function LeafDirectiveView() {
|
|
3032
|
+
const { t } = useLocale4();
|
|
2876
3033
|
const { name, attributes, update } = useDirectiveAttrs();
|
|
2877
3034
|
if (name !== "metric") {
|
|
2878
3035
|
return /* @__PURE__ */ jsxs6(
|
|
@@ -2881,7 +3038,8 @@ function LeafDirectiveView() {
|
|
|
2881
3038
|
className: "brand-directive brand-directive--leaf brand-directive--unknown rounded-md border border-destructive/40 bg-surface-muted p-3 text-sm text-muted-foreground",
|
|
2882
3039
|
"data-brand-leaf": name,
|
|
2883
3040
|
children: [
|
|
2884
|
-
"
|
|
3041
|
+
t("editor.directiveViews.unknownInlineBlock"),
|
|
3042
|
+
" ",
|
|
2885
3043
|
/* @__PURE__ */ jsxs6("code", { children: [
|
|
2886
3044
|
"::",
|
|
2887
3045
|
name
|
|
@@ -2899,8 +3057,8 @@ function LeafDirectiveView() {
|
|
|
2899
3057
|
label: /* @__PURE__ */ jsx10(
|
|
2900
3058
|
InlineEdit,
|
|
2901
3059
|
{
|
|
2902
|
-
ariaLabel: "
|
|
2903
|
-
placeholder: "
|
|
3060
|
+
ariaLabel: t("editor.directiveViews.metricLabel"),
|
|
3061
|
+
placeholder: t("editor.directiveViews.metricLabelPlaceholder"),
|
|
2904
3062
|
value: attributes.label ?? "",
|
|
2905
3063
|
onCommit: (v) => update("label", v)
|
|
2906
3064
|
}
|
|
@@ -2908,8 +3066,8 @@ function LeafDirectiveView() {
|
|
|
2908
3066
|
value: /* @__PURE__ */ jsx10(
|
|
2909
3067
|
InlineEdit,
|
|
2910
3068
|
{
|
|
2911
|
-
ariaLabel: "
|
|
2912
|
-
placeholder: "
|
|
3069
|
+
ariaLabel: t("editor.directiveViews.metricValue"),
|
|
3070
|
+
placeholder: t("editor.directiveViews.metricValuePlaceholder"),
|
|
2913
3071
|
value: attributes.value ?? "",
|
|
2914
3072
|
onCommit: (v) => update("value", v),
|
|
2915
3073
|
className: "min-w-[1ch]"
|
|
@@ -3045,7 +3203,7 @@ function makeErrorChip(message) {
|
|
|
3045
3203
|
chip.setAttribute("role", "alert");
|
|
3046
3204
|
chip.setAttribute("aria-live", "assertive");
|
|
3047
3205
|
chip.setAttribute("title", message);
|
|
3048
|
-
chip.className = "inline-flex items-center gap-1 rounded px-2 py-0.5 text-caption bg-destructive/10 text-destructive border border-destructive/30 select-none";
|
|
3206
|
+
chip.className = "inline-flex items-center gap-1 rounded px-2 py-0.5 text-caption bg-destructive/10 text-destructive-text border border-destructive/30 select-none";
|
|
3049
3207
|
const label = document.createElement("span");
|
|
3050
3208
|
label.textContent = `\u26A0 Upload failed`;
|
|
3051
3209
|
chip.appendChild(label);
|
|
@@ -3228,6 +3386,7 @@ import {
|
|
|
3228
3386
|
import { Plugin as Plugin7, PluginKey as PluginKey6 } from "@milkdown/kit/prose/state";
|
|
3229
3387
|
import { $prose as $prose7 } from "@milkdown/kit/utils";
|
|
3230
3388
|
import { isInTable } from "@milkdown/kit/prose/tables";
|
|
3389
|
+
import { useLocale as useLocale5 } from "@elabs-ai/components-ui";
|
|
3231
3390
|
import { cn as cn7 } from "@elabs-ai/components-ui/lib/cn";
|
|
3232
3391
|
import { usePluginViewContext } from "@prosemirror-adapter/react";
|
|
3233
3392
|
import { jsx as jsx11, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
@@ -3259,9 +3418,10 @@ function ToolbarButton({
|
|
|
3259
3418
|
className: cn7(
|
|
3260
3419
|
"inline-flex h-7 items-center gap-1 rounded px-2 text-caption font-medium",
|
|
3261
3420
|
"border border-border-strong",
|
|
3262
|
-
"focus-
|
|
3421
|
+
"focus-ring",
|
|
3263
3422
|
"transition-colors duration-fast ease-standard motion-reduce:transition-none",
|
|
3264
|
-
|
|
3423
|
+
// #124: the button's LABEL text, not a mark — ink rung.
|
|
3424
|
+
variant === "destructive" ? "bg-background text-destructive-text hover:bg-destructive/10" : "bg-background text-foreground hover:bg-surface-muted"
|
|
3265
3425
|
),
|
|
3266
3426
|
children
|
|
3267
3427
|
}
|
|
@@ -3272,25 +3432,32 @@ function ToolbarDivider() {
|
|
|
3272
3432
|
}
|
|
3273
3433
|
function TableControlsView() {
|
|
3274
3434
|
const { view } = usePluginViewContext();
|
|
3435
|
+
const { t } = useLocale5();
|
|
3275
3436
|
const inTable = isInTable(view.state);
|
|
3276
3437
|
const run = (key) => () => dispatchCommand(view, key);
|
|
3277
3438
|
if (!inTable) return null;
|
|
3439
|
+
const addRowAbove = t("editor.tableView.addRowAbove");
|
|
3440
|
+
const addRowBelow = t("editor.tableView.addRowBelow");
|
|
3441
|
+
const deleteRow = t("editor.tableView.deleteRow");
|
|
3442
|
+
const addColLeft = t("editor.tableView.addColumnLeft");
|
|
3443
|
+
const addColRight = t("editor.tableView.addColumnRight");
|
|
3444
|
+
const deleteCol = t("editor.tableView.deleteColumn");
|
|
3278
3445
|
return /* @__PURE__ */ jsxs7(
|
|
3279
3446
|
"div",
|
|
3280
3447
|
{
|
|
3281
3448
|
role: "toolbar",
|
|
3282
|
-
"aria-label": "
|
|
3449
|
+
"aria-label": t("editor.tableView.tableControls"),
|
|
3283
3450
|
className: cn7(
|
|
3284
3451
|
"flex flex-wrap items-center gap-1 px-2 py-1.5",
|
|
3285
3452
|
"border-t border-border-strong bg-surface-muted"
|
|
3286
3453
|
),
|
|
3287
3454
|
children: [
|
|
3288
|
-
/* @__PURE__ */ jsx11("span", { className: "mr-1 select-none text-caption text-muted-foreground", children: "
|
|
3455
|
+
/* @__PURE__ */ jsx11("span", { className: "mr-1 select-none text-caption text-muted-foreground", children: t("editor.tableView.row") }),
|
|
3289
3456
|
/* @__PURE__ */ jsx11(
|
|
3290
3457
|
ToolbarButton,
|
|
3291
3458
|
{
|
|
3292
|
-
ariaLabel:
|
|
3293
|
-
title:
|
|
3459
|
+
ariaLabel: addRowAbove,
|
|
3460
|
+
title: addRowAbove,
|
|
3294
3461
|
onClick: run(addRowBeforeCommand.key),
|
|
3295
3462
|
children: "\u2191+"
|
|
3296
3463
|
}
|
|
@@ -3298,8 +3465,8 @@ function TableControlsView() {
|
|
|
3298
3465
|
/* @__PURE__ */ jsx11(
|
|
3299
3466
|
ToolbarButton,
|
|
3300
3467
|
{
|
|
3301
|
-
ariaLabel:
|
|
3302
|
-
title:
|
|
3468
|
+
ariaLabel: addRowBelow,
|
|
3469
|
+
title: addRowBelow,
|
|
3303
3470
|
onClick: run(addRowAfterCommand.key),
|
|
3304
3471
|
children: "\u2193+"
|
|
3305
3472
|
}
|
|
@@ -3307,20 +3474,20 @@ function TableControlsView() {
|
|
|
3307
3474
|
/* @__PURE__ */ jsx11(
|
|
3308
3475
|
ToolbarButton,
|
|
3309
3476
|
{
|
|
3310
|
-
ariaLabel:
|
|
3311
|
-
title:
|
|
3477
|
+
ariaLabel: deleteRow,
|
|
3478
|
+
title: deleteRow,
|
|
3312
3479
|
variant: "destructive",
|
|
3313
3480
|
onClick: run(deleteSelectedCellsCommand.key),
|
|
3314
3481
|
children: "\xD7row"
|
|
3315
3482
|
}
|
|
3316
3483
|
),
|
|
3317
3484
|
/* @__PURE__ */ jsx11(ToolbarDivider, {}),
|
|
3318
|
-
/* @__PURE__ */ jsx11("span", { className: "mr-1 select-none text-caption text-muted-foreground", children: "
|
|
3485
|
+
/* @__PURE__ */ jsx11("span", { className: "mr-1 select-none text-caption text-muted-foreground", children: t("editor.tableView.col") }),
|
|
3319
3486
|
/* @__PURE__ */ jsx11(
|
|
3320
3487
|
ToolbarButton,
|
|
3321
3488
|
{
|
|
3322
|
-
ariaLabel:
|
|
3323
|
-
title:
|
|
3489
|
+
ariaLabel: addColLeft,
|
|
3490
|
+
title: addColLeft,
|
|
3324
3491
|
onClick: run(addColBeforeCommand.key),
|
|
3325
3492
|
children: "\u2190+"
|
|
3326
3493
|
}
|
|
@@ -3328,8 +3495,8 @@ function TableControlsView() {
|
|
|
3328
3495
|
/* @__PURE__ */ jsx11(
|
|
3329
3496
|
ToolbarButton,
|
|
3330
3497
|
{
|
|
3331
|
-
ariaLabel:
|
|
3332
|
-
title:
|
|
3498
|
+
ariaLabel: addColRight,
|
|
3499
|
+
title: addColRight,
|
|
3333
3500
|
onClick: run(addColAfterCommand.key),
|
|
3334
3501
|
children: "\u2192+"
|
|
3335
3502
|
}
|
|
@@ -3337,8 +3504,8 @@ function TableControlsView() {
|
|
|
3337
3504
|
/* @__PURE__ */ jsx11(
|
|
3338
3505
|
ToolbarButton,
|
|
3339
3506
|
{
|
|
3340
|
-
ariaLabel:
|
|
3341
|
-
title:
|
|
3507
|
+
ariaLabel: deleteCol,
|
|
3508
|
+
title: deleteCol,
|
|
3342
3509
|
variant: "destructive",
|
|
3343
3510
|
onClick: run(deleteSelectedCellsCommand.key),
|
|
3344
3511
|
children: "\xD7col"
|
|
@@ -3374,8 +3541,8 @@ function tableViewPlugins(pluginViewFactory) {
|
|
|
3374
3541
|
|
|
3375
3542
|
// src/markdown-editor/markdown-editor.tsx
|
|
3376
3543
|
import { jsx as jsx12 } from "react/jsx-runtime";
|
|
3377
|
-
function scrollHeadingBySlug(
|
|
3378
|
-
|
|
3544
|
+
function scrollHeadingBySlug(editor, slug) {
|
|
3545
|
+
editor.action((ctx2) => {
|
|
3379
3546
|
const view = ctx2.get(editorViewCtx3);
|
|
3380
3547
|
const { doc } = view.state;
|
|
3381
3548
|
const used = /* @__PURE__ */ new Map();
|
|
@@ -3435,7 +3602,7 @@ var MarkdownEditorView = forwardRef6(function MarkdownEditorView2({
|
|
|
3435
3602
|
const embedPlugin = pasteEmbedPlugin(
|
|
3436
3603
|
onEmbedAssetRef.current ? (file) => onEmbedAssetRef.current(file) : void 0
|
|
3437
3604
|
);
|
|
3438
|
-
let
|
|
3605
|
+
let editor = Editor.make().config((ctx2) => {
|
|
3439
3606
|
ctx2.set(rootCtx, root);
|
|
3440
3607
|
ctx2.set(defaultValueCtx, lastMarkdown.current);
|
|
3441
3608
|
ctx2.update(editorViewOptionsCtx, (prev) => ({
|
|
@@ -3456,7 +3623,7 @@ var MarkdownEditorView = forwardRef6(function MarkdownEditorView2({
|
|
|
3456
3623
|
)
|
|
3457
3624
|
);
|
|
3458
3625
|
if (slashEnabled) {
|
|
3459
|
-
|
|
3626
|
+
editor = editor.use(
|
|
3460
3627
|
brandSlashViewPlugins(widgetViewFactory, {
|
|
3461
3628
|
...slashConfigRef.current,
|
|
3462
3629
|
getIterationEditHandler: () => iterationEditHandlerRef.current
|
|
@@ -3464,14 +3631,14 @@ var MarkdownEditorView = forwardRef6(function MarkdownEditorView2({
|
|
|
3464
3631
|
);
|
|
3465
3632
|
}
|
|
3466
3633
|
if (calcEnabled) {
|
|
3467
|
-
|
|
3634
|
+
editor = editor.use(calcProsePlugins(() => calcRef.current));
|
|
3468
3635
|
}
|
|
3469
3636
|
if (completionsEnabled) {
|
|
3470
|
-
|
|
3637
|
+
editor = editor.use(
|
|
3471
3638
|
completionsViewPlugins(widgetViewFactory, () => completionsRef.current)
|
|
3472
3639
|
);
|
|
3473
3640
|
}
|
|
3474
|
-
return
|
|
3641
|
+
return editor;
|
|
3475
3642
|
},
|
|
3476
3643
|
[readOnly, ariaLabel, slashEnabled, calcEnabled, completionsEnabled]
|
|
3477
3644
|
);
|
|
@@ -3479,21 +3646,21 @@ var MarkdownEditorView = forwardRef6(function MarkdownEditorView2({
|
|
|
3479
3646
|
useEffect5(() => {
|
|
3480
3647
|
if (loading || value === void 0) return;
|
|
3481
3648
|
if (value === lastMarkdown.current) return;
|
|
3482
|
-
const
|
|
3483
|
-
if (!
|
|
3649
|
+
const editor = getInstance();
|
|
3650
|
+
if (!editor) return;
|
|
3484
3651
|
lastMarkdown.current = value;
|
|
3485
|
-
|
|
3652
|
+
editor.action(replaceAll(value));
|
|
3486
3653
|
}, [loading, value, getInstance]);
|
|
3487
3654
|
useImperativeHandle2(
|
|
3488
3655
|
ref,
|
|
3489
3656
|
() => {
|
|
3490
3657
|
const serializeSlice = (view) => {
|
|
3491
|
-
const
|
|
3492
|
-
if (!
|
|
3658
|
+
const editor = getInstance();
|
|
3659
|
+
if (!editor) return "";
|
|
3493
3660
|
const { selection } = view.state;
|
|
3494
3661
|
if (selection.empty) return "";
|
|
3495
3662
|
try {
|
|
3496
|
-
return
|
|
3663
|
+
return editor.action((ctx2) => {
|
|
3497
3664
|
const serialize = ctx2.get(serializerCtx2);
|
|
3498
3665
|
const doc = selection.content().content;
|
|
3499
3666
|
const wrapper = view.state.doc.type.schema.topNodeType.create(null, doc);
|
|
@@ -3505,10 +3672,10 @@ var MarkdownEditorView = forwardRef6(function MarkdownEditorView2({
|
|
|
3505
3672
|
};
|
|
3506
3673
|
serializeSliceRef.current = serializeSlice;
|
|
3507
3674
|
const parseAndReplace = (view, md) => {
|
|
3508
|
-
const
|
|
3509
|
-
if (!
|
|
3675
|
+
const editor = getInstance();
|
|
3676
|
+
if (!editor) return;
|
|
3510
3677
|
try {
|
|
3511
|
-
|
|
3678
|
+
editor.action((ctx2) => {
|
|
3512
3679
|
const parse = ctx2.get(parserCtx3);
|
|
3513
3680
|
const parsed = parse(md);
|
|
3514
3681
|
if (!parsed) {
|
|
@@ -3526,10 +3693,10 @@ var MarkdownEditorView = forwardRef6(function MarkdownEditorView2({
|
|
|
3526
3693
|
}
|
|
3527
3694
|
};
|
|
3528
3695
|
const getView = () => {
|
|
3529
|
-
const
|
|
3530
|
-
if (!
|
|
3696
|
+
const editor = getInstance();
|
|
3697
|
+
if (!editor) return null;
|
|
3531
3698
|
try {
|
|
3532
|
-
return
|
|
3699
|
+
return editor.action((ctx2) => ctx2.get(editorViewCtx3));
|
|
3533
3700
|
} catch {
|
|
3534
3701
|
return null;
|
|
3535
3702
|
}
|
|
@@ -3553,15 +3720,15 @@ var MarkdownEditorView = forwardRef6(function MarkdownEditorView2({
|
|
|
3553
3720
|
getMarkdown: () => getInstance()?.action(getMarkdown()) ?? lastMarkdown.current,
|
|
3554
3721
|
serialized: () => getInstance()?.action(getMarkdown()) ?? null,
|
|
3555
3722
|
scrollToHeading: (slug) => {
|
|
3556
|
-
const
|
|
3557
|
-
if (
|
|
3723
|
+
const editor = getInstance();
|
|
3724
|
+
if (editor) scrollHeadingBySlug(editor, slug);
|
|
3558
3725
|
},
|
|
3559
3726
|
revealLine: (line, _opts) => {
|
|
3560
|
-
const
|
|
3561
|
-
if (!
|
|
3562
|
-
const md =
|
|
3727
|
+
const editor = getInstance();
|
|
3728
|
+
if (!editor) return;
|
|
3729
|
+
const md = editor.action(getMarkdown());
|
|
3563
3730
|
const preceding = parseMarkdownOutline(md).filter((item) => item.line <= line).at(-1);
|
|
3564
|
-
if (preceding) scrollHeadingBySlug(
|
|
3731
|
+
if (preceding) scrollHeadingBySlug(editor, preceding.id);
|
|
3565
3732
|
}
|
|
3566
3733
|
};
|
|
3567
3734
|
},
|
|
@@ -3591,10 +3758,13 @@ var MarkdownEditor = forwardRef6(
|
|
|
3591
3758
|
{
|
|
3592
3759
|
"data-testid": "markdown-editor",
|
|
3593
3760
|
className: cn8(
|
|
3594
|
-
//
|
|
3595
|
-
//
|
|
3596
|
-
//
|
|
3597
|
-
|
|
3761
|
+
// No focus-ring utility here (deliberately, #309): the editable
|
|
3762
|
+
// `.ProseMirror` element owns the compound focus indicator itself
|
|
3763
|
+
// (`markdown-editor.css`'s `:focus-visible` rule), so it renders
|
|
3764
|
+
// even when a consumer `className` overrides this wrapper's
|
|
3765
|
+
// classes (`MarkdownWorkspace` does exactly that via
|
|
3766
|
+
// `className="border-0"`) and never doubles up with a wrapper ring.
|
|
3767
|
+
"milkdown-host overflow-auto rounded-md border border-border bg-background text-foreground",
|
|
3598
3768
|
className
|
|
3599
3769
|
),
|
|
3600
3770
|
style: { ...markdownScaleVars(), ...style },
|
|
@@ -3620,16 +3790,18 @@ var MarkdownEditor = forwardRef6(
|
|
|
3620
3790
|
);
|
|
3621
3791
|
|
|
3622
3792
|
// src/copy-button/copy-button.tsx
|
|
3623
|
-
import { Button, useCopyToClipboard } from "@elabs-ai/components-ui";
|
|
3793
|
+
import { Button, useCopyToClipboard, useLocale as useLocale6 } from "@elabs-ai/components-ui";
|
|
3624
3794
|
import { cn as cn9 } from "@elabs-ai/components-ui/lib/cn";
|
|
3625
3795
|
import { CheckIcon, CopyIcon } from "lucide-react";
|
|
3626
3796
|
import { useCallback as useCallback3 } from "react";
|
|
3627
3797
|
import { jsx as jsx13, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
3628
3798
|
function CopyButton({ value, label = true, className, ...props }) {
|
|
3629
3799
|
const { copied, copy } = useCopyToClipboard();
|
|
3800
|
+
const { t } = useLocale6();
|
|
3630
3801
|
const onClick = useCallback3(() => {
|
|
3631
3802
|
void copy(value);
|
|
3632
3803
|
}, [copy, value]);
|
|
3804
|
+
const text = copied ? t("editor.copyButton.copied") : t("copy");
|
|
3633
3805
|
return /* @__PURE__ */ jsxs8(
|
|
3634
3806
|
Button,
|
|
3635
3807
|
{
|
|
@@ -3639,7 +3811,7 @@ function CopyButton({ value, label = true, className, ...props }) {
|
|
|
3639
3811
|
type: "button",
|
|
3640
3812
|
className: cn9("h-7 gap-1.5", className),
|
|
3641
3813
|
onClick,
|
|
3642
|
-
"aria-label":
|
|
3814
|
+
"aria-label": text,
|
|
3643
3815
|
children: [
|
|
3644
3816
|
copied ? /* @__PURE__ */ jsx13(
|
|
3645
3817
|
CheckIcon,
|
|
@@ -3649,37 +3821,37 @@ function CopyButton({ value, label = true, className, ...props }) {
|
|
|
3649
3821
|
},
|
|
3650
3822
|
String(copied)
|
|
3651
3823
|
) : /* @__PURE__ */ jsx13(CopyIcon, { className: "size-4", "aria-hidden": "true" }),
|
|
3652
|
-
label ? /* @__PURE__ */ jsx13("span", { className: "text-xs", children:
|
|
3824
|
+
label ? /* @__PURE__ */ jsx13("span", { className: "text-xs", children: text }) : null
|
|
3653
3825
|
]
|
|
3654
3826
|
}
|
|
3655
3827
|
);
|
|
3656
3828
|
}
|
|
3657
3829
|
|
|
3658
3830
|
// src/lib/editor-content-access.ts
|
|
3659
|
-
function monacoContentAccess(
|
|
3831
|
+
function monacoContentAccess(editor) {
|
|
3660
3832
|
const readSelection = () => {
|
|
3661
|
-
const model =
|
|
3662
|
-
const selection =
|
|
3833
|
+
const model = editor.getModel();
|
|
3834
|
+
const selection = editor.getSelection();
|
|
3663
3835
|
if (!model || !selection) return { text: "", empty: true };
|
|
3664
3836
|
const text = model.getValueInRange(selection);
|
|
3665
3837
|
return { text, empty: selection.isEmpty() };
|
|
3666
3838
|
};
|
|
3667
3839
|
const applyAtSelection = (text) => {
|
|
3668
|
-
const selection =
|
|
3840
|
+
const selection = editor.getSelection();
|
|
3669
3841
|
if (!selection) return;
|
|
3670
|
-
|
|
3842
|
+
editor.executeEdits("editor-content-access", [
|
|
3671
3843
|
{ range: selection, text, forceMoveMarkers: true }
|
|
3672
3844
|
]);
|
|
3673
|
-
|
|
3845
|
+
editor.pushUndoStop();
|
|
3674
3846
|
};
|
|
3675
3847
|
return {
|
|
3676
|
-
getText: () =>
|
|
3848
|
+
getText: () => editor.getValue(),
|
|
3677
3849
|
getSelection: readSelection,
|
|
3678
3850
|
replaceSelection: applyAtSelection,
|
|
3679
3851
|
insertAtCursor: applyAtSelection,
|
|
3680
|
-
focus: () =>
|
|
3852
|
+
focus: () => editor.focus(),
|
|
3681
3853
|
onSelectionChange: (listener2) => {
|
|
3682
|
-
const sub =
|
|
3854
|
+
const sub = editor.onDidChangeCursorSelection(() => listener2(readSelection()));
|
|
3683
3855
|
return () => sub.dispose();
|
|
3684
3856
|
}
|
|
3685
3857
|
};
|
|
@@ -3745,4 +3917,4 @@ export {
|
|
|
3745
3917
|
CopyButton,
|
|
3746
3918
|
monacoContentAccess
|
|
3747
3919
|
};
|
|
3748
|
-
//# sourceMappingURL=chunk-
|
|
3920
|
+
//# sourceMappingURL=chunk-FO5S3YZM.js.map
|