@bendyline/squisq-editor-react 2.0.1 → 2.1.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 +10 -2
- package/dist/index.d.ts +505 -15
- package/dist/index.js +6035 -2283
- package/dist/index.js.map +1 -1
- package/dist/styles/index.css +870 -40
- package/package.json +6 -5
- package/src/EditorContext.tsx +27 -0
- package/src/EditorShell.tsx +24 -0
- package/src/PreviewControls.tsx +20 -5
- package/src/PreviewPanel.tsx +5 -1
- package/src/RawEditor.tsx +12 -0
- package/src/RecorderEntry.tsx +3 -0
- package/src/Toolbar.tsx +315 -17
- package/src/WysiwygEditor.tsx +25 -11
- package/src/__tests__/buildPreviewDocContent.test.ts +17 -0
- package/src/__tests__/editorShellProps.test.tsx +65 -0
- package/src/__tests__/findMode.test.tsx +104 -0
- package/src/__tests__/findModel.test.ts +55 -0
- package/src/__tests__/markdownCodeFence.test.ts +45 -0
- package/src/__tests__/mediaReferences.test.ts +15 -0
- package/src/__tests__/previewControls.test.tsx +31 -0
- package/src/__tests__/tiptapBridge.test.ts +9 -0
- package/src/__tests__/toolbarSelectionConversion.test.tsx +26 -0
- package/src/__tests__/writeCanvasSettings.test.ts +15 -0
- package/src/asciiDiagram/__tests__/AsciiDiagramExtension.test.ts +20 -1
- package/src/buildPreviewDoc.ts +9 -7
- package/src/codeSnippet/CodeSnippetExtension.ts +205 -0
- package/src/codeSnippet/CodeSnippetWidget.tsx +109 -0
- package/src/codeSnippet/__tests__/CodeSnippetExtension.test.ts +95 -0
- package/src/codeSnippet/__tests__/codeSnippetLanguages.test.ts +50 -0
- package/src/codeSnippet/codeSnippetCommands.ts +21 -0
- package/src/codeSnippet/codeSnippetData.ts +43 -0
- package/src/codeSnippet/codeSnippetLanguages.ts +216 -0
- package/src/diagram/DiagramCanvas.tsx +1 -0
- package/src/find/FindHighlightExtension.ts +81 -0
- package/src/find/FindToolbar.tsx +314 -0
- package/src/find/findModel.ts +77 -0
- package/src/index.ts +89 -0
- package/src/markdownCodeFence.ts +72 -0
- package/src/mediaReferences.ts +5 -3
- package/src/mermaid/MermaidDiagramCanvas.tsx +693 -0
- package/src/mermaid/MermaidDiagramExtension.ts +243 -0
- package/src/mermaid/MermaidDiagramTypeThumbnail.tsx +184 -0
- package/src/mermaid/MermaidDiagramWidget.tsx +653 -0
- package/src/mermaid/MermaidShapePalette.tsx +245 -0
- package/src/mermaid/__tests__/MermaidDiagramExtension.test.ts +361 -0
- package/src/mermaid/__tests__/mermaidDiagramTypes.test.ts +35 -0
- package/src/mermaid/__tests__/mermaidRenderer.test.ts +49 -0
- package/src/mermaid/__tests__/mermaidSourceOps.test.ts +213 -0
- package/src/mermaid/__tests__/mermaidSyntax.test.ts +71 -0
- package/src/mermaid/mermaidCommands.ts +34 -0
- package/src/mermaid/mermaidData.ts +31 -0
- package/src/mermaid/mermaidDiagramTypes.ts +325 -0
- package/src/mermaid/mermaidModel.ts +31 -0
- package/src/mermaid/mermaidRenderer.ts +181 -0
- package/src/mermaid/mermaidShapes.ts +113 -0
- package/src/mermaid/mermaidSourceOps.ts +454 -0
- package/src/scene/Scene.tsx +46 -15
- package/src/scene/SceneBlockToolbar.tsx +29 -14
- package/src/scene/SceneViewControls.tsx +43 -0
- package/src/scene/__tests__/fitScale.test.ts +19 -0
- package/src/scene/__tests__/useScenePanZoom.test.ts +28 -1
- package/src/scene/fitScale.ts +17 -0
- package/src/scene/hooks/useScenePanZoom.ts +11 -4
- package/src/scene/scene.css +85 -3
- package/src/styles/code-snippet.css +76 -0
- package/src/styles/editor.css +322 -2
- package/src/styles/index.css +2 -0
- package/src/styles/mermaid-diagram.css +487 -0
- package/src/writeCanvasSettings.ts +30 -0
package/src/index.ts
CHANGED
|
@@ -89,6 +89,7 @@ export type { RawEditorProps } from './RawEditor.js';
|
|
|
89
89
|
|
|
90
90
|
export { WysiwygEditor } from './WysiwygEditor.js';
|
|
91
91
|
export type { WysiwygEditorProps } from './WysiwygEditor.js';
|
|
92
|
+
export type { WriteCanvasSettings } from './writeCanvasSettings.js';
|
|
92
93
|
|
|
93
94
|
export { PreviewPanel } from './PreviewPanel.js';
|
|
94
95
|
export type { PreviewPanelProps } from './PreviewPanel.js';
|
|
@@ -293,6 +294,94 @@ export {
|
|
|
293
294
|
} from './asciiDiagram/asciiDiagramOps.js';
|
|
294
295
|
export { shouldPasteAsAsciiFence } from './asciiDiagram/asciiPaste.js';
|
|
295
296
|
|
|
297
|
+
// Complex diagram editor — every explicit `mermaid` fence is rendered through
|
|
298
|
+
// Mermaid's public renderer inside the shared diagram chrome. Flowcharts add
|
|
299
|
+
// source-backed node/edge gestures and the full Mermaid shape catalog; every
|
|
300
|
+
// other diagram family remains lossless render + source editing.
|
|
301
|
+
export {
|
|
302
|
+
MermaidDiagramExtension,
|
|
303
|
+
MERMAID_DIAGRAM_KEY,
|
|
304
|
+
findMermaidDiagramBlockPos,
|
|
305
|
+
isMermaidDiagramNode,
|
|
306
|
+
isMermaidSourceVisible,
|
|
307
|
+
toggleMermaidSource,
|
|
308
|
+
} from './mermaid/MermaidDiagramExtension.js';
|
|
309
|
+
export type {
|
|
310
|
+
MermaidDiagramBlockEntry,
|
|
311
|
+
MermaidDiagramExtensionOptions,
|
|
312
|
+
MermaidDiagramPluginState,
|
|
313
|
+
} from './mermaid/MermaidDiagramExtension.js';
|
|
314
|
+
export { MermaidDiagramWidget } from './mermaid/MermaidDiagramWidget.js';
|
|
315
|
+
export type { MermaidDiagramWidgetProps } from './mermaid/MermaidDiagramWidget.js';
|
|
316
|
+
export { MermaidDiagramCanvas } from './mermaid/MermaidDiagramCanvas.js';
|
|
317
|
+
export type {
|
|
318
|
+
MermaidDiagramCanvasProps,
|
|
319
|
+
MermaidNodeCanvasAction,
|
|
320
|
+
} from './mermaid/MermaidDiagramCanvas.js';
|
|
321
|
+
export { useMermaidDiagramData } from './mermaid/mermaidData.js';
|
|
322
|
+
export type { MermaidDiagramData } from './mermaid/mermaidData.js';
|
|
323
|
+
export {
|
|
324
|
+
renderMermaidDiagram,
|
|
325
|
+
inspectMermaidSource,
|
|
326
|
+
mermaidErrorMessage,
|
|
327
|
+
} from './mermaid/mermaidRenderer.js';
|
|
328
|
+
export type { MermaidRenderResult } from './mermaid/mermaidRenderer.js';
|
|
329
|
+
export { MermaidShapePalette } from './mermaid/MermaidShapePalette.js';
|
|
330
|
+
export type { MermaidShapePaletteProps } from './mermaid/MermaidShapePalette.js';
|
|
331
|
+
export {
|
|
332
|
+
MERMAID_FLOWCHART_SHAPES,
|
|
333
|
+
isMermaidFlowchartShapeId,
|
|
334
|
+
normalizeMermaidFlowchartShape,
|
|
335
|
+
} from './mermaid/mermaidShapes.js';
|
|
336
|
+
export type { MermaidFlowchartShape, MermaidFlowchartShapeId } from './mermaid/mermaidShapes.js';
|
|
337
|
+
export type {
|
|
338
|
+
MermaidEditableEdge,
|
|
339
|
+
MermaidEditableModel,
|
|
340
|
+
MermaidEditableNode,
|
|
341
|
+
MermaidFlowchartDirection,
|
|
342
|
+
MermaidFlowchartModel,
|
|
343
|
+
} from './mermaid/mermaidModel.js';
|
|
344
|
+
export {
|
|
345
|
+
DEFAULT_MERMAID_DIAGRAM_TYPE,
|
|
346
|
+
MERMAID_DIAGRAM_TYPES,
|
|
347
|
+
mermaidDiagramMarkdown,
|
|
348
|
+
} from './mermaid/mermaidDiagramTypes.js';
|
|
349
|
+
export type {
|
|
350
|
+
MermaidDiagramCategory,
|
|
351
|
+
MermaidDiagramPreview,
|
|
352
|
+
MermaidDiagramType,
|
|
353
|
+
} from './mermaid/mermaidDiagramTypes.js';
|
|
354
|
+
export { MermaidDiagramTypeThumbnail } from './mermaid/MermaidDiagramTypeThumbnail.js';
|
|
355
|
+
|
|
356
|
+
// Code snippets — every ordinary explicit-language fence is replaced in the
|
|
357
|
+
// WYSIWYG surface by a Monaco inset. The fence node remains authoritative, so
|
|
358
|
+
// edits preserve the exact language tag and source when serialized to Markdown.
|
|
359
|
+
export {
|
|
360
|
+
CodeSnippetExtension,
|
|
361
|
+
CODE_SNIPPET_KEY,
|
|
362
|
+
findCodeSnippetBlockPos,
|
|
363
|
+
isCodeSnippetNode,
|
|
364
|
+
} from './codeSnippet/CodeSnippetExtension.js';
|
|
365
|
+
export type {
|
|
366
|
+
CodeSnippetBlockEntry,
|
|
367
|
+
CodeSnippetExtensionOptions,
|
|
368
|
+
CodeSnippetPluginState,
|
|
369
|
+
} from './codeSnippet/CodeSnippetExtension.js';
|
|
370
|
+
export { CodeSnippetWidget } from './codeSnippet/CodeSnippetWidget.js';
|
|
371
|
+
export type { CodeSnippetWidgetProps } from './codeSnippet/CodeSnippetWidget.js';
|
|
372
|
+
export { replaceCodeSnippetText } from './codeSnippet/codeSnippetCommands.js';
|
|
373
|
+
export { useCodeSnippetData } from './codeSnippet/codeSnippetData.js';
|
|
374
|
+
export type { CodeSnippetData } from './codeSnippet/codeSnippetData.js';
|
|
375
|
+
export {
|
|
376
|
+
CODE_SNIPPET_LANGUAGES,
|
|
377
|
+
codeSnippetFenceLanguageToken,
|
|
378
|
+
codeSnippetLanguageLabel,
|
|
379
|
+
codeSnippetMarkdown,
|
|
380
|
+
isCodeSnippetFenceLanguage,
|
|
381
|
+
monacoLanguageForFence,
|
|
382
|
+
} from './codeSnippet/codeSnippetLanguages.js';
|
|
383
|
+
export type { CodeSnippetLanguage } from './codeSnippet/codeSnippetLanguages.js';
|
|
384
|
+
|
|
296
385
|
// Treeview editor — ASCII file-tree / outline fences get an interactive
|
|
297
386
|
// outline widget; edits re-render the tree art (the fence stays the source
|
|
298
387
|
// of truth). Peer to the ASCII diagram editor; mutually exclusive with it
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Source-level Markdown fenced-code detection for editor features that cannot
|
|
3
|
+
* operate on the parsed AST. The returned mask includes opening and closing
|
|
4
|
+
* fence lines, and an unclosed fence remains active through EOF.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
interface FenceState {
|
|
8
|
+
marker: '`' | '~';
|
|
9
|
+
length: number;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const FENCE_RE = /^ {0,3}(`{3,}|~{3,})(.*)$/;
|
|
13
|
+
const CLOSING_FENCE_RE = /^ {0,3}(`{3,}|~{3,})[ \t]*$/;
|
|
14
|
+
|
|
15
|
+
function openingFence(line: string): FenceState | null {
|
|
16
|
+
const match = FENCE_RE.exec(line);
|
|
17
|
+
if (!match) return null;
|
|
18
|
+
const run = match[1];
|
|
19
|
+
const marker = run[0] as '`' | '~';
|
|
20
|
+
// CommonMark forbids backticks in a backtick fence's info string.
|
|
21
|
+
if (marker === '`' && match[2].includes('`')) return null;
|
|
22
|
+
return { marker, length: run.length };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function isClosingFence(line: string, fence: FenceState): boolean {
|
|
26
|
+
const match = CLOSING_FENCE_RE.exec(line);
|
|
27
|
+
return !!match && match[1][0] === fence.marker && match[1].length >= fence.length;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** One boolean per physical source line; true means the whole line is fenced code. */
|
|
31
|
+
export function markdownFencedCodeLineMask(source: string): boolean[] {
|
|
32
|
+
const lines = source.split(/\r\n|\r|\n/);
|
|
33
|
+
const mask: boolean[] = [];
|
|
34
|
+
let fence: FenceState | null = null;
|
|
35
|
+
|
|
36
|
+
for (const line of lines) {
|
|
37
|
+
if (fence) {
|
|
38
|
+
mask.push(true);
|
|
39
|
+
if (isClosingFence(line, fence)) fence = null;
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const opening = openingFence(line);
|
|
44
|
+
mask.push(opening != null);
|
|
45
|
+
fence = opening;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return mask;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Whether a 1-based physical source line is an opening, body, or closing fence line. */
|
|
52
|
+
export function isMarkdownFencedCodeLine(source: string, lineNumber: number): boolean {
|
|
53
|
+
if (!Number.isInteger(lineNumber) || lineNumber < 1) return false;
|
|
54
|
+
return markdownFencedCodeLineMask(source)[lineNumber - 1] ?? false;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Replace fenced-code line contents with spaces while retaining every line
|
|
59
|
+
* ending and character offset. Raw-source scanners can safely inspect the
|
|
60
|
+
* result and use any match offsets against the original source.
|
|
61
|
+
*/
|
|
62
|
+
export function maskMarkdownFencedCode(source: string): string {
|
|
63
|
+
const mask = markdownFencedCodeLineMask(source);
|
|
64
|
+
let lineIndex = 0;
|
|
65
|
+
return source
|
|
66
|
+
.split(/(\r\n|\r|\n)/)
|
|
67
|
+
.map((part, index) => {
|
|
68
|
+
if (index % 2 === 1) return part;
|
|
69
|
+
return mask[lineIndex++] ? ' '.repeat(part.length) : part;
|
|
70
|
+
})
|
|
71
|
+
.join('');
|
|
72
|
+
}
|
package/src/mediaReferences.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { splitKeyValueToken, tokenizeAttrTokens } from '@bendyline/squisq/markdown';
|
|
2
|
+
import { maskMarkdownFencedCode } from './markdownCodeFence';
|
|
2
3
|
|
|
3
4
|
interface MediaReferenceRange {
|
|
4
5
|
start: number;
|
|
@@ -32,9 +33,10 @@ const HTML_MEDIA_ATTRS = ['src', 'href', 'poster'] as const;
|
|
|
32
33
|
*/
|
|
33
34
|
export function collectMediaReferencesFromMarkdown(source: string): ReadonlySet<string> {
|
|
34
35
|
const refs = new Set<string>();
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
const searchableSource = maskMarkdownFencedCode(source);
|
|
37
|
+
collectMarkdownInlineReferences(searchableSource, refs);
|
|
38
|
+
collectHtmlAttributeReferences(searchableSource, refs);
|
|
39
|
+
collectAnnotationReferences(searchableSource, refs);
|
|
38
40
|
return refs;
|
|
39
41
|
}
|
|
40
42
|
|