@liminis/editor 0.1.0-rc.1
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/LICENSE +34 -0
- package/README.md +376 -0
- package/dist/annotations/anchor-align.d.ts +50 -0
- package/dist/annotations/anchor-align.js +74 -0
- package/dist/annotations/anchor-model.d.ts +81 -0
- package/dist/annotations/anchor-model.js +80 -0
- package/dist/annotations/anchor-resolver.d.ts +92 -0
- package/dist/annotations/anchor-resolver.js +231 -0
- package/dist/annotations/block-structure.d.ts +65 -0
- package/dist/annotations/block-structure.js +113 -0
- package/dist/annotations/types.d.ts +159 -0
- package/dist/annotations/types.js +50 -0
- package/dist/annotations.d.ts +25 -0
- package/dist/annotations.js +27 -0
- package/dist/app/App.d.ts +64 -0
- package/dist/app/App.js +180 -0
- package/dist/app/editor/AmbientCorrectionPlugin.d.ts +18 -0
- package/dist/app/editor/AmbientCorrectionPlugin.js +185 -0
- package/dist/app/editor/AnchorScrollPlugin.d.ts +16 -0
- package/dist/app/editor/AnchorScrollPlugin.js +134 -0
- package/dist/app/editor/AnnotationMarkerPlugin.d.ts +24 -0
- package/dist/app/editor/AnnotationMarkerPlugin.js +224 -0
- package/dist/app/editor/AnnotationPlugin.d.ts +42 -0
- package/dist/app/editor/AnnotationPlugin.js +135 -0
- package/dist/app/editor/AnnotationSurface.d.ts +34 -0
- package/dist/app/editor/AnnotationSurface.js +115 -0
- package/dist/app/editor/AssetContext.d.ts +20 -0
- package/dist/app/editor/AssetContext.js +81 -0
- package/dist/app/editor/BlockClickPlugin.d.ts +8 -0
- package/dist/app/editor/BlockClickPlugin.js +126 -0
- package/dist/app/editor/CodeBlockPlugin.d.ts +1 -0
- package/dist/app/editor/CodeBlockPlugin.js +219 -0
- package/dist/app/editor/CorrectionPanelPlugin.d.ts +14 -0
- package/dist/app/editor/CorrectionPanelPlugin.js +333 -0
- package/dist/app/editor/DragHandlePlugin.d.ts +1 -0
- package/dist/app/editor/DragHandlePlugin.js +300 -0
- package/dist/app/editor/Editor.d.ts +84 -0
- package/dist/app/editor/Editor.js +539 -0
- package/dist/app/editor/FrontmatterPlugin.d.ts +19 -0
- package/dist/app/editor/FrontmatterPlugin.js +301 -0
- package/dist/app/editor/ImageModal.d.ts +13 -0
- package/dist/app/editor/ImageModal.js +267 -0
- package/dist/app/editor/ImagePlugin.d.ts +3 -0
- package/dist/app/editor/ImagePlugin.js +187 -0
- package/dist/app/editor/LinkClickPlugin.d.ts +23 -0
- package/dist/app/editor/LinkClickPlugin.js +90 -0
- package/dist/app/editor/MarkdownShortcutsPlugin.d.ts +49 -0
- package/dist/app/editor/MarkdownShortcutsPlugin.js +373 -0
- package/dist/app/editor/OrderedTaskListPlugin.d.ts +21 -0
- package/dist/app/editor/OrderedTaskListPlugin.js +78 -0
- package/dist/app/editor/SearchPlugin.d.ts +1 -0
- package/dist/app/editor/SearchPlugin.js +379 -0
- package/dist/app/editor/SelectionContextMenuPlugin.d.ts +29 -0
- package/dist/app/editor/SelectionContextMenuPlugin.js +160 -0
- package/dist/app/editor/SlashMenu.d.ts +11 -0
- package/dist/app/editor/SlashMenu.js +494 -0
- package/dist/app/editor/SlashMenuPlugin.d.ts +1 -0
- package/dist/app/editor/SlashMenuPlugin.js +168 -0
- package/dist/app/editor/TableActionsPlugin.d.ts +1 -0
- package/dist/app/editor/TableActionsPlugin.js +398 -0
- package/dist/app/editor/TogglePlugin.d.ts +1 -0
- package/dist/app/editor/TogglePlugin.js +159 -0
- package/dist/app/editor/Toolbar.d.ts +10 -0
- package/dist/app/editor/Toolbar.js +263 -0
- package/dist/app/editor/WikiLinkExistencePlugin.d.ts +17 -0
- package/dist/app/editor/WikiLinkExistencePlugin.js +104 -0
- package/dist/app/editor/WikiLinkFormatPlugin.d.ts +17 -0
- package/dist/app/editor/WikiLinkFormatPlugin.js +203 -0
- package/dist/app/editor/annotation-marks.d.ts +177 -0
- package/dist/app/editor/annotation-marks.js +750 -0
- package/dist/app/editor/annotationCommands.d.ts +13 -0
- package/dist/app/editor/annotationCommands.js +11 -0
- package/dist/app/editor/c4/C4InteractiveRenderer.d.ts +35 -0
- package/dist/app/editor/c4/C4InteractiveRenderer.js +299 -0
- package/dist/app/editor/c4/edge-clipping.d.ts +24 -0
- package/dist/app/editor/c4/edge-clipping.js +139 -0
- package/dist/app/editor/c4/hooks/useC4DiagramDrag.d.ts +38 -0
- package/dist/app/editor/c4/hooks/useC4DiagramDrag.js +112 -0
- package/dist/app/editor/c4/layout.d.ts +25 -0
- package/dist/app/editor/c4/layout.js +839 -0
- package/dist/app/editor/c4/parser.d.ts +19 -0
- package/dist/app/editor/c4/parser.js +410 -0
- package/dist/app/editor/c4/render-to-string.d.ts +24 -0
- package/dist/app/editor/c4/render-to-string.js +34 -0
- package/dist/app/editor/c4/renderer.d.ts +64 -0
- package/dist/app/editor/c4/renderer.js +569 -0
- package/dist/app/editor/c4/types.d.ts +203 -0
- package/dist/app/editor/c4/types.js +43 -0
- package/dist/app/editor/correction-yaml.d.ts +10 -0
- package/dist/app/editor/correction-yaml.js +40 -0
- package/dist/app/editor/editorNodes.d.ts +9 -0
- package/dist/app/editor/editorNodes.js +36 -0
- package/dist/app/editor/index.d.ts +1 -0
- package/dist/app/editor/index.js +1 -0
- package/dist/app/editor/mark-overlap-resolver.d.ts +6 -0
- package/dist/app/editor/mark-overlap-resolver.js +45 -0
- package/dist/app/editor/nodes/C4Component.d.ts +14 -0
- package/dist/app/editor/nodes/C4Component.js +284 -0
- package/dist/app/editor/nodes/C4Node.d.ts +32 -0
- package/dist/app/editor/nodes/C4Node.js +112 -0
- package/dist/app/editor/nodes/CalloutNode.d.ts +23 -0
- package/dist/app/editor/nodes/CalloutNode.js +94 -0
- package/dist/app/editor/nodes/CustomLinkNode.d.ts +57 -0
- package/dist/app/editor/nodes/CustomLinkNode.js +209 -0
- package/dist/app/editor/nodes/CustomListItemNode.d.ts +46 -0
- package/dist/app/editor/nodes/CustomListItemNode.js +120 -0
- package/dist/app/editor/nodes/CustomListNode.d.ts +27 -0
- package/dist/app/editor/nodes/CustomListNode.js +54 -0
- package/dist/app/editor/nodes/DefinitionListNode.d.ts +44 -0
- package/dist/app/editor/nodes/DefinitionListNode.js +151 -0
- package/dist/app/editor/nodes/DiagramContextMenu.d.ts +45 -0
- package/dist/app/editor/nodes/DiagramContextMenu.js +116 -0
- package/dist/app/editor/nodes/EquationComponent.d.ts +17 -0
- package/dist/app/editor/nodes/EquationComponent.js +130 -0
- package/dist/app/editor/nodes/EquationNode.d.ts +43 -0
- package/dist/app/editor/nodes/EquationNode.js +179 -0
- package/dist/app/editor/nodes/FootnoteNode.d.ts +40 -0
- package/dist/app/editor/nodes/FootnoteNode.js +151 -0
- package/dist/app/editor/nodes/FrontmatterNode.d.ts +24 -0
- package/dist/app/editor/nodes/FrontmatterNode.js +88 -0
- package/dist/app/editor/nodes/HorizontalRuleNode.d.ts +17 -0
- package/dist/app/editor/nodes/HorizontalRuleNode.js +57 -0
- package/dist/app/editor/nodes/HtmlNode.d.ts +32 -0
- package/dist/app/editor/nodes/HtmlNode.js +121 -0
- package/dist/app/editor/nodes/ImageComponent.d.ts +11 -0
- package/dist/app/editor/nodes/ImageComponent.js +228 -0
- package/dist/app/editor/nodes/ImageNode.d.ts +53 -0
- package/dist/app/editor/nodes/ImageNode.js +183 -0
- package/dist/app/editor/nodes/ListItemParagraphBreakNode.d.ts +42 -0
- package/dist/app/editor/nodes/ListItemParagraphBreakNode.js +95 -0
- package/dist/app/editor/nodes/MermaidComponent.d.ts +11 -0
- package/dist/app/editor/nodes/MermaidComponent.js +216 -0
- package/dist/app/editor/nodes/MermaidNode.d.ts +27 -0
- package/dist/app/editor/nodes/MermaidNode.js +96 -0
- package/dist/app/editor/nodes/ToggleNode.d.ts +56 -0
- package/dist/app/editor/nodes/ToggleNode.js +237 -0
- package/dist/app/editor/nodes/diagram-context-menu.d.ts +11 -0
- package/dist/app/editor/nodes/diagram-context-menu.js +70 -0
- package/dist/app/editor/nodes/diagram-utils.d.ts +13 -0
- package/dist/app/editor/nodes/diagram-utils.js +29 -0
- package/dist/app/editor/nodes/index.d.ts +30 -0
- package/dist/app/editor/nodes/index.js +17 -0
- package/dist/app/editor/utils.d.ts +2 -0
- package/dist/app/editor/utils.js +17 -0
- package/dist/app/mapper/index.d.ts +3 -0
- package/dist/app/mapper/index.js +2 -0
- package/dist/app/mapper/lexicalToMdast.d.ts +62 -0
- package/dist/app/mapper/lexicalToMdast.js +1937 -0
- package/dist/app/mapper/mdastToLexical.d.ts +31 -0
- package/dist/app/mapper/mdastToLexical.js +1075 -0
- package/dist/contract.d.ts +8 -0
- package/dist/contract.js +8 -0
- package/dist/headless.d.ts +40 -0
- package/dist/headless.js +45 -0
- package/dist/host/context.d.ts +20 -0
- package/dist/host/context.js +24 -0
- package/dist/host/defaults.d.ts +21 -0
- package/dist/host/defaults.js +47 -0
- package/dist/host/messages.d.ts +26 -0
- package/dist/host/messages.js +47 -0
- package/dist/host/types.d.ts +75 -0
- package/dist/host/types.js +13 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.js +51 -0
- package/dist/markdown/annotate-sentinels.d.ts +42 -0
- package/dist/markdown/annotate-sentinels.js +86 -0
- package/dist/markdown/parse.d.ts +56 -0
- package/dist/markdown/parse.js +516 -0
- package/dist/markdown/stringify.d.ts +7 -0
- package/dist/markdown/stringify.js +439 -0
- package/dist/markdown/vendor/mdast-util-wiki-link/LICENSE +21 -0
- package/dist/markdown/vendor/mdast-util-wiki-link/README.md +41 -0
- package/dist/markdown/vendor/mdast-util-wiki-link/from-markdown.d.ts +72 -0
- package/dist/markdown/vendor/mdast-util-wiki-link/from-markdown.js +127 -0
- package/dist/markdown/vendor/mdast-util-wiki-link/index.d.ts +8 -0
- package/dist/markdown/vendor/mdast-util-wiki-link/index.js +6 -0
- package/dist/markdown/vendor/mdast-util-wiki-link/to-markdown.d.ts +17 -0
- package/dist/markdown/vendor/mdast-util-wiki-link/to-markdown.js +33 -0
- package/dist/markdown.d.ts +28 -0
- package/dist/markdown.js +44 -0
- package/dist/mathjax-config.d.ts +89 -0
- package/dist/mathjax-config.js +133 -0
- package/dist/nodes.d.ts +34 -0
- package/dist/nodes.js +34 -0
- package/dist/stores/correctionStore.d.ts +15 -0
- package/dist/stores/correctionStore.js +12 -0
- package/dist/stores/editorStore.d.ts +16 -0
- package/dist/stores/editorStore.js +27 -0
- package/dist/styles.css +2477 -0
- package/dist/types.d.ts +296 -0
- package/dist/types.js +91 -0
- package/dist/utils/file-types.d.ts +10 -0
- package/dist/utils/file-types.js +46 -0
- package/docs/annotations.md +134 -0
- package/docs/decisions/README.md +72 -0
- package/docs/decisions/adr-002.md +27 -0
- package/docs/decisions/adr-007.md +27 -0
- package/docs/decisions/adr-010.md +26 -0
- package/docs/decisions/adr-024.md +124 -0
- package/docs/decisions/adr-024b.md +0 -0
- package/docs/decisions/adr-025.md +103 -0
- package/docs/decisions/adr-027.md +66 -0
- package/docs/decisions/adr-057.md +67 -0
- package/docs/decisions/adr-070.md +131 -0
- package/docs/decisions/adr-075.md +410 -0
- package/docs/decisions/adr-076.md +183 -0
- package/docs/decisions/adr-077.md +410 -0
- package/docs/decisions/adr-078.md +243 -0
- package/docs/decisions/adr-079.md +167 -0
- package/docs/decisions/adr-080.md +325 -0
- package/docs/decisions/adr-081.md +108 -0
- package/docs/decisions/adr-082.md +123 -0
- package/docs/decisions/adr-083.md +204 -0
- package/docs/decisions/adr-084.md +179 -0
- package/docs/editor-api.md +106 -0
- package/docs/markdown-pipeline.md +282 -0
- package/docs/provenance.md +106 -0
- package/docs/zusammen-editor-capability-map.md +232 -0
- package/package.json +175 -0
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* C4Component - React component for rendering and editing C4 architecture diagrams
|
|
4
|
+
*
|
|
5
|
+
* Uses the canonical React C4Renderer for diagram display.
|
|
6
|
+
* Provides editing UI (textarea overlay, click-to-edit) for the Lexical editor.
|
|
7
|
+
* Supports manual layout mode for drag-and-drop positioning of elements.
|
|
8
|
+
*/
|
|
9
|
+
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
|
|
10
|
+
import { mergeRegister } from '@lexical/utils';
|
|
11
|
+
import { $getNodeByKey, $getSelection, $isNodeSelection, COMMAND_PRIORITY_HIGH, KEY_ESCAPE_COMMAND, SELECTION_CHANGE_COMMAND, } from 'lexical';
|
|
12
|
+
import { Move, RotateCcw } from 'lucide-react';
|
|
13
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
14
|
+
import { parseC4, validateC4 } from '../c4/parser.js';
|
|
15
|
+
import { layoutC4Diagram } from '../c4/layout.js';
|
|
16
|
+
import { C4Renderer, C4ErrorDisplay } from '../c4/renderer.js';
|
|
17
|
+
import { C4InteractiveRenderer } from '../c4/C4InteractiveRenderer.js';
|
|
18
|
+
import { $isC4Node } from './C4Node.js';
|
|
19
|
+
import { DiagramContextMenu, useDiagramContextMenu } from './DiagramContextMenu.js';
|
|
20
|
+
function C4DiagramDisplay({ code, nodeKey, onDoubleClick, isEditable, }) {
|
|
21
|
+
const [editor] = useLexicalComposerContext();
|
|
22
|
+
const containerRef = useRef(null);
|
|
23
|
+
const [isDarkMode, setIsDarkMode] = useState(false);
|
|
24
|
+
const [showToolbar, setShowToolbar] = useState(false);
|
|
25
|
+
const [isEditingLayout, setIsEditingLayout] = useState(false);
|
|
26
|
+
const contextMenu = useDiagramContextMenu();
|
|
27
|
+
const previousCodeRef = useRef(code);
|
|
28
|
+
// Read manual layout from the node
|
|
29
|
+
const [manualLayout, setManualLayout] = useState(() => {
|
|
30
|
+
return editor.getEditorState().read(() => {
|
|
31
|
+
const node = $getNodeByKey(nodeKey);
|
|
32
|
+
if ($isC4Node(node)) {
|
|
33
|
+
return node.getManualLayout();
|
|
34
|
+
}
|
|
35
|
+
return undefined;
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
// Sync manual layout from node when it changes externally (e.g., undo/redo)
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
return editor.registerUpdateListener(({ editorState }) => {
|
|
41
|
+
editorState.read(() => {
|
|
42
|
+
const node = $getNodeByKey(nodeKey);
|
|
43
|
+
if ($isC4Node(node)) {
|
|
44
|
+
const nodeLayout = node.getManualLayout();
|
|
45
|
+
setManualLayout(nodeLayout);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
}, [editor, nodeKey]);
|
|
50
|
+
// Detect theme using MutationObserver
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
const detectTheme = () => {
|
|
53
|
+
const isDark = document.documentElement.classList.contains('dark');
|
|
54
|
+
setIsDarkMode(isDark);
|
|
55
|
+
};
|
|
56
|
+
detectTheme();
|
|
57
|
+
const observer = new MutationObserver(detectTheme);
|
|
58
|
+
observer.observe(document.documentElement, {
|
|
59
|
+
attributes: true,
|
|
60
|
+
attributeFilter: ['class'],
|
|
61
|
+
});
|
|
62
|
+
return () => observer.disconnect();
|
|
63
|
+
}, []);
|
|
64
|
+
// Parse, validate, and layout the diagram
|
|
65
|
+
const parseResult = useMemo(() => {
|
|
66
|
+
const pr = parseC4(code);
|
|
67
|
+
if (pr.diagram) {
|
|
68
|
+
const validationErrors = validateC4(pr.diagram);
|
|
69
|
+
pr.errors.push(...validationErrors);
|
|
70
|
+
}
|
|
71
|
+
return pr;
|
|
72
|
+
}, [code]);
|
|
73
|
+
const layout = useMemo(() => {
|
|
74
|
+
if (!parseResult.diagram || parseResult.errors.length > 0)
|
|
75
|
+
return null;
|
|
76
|
+
const positions = manualLayout?.positions;
|
|
77
|
+
return layoutC4Diagram(parseResult.diagram, undefined, positions);
|
|
78
|
+
}, [parseResult, manualLayout]);
|
|
79
|
+
// TASK 7: Clear manual layout when DSL code changes (elements added/removed)
|
|
80
|
+
useEffect(() => {
|
|
81
|
+
if (manualLayout && code !== previousCodeRef.current && parseResult.diagram) {
|
|
82
|
+
const newElementIds = new Set(parseResult.diagram.elements.map(e => e.id));
|
|
83
|
+
const oldElementIds = new Set(Object.keys(manualLayout.positions).filter(id => !id.startsWith('__')));
|
|
84
|
+
// Check if elements were added or removed
|
|
85
|
+
const hasChanges = newElementIds.size !== oldElementIds.size ||
|
|
86
|
+
[...newElementIds].some(id => !oldElementIds.has(id)) ||
|
|
87
|
+
[...oldElementIds].some(id => !newElementIds.has(id));
|
|
88
|
+
if (hasChanges) {
|
|
89
|
+
// Clear manual layout
|
|
90
|
+
editor.update(() => {
|
|
91
|
+
const node = $getNodeByKey(nodeKey);
|
|
92
|
+
if ($isC4Node(node)) {
|
|
93
|
+
node.setManualLayout(undefined);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
setIsEditingLayout(false);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
previousCodeRef.current = code;
|
|
100
|
+
}, [code, manualLayout, parseResult.diagram, editor, nodeKey]);
|
|
101
|
+
// TASK 6: Handle position changes with Lexical undo integration
|
|
102
|
+
// The update listener above will sync manualLayout state from the node,
|
|
103
|
+
// so we only need to write to the Lexical node here.
|
|
104
|
+
const handlePositionChange = useCallback((newPositions) => {
|
|
105
|
+
editor.update(() => {
|
|
106
|
+
const node = $getNodeByKey(nodeKey);
|
|
107
|
+
if ($isC4Node(node)) {
|
|
108
|
+
node.setManualLayout({ positions: newPositions });
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
}, [editor, nodeKey]);
|
|
112
|
+
// Handle reset to auto layout
|
|
113
|
+
const handleResetLayout = useCallback(() => {
|
|
114
|
+
editor.update(() => {
|
|
115
|
+
const node = $getNodeByKey(nodeKey);
|
|
116
|
+
if ($isC4Node(node)) {
|
|
117
|
+
node.setManualLayout(undefined);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
setManualLayout(undefined);
|
|
121
|
+
setIsEditingLayout(false);
|
|
122
|
+
}, [editor, nodeKey]);
|
|
123
|
+
// Exit edit mode when clicking outside or pressing Escape
|
|
124
|
+
useEffect(() => {
|
|
125
|
+
if (!isEditingLayout)
|
|
126
|
+
return;
|
|
127
|
+
const handleKeyDown = (e) => {
|
|
128
|
+
if (e.key === 'Escape') {
|
|
129
|
+
setIsEditingLayout(false);
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
const handleMouseDown = (e) => {
|
|
133
|
+
const container = containerRef.current;
|
|
134
|
+
if (!container)
|
|
135
|
+
return;
|
|
136
|
+
if (e.target instanceof Node && !container.contains(e.target)) {
|
|
137
|
+
setIsEditingLayout(false);
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
window.addEventListener('keydown', handleKeyDown);
|
|
141
|
+
document.addEventListener('mousedown', handleMouseDown);
|
|
142
|
+
return () => {
|
|
143
|
+
window.removeEventListener('keydown', handleKeyDown);
|
|
144
|
+
document.removeEventListener('mousedown', handleMouseDown);
|
|
145
|
+
};
|
|
146
|
+
}, [isEditingLayout]);
|
|
147
|
+
if (!layout || !parseResult.diagram) {
|
|
148
|
+
return _jsx(C4ErrorDisplay, { errors: parseResult.errors, isDarkMode: isDarkMode });
|
|
149
|
+
}
|
|
150
|
+
const manualPositions = manualLayout?.positions ?? {};
|
|
151
|
+
return (_jsxs("div", { ref: containerRef, role: "button", tabIndex: 0, onDoubleClick: isEditingLayout ? undefined : onDoubleClick, onContextMenu: (e) => contextMenu.show(e, containerRef), onKeyDown: (e) => {
|
|
152
|
+
if (!isEditingLayout && (e.key === 'Enter' || e.key === ' ')) {
|
|
153
|
+
e.preventDefault();
|
|
154
|
+
onDoubleClick();
|
|
155
|
+
}
|
|
156
|
+
}, onMouseEnter: () => setShowToolbar(true), onMouseLeave: () => setShowToolbar(false), className: "c4-renderer c4-diagram-container", style: {
|
|
157
|
+
display: 'flex',
|
|
158
|
+
justifyContent: 'center',
|
|
159
|
+
padding: '1rem',
|
|
160
|
+
cursor: isEditingLayout ? 'default' : 'pointer',
|
|
161
|
+
minHeight: '100px',
|
|
162
|
+
overflowX: 'auto',
|
|
163
|
+
position: 'relative',
|
|
164
|
+
}, children: [isEditable && (showToolbar || isEditingLayout) && (_jsxs("div", { style: {
|
|
165
|
+
position: 'absolute',
|
|
166
|
+
top: '8px',
|
|
167
|
+
right: '8px',
|
|
168
|
+
display: 'flex',
|
|
169
|
+
gap: '4px',
|
|
170
|
+
zIndex: 10,
|
|
171
|
+
}, children: [_jsx("button", { type: "button", onClick: (e) => {
|
|
172
|
+
e.stopPropagation();
|
|
173
|
+
setIsEditingLayout(!isEditingLayout);
|
|
174
|
+
}, title: isEditingLayout ? 'Exit layout mode' : 'Edit layout', "aria-label": isEditingLayout ? 'Exit layout mode' : 'Edit layout', style: {
|
|
175
|
+
width: '28px',
|
|
176
|
+
height: '28px',
|
|
177
|
+
display: 'flex',
|
|
178
|
+
alignItems: 'center',
|
|
179
|
+
justifyContent: 'center',
|
|
180
|
+
borderRadius: '4px',
|
|
181
|
+
border: 'none',
|
|
182
|
+
cursor: 'pointer',
|
|
183
|
+
backgroundColor: isEditingLayout
|
|
184
|
+
? 'var(--color-primary-100, rgba(59, 130, 246, 0.1))'
|
|
185
|
+
: 'var(--color-muted-100, rgba(128, 128, 128, 0.1))',
|
|
186
|
+
color: isEditingLayout
|
|
187
|
+
? 'var(--color-primary, #3b82f6)'
|
|
188
|
+
: 'var(--color-muted-foreground, #6b7280)',
|
|
189
|
+
}, children: _jsx(Move, { size: 16 }) }), manualLayout && (_jsx("button", { type: "button", onClick: (e) => {
|
|
190
|
+
e.stopPropagation();
|
|
191
|
+
handleResetLayout();
|
|
192
|
+
}, title: "Reset to auto layout", "aria-label": "Reset to auto layout", style: {
|
|
193
|
+
width: '28px',
|
|
194
|
+
height: '28px',
|
|
195
|
+
display: 'flex',
|
|
196
|
+
alignItems: 'center',
|
|
197
|
+
justifyContent: 'center',
|
|
198
|
+
borderRadius: '4px',
|
|
199
|
+
border: 'none',
|
|
200
|
+
cursor: 'pointer',
|
|
201
|
+
backgroundColor: 'var(--color-muted-100, rgba(128, 128, 128, 0.1))',
|
|
202
|
+
color: 'var(--color-muted-foreground, #6b7280)',
|
|
203
|
+
}, children: _jsx(RotateCcw, { size: 16 }) }))] })), isEditingLayout && parseResult.diagram ? (_jsx(C4InteractiveRenderer, { diagram: parseResult.diagram, isDarkMode: isDarkMode, isEditMode: isEditingLayout, manualPositions: manualPositions, onPositionChange: handlePositionChange })) : (_jsx(C4Renderer, { layout: layout, isDarkMode: isDarkMode })), _jsx(DiagramContextMenu, { ...contextMenu.props, onEditText: isEditable ? onDoubleClick : undefined, onEditLayout: isEditable ? () => setIsEditingLayout(prev => !prev) : undefined, onResetLayout: isEditable ? handleResetLayout : undefined, isEditingLayout: isEditingLayout, hasManualLayout: !!manualLayout })] }));
|
|
204
|
+
}
|
|
205
|
+
// =============================================================================
|
|
206
|
+
// C4 EDITOR
|
|
207
|
+
// =============================================================================
|
|
208
|
+
function C4Editor({ code, setCode, onClose, }) {
|
|
209
|
+
const textareaRef = useRef(null);
|
|
210
|
+
useEffect(() => {
|
|
211
|
+
textareaRef.current?.focus();
|
|
212
|
+
}, []);
|
|
213
|
+
const handleKeyDown = (e) => {
|
|
214
|
+
if (e.key === 'Escape') {
|
|
215
|
+
e.preventDefault();
|
|
216
|
+
onClose();
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
return (_jsxs("div", { className: "c4-editor-container", children: [_jsxs("div", { className: "c4-editor-header", children: [_jsx("span", { className: "c4-editor-label", children: "```c4" }), _jsx("button", { className: "c4-editor-close", onClick: onClose, title: "Close editor (Esc)", children: "\u2715" })] }), _jsx("textarea", { ref: textareaRef, className: "c4-editor-textarea", value: code, onChange: (e) => setCode(e.target.value), onKeyDown: handleKeyDown, placeholder: "Enter C4 diagram code...", spellCheck: false }), _jsx("div", { className: "c4-editor-footer", children: _jsx("span", { className: "c4-editor-label", children: "```" }) })] }));
|
|
220
|
+
}
|
|
221
|
+
export default function C4Component({ code, nodeKey, }) {
|
|
222
|
+
const [editor] = useLexicalComposerContext();
|
|
223
|
+
const [isEditable, setIsEditable] = useState(() => editor.isEditable());
|
|
224
|
+
const [codeValue, setCodeValue] = useState(code);
|
|
225
|
+
const [showEditor, setShowEditor] = useState(false);
|
|
226
|
+
// Listen for editable changes
|
|
227
|
+
useEffect(() => {
|
|
228
|
+
return editor.registerEditableListener((editable) => {
|
|
229
|
+
setIsEditable(editable);
|
|
230
|
+
});
|
|
231
|
+
}, [editor]);
|
|
232
|
+
const onHide = useCallback(() => {
|
|
233
|
+
setShowEditor(false);
|
|
234
|
+
editor.update(() => {
|
|
235
|
+
const node = $getNodeByKey(nodeKey);
|
|
236
|
+
if ($isC4Node(node)) {
|
|
237
|
+
node.setCode(codeValue);
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
}, [editor, codeValue, nodeKey]);
|
|
241
|
+
useEffect(() => {
|
|
242
|
+
if (!showEditor && codeValue !== code) {
|
|
243
|
+
setCodeValue(code);
|
|
244
|
+
}
|
|
245
|
+
}, [showEditor, code, codeValue]);
|
|
246
|
+
useEffect(() => {
|
|
247
|
+
if (!isEditable) {
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
if (showEditor) {
|
|
251
|
+
return mergeRegister(editor.registerCommand(SELECTION_CHANGE_COMMAND, () => {
|
|
252
|
+
// Don't close on selection change while editing
|
|
253
|
+
return false;
|
|
254
|
+
}, COMMAND_PRIORITY_HIGH), editor.registerCommand(KEY_ESCAPE_COMMAND, () => {
|
|
255
|
+
if (showEditor) {
|
|
256
|
+
onHide();
|
|
257
|
+
return true;
|
|
258
|
+
}
|
|
259
|
+
return false;
|
|
260
|
+
}, COMMAND_PRIORITY_HIGH));
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
return editor.registerUpdateListener(({ editorState }) => {
|
|
264
|
+
const isSelected = editorState.read(() => {
|
|
265
|
+
const selection = $getSelection();
|
|
266
|
+
return ($isNodeSelection(selection) &&
|
|
267
|
+
selection.has(nodeKey) &&
|
|
268
|
+
selection.getNodes().length === 1);
|
|
269
|
+
});
|
|
270
|
+
if (isSelected) {
|
|
271
|
+
setShowEditor(true);
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
}, [editor, nodeKey, onHide, showEditor, isEditable]);
|
|
276
|
+
if (showEditor && isEditable) {
|
|
277
|
+
return (_jsx(C4Editor, { code: codeValue, setCode: setCodeValue, onClose: onHide }));
|
|
278
|
+
}
|
|
279
|
+
return (_jsx(C4DiagramDisplay, { code: codeValue, nodeKey: nodeKey, isEditable: isEditable, onDoubleClick: () => {
|
|
280
|
+
if (isEditable) {
|
|
281
|
+
setShowEditor(true);
|
|
282
|
+
}
|
|
283
|
+
} }));
|
|
284
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* C4Node - Renders C4 architecture diagrams
|
|
3
|
+
* Uses DecoratorNode pattern similar to MermaidNode
|
|
4
|
+
*/
|
|
5
|
+
import { DecoratorNode, DOMConversionMap, DOMExportOutput, LexicalNode, NodeKey, SerializedLexicalNode, Spread } from 'lexical';
|
|
6
|
+
import type { ManualLayout } from '../c4/types.js';
|
|
7
|
+
export type SerializedC4Node = Spread<{
|
|
8
|
+
code: string;
|
|
9
|
+
manualLayout?: ManualLayout;
|
|
10
|
+
}, SerializedLexicalNode>;
|
|
11
|
+
export declare class C4Node extends DecoratorNode<JSX.Element> {
|
|
12
|
+
__code: string;
|
|
13
|
+
__manualLayout: ManualLayout | undefined;
|
|
14
|
+
static getType(): string;
|
|
15
|
+
static clone(node: C4Node): C4Node;
|
|
16
|
+
constructor(code: string, manualLayout?: ManualLayout, key?: NodeKey);
|
|
17
|
+
static importJSON(serializedNode: SerializedC4Node): C4Node;
|
|
18
|
+
exportJSON(): SerializedC4Node;
|
|
19
|
+
createDOM(): HTMLElement;
|
|
20
|
+
exportDOM(): DOMExportOutput;
|
|
21
|
+
static importDOM(): DOMConversionMap | null;
|
|
22
|
+
updateDOM(): boolean;
|
|
23
|
+
isInline(): boolean;
|
|
24
|
+
getTextContent(): string;
|
|
25
|
+
getCode(): string;
|
|
26
|
+
setCode(code: string): void;
|
|
27
|
+
getManualLayout(): ManualLayout | undefined;
|
|
28
|
+
setManualLayout(layout: ManualLayout | undefined): void;
|
|
29
|
+
decorate(): JSX.Element;
|
|
30
|
+
}
|
|
31
|
+
export declare function $createC4Node(code?: string, manualLayout?: ManualLayout): C4Node;
|
|
32
|
+
export declare function $isC4Node(node: LexicalNode | null | undefined): node is C4Node;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/* eslint-disable react-refresh/only-export-components */
|
|
2
|
+
/**
|
|
3
|
+
* C4Node - Renders C4 architecture diagrams
|
|
4
|
+
* Uses DecoratorNode pattern similar to MermaidNode
|
|
5
|
+
*/
|
|
6
|
+
import { DecoratorNode, $applyNodeReplacement, } from 'lexical';
|
|
7
|
+
import { createElement, lazy, Suspense } from 'react';
|
|
8
|
+
const C4Component = lazy(() => import('./C4Component.js'));
|
|
9
|
+
function $convertC4Element(domNode) {
|
|
10
|
+
const code = domNode.getAttribute('data-lexical-c4');
|
|
11
|
+
if (code) {
|
|
12
|
+
// Decode from base64
|
|
13
|
+
const decodedCode = atob(code);
|
|
14
|
+
const node = $createC4Node(decodedCode);
|
|
15
|
+
return { node };
|
|
16
|
+
}
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
export class C4Node extends DecoratorNode {
|
|
20
|
+
__code;
|
|
21
|
+
__manualLayout;
|
|
22
|
+
static getType() {
|
|
23
|
+
return 'c4';
|
|
24
|
+
}
|
|
25
|
+
static clone(node) {
|
|
26
|
+
const layout = node.__manualLayout
|
|
27
|
+
? { positions: { ...node.__manualLayout.positions } }
|
|
28
|
+
: undefined;
|
|
29
|
+
return new C4Node(node.__code, layout, node.__key);
|
|
30
|
+
}
|
|
31
|
+
constructor(code, manualLayout, key) {
|
|
32
|
+
super(key);
|
|
33
|
+
this.__code = code;
|
|
34
|
+
this.__manualLayout = manualLayout;
|
|
35
|
+
}
|
|
36
|
+
static importJSON(serializedNode) {
|
|
37
|
+
return $createC4Node(serializedNode.code, serializedNode.manualLayout);
|
|
38
|
+
}
|
|
39
|
+
exportJSON() {
|
|
40
|
+
const json = {
|
|
41
|
+
type: 'c4',
|
|
42
|
+
version: 1,
|
|
43
|
+
code: this.getCode(),
|
|
44
|
+
};
|
|
45
|
+
if (this.__manualLayout) {
|
|
46
|
+
json.manualLayout = this.__manualLayout;
|
|
47
|
+
}
|
|
48
|
+
return json;
|
|
49
|
+
}
|
|
50
|
+
createDOM() {
|
|
51
|
+
const element = document.createElement('div');
|
|
52
|
+
element.className = 'editor-c4';
|
|
53
|
+
return element;
|
|
54
|
+
}
|
|
55
|
+
exportDOM() {
|
|
56
|
+
const element = document.createElement('div');
|
|
57
|
+
// Encode as base64 to avoid issues with special characters
|
|
58
|
+
element.setAttribute('data-lexical-c4', btoa(this.__code));
|
|
59
|
+
element.className = 'c4-export';
|
|
60
|
+
element.textContent = this.__code;
|
|
61
|
+
return { element };
|
|
62
|
+
}
|
|
63
|
+
static importDOM() {
|
|
64
|
+
return {
|
|
65
|
+
div: (domNode) => {
|
|
66
|
+
if (!domNode.hasAttribute('data-lexical-c4')) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
return {
|
|
70
|
+
conversion: $convertC4Element,
|
|
71
|
+
priority: 2,
|
|
72
|
+
};
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
updateDOM() {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
isInline() {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
getTextContent() {
|
|
83
|
+
return this.__code;
|
|
84
|
+
}
|
|
85
|
+
getCode() {
|
|
86
|
+
return this.__code;
|
|
87
|
+
}
|
|
88
|
+
setCode(code) {
|
|
89
|
+
const writable = this.getWritable();
|
|
90
|
+
writable.__code = code;
|
|
91
|
+
}
|
|
92
|
+
getManualLayout() {
|
|
93
|
+
return this.__manualLayout;
|
|
94
|
+
}
|
|
95
|
+
setManualLayout(layout) {
|
|
96
|
+
const writable = this.getWritable();
|
|
97
|
+
writable.__manualLayout = layout;
|
|
98
|
+
}
|
|
99
|
+
decorate() {
|
|
100
|
+
return createElement(Suspense, { fallback: createElement('div', { className: 'c4-loading' }, 'Loading diagram...') }, createElement(C4Component, {
|
|
101
|
+
code: this.__code,
|
|
102
|
+
nodeKey: this.__key,
|
|
103
|
+
}));
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
export function $createC4Node(code = '', manualLayout) {
|
|
107
|
+
const c4Node = new C4Node(code, manualLayout);
|
|
108
|
+
return $applyNodeReplacement(c4Node);
|
|
109
|
+
}
|
|
110
|
+
export function $isC4Node(node) {
|
|
111
|
+
return node instanceof C4Node;
|
|
112
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { DOMConversionMap, DOMExportOutput, EditorConfig, ElementNode, LexicalNode, NodeKey, SerializedElementNode, Spread } from 'lexical';
|
|
2
|
+
export type CalloutType = 'note' | 'tip' | 'warning' | 'important' | 'caution';
|
|
3
|
+
export type SerializedCalloutNode = Spread<{
|
|
4
|
+
calloutType: CalloutType;
|
|
5
|
+
}, SerializedElementNode>;
|
|
6
|
+
export declare class CalloutNode extends ElementNode {
|
|
7
|
+
__calloutType: CalloutType;
|
|
8
|
+
static getType(): string;
|
|
9
|
+
static clone(node: CalloutNode): CalloutNode;
|
|
10
|
+
constructor(calloutType: CalloutType, key?: NodeKey);
|
|
11
|
+
getCalloutType(): CalloutType;
|
|
12
|
+
setCalloutType(calloutType: CalloutType): void;
|
|
13
|
+
createDOM(config: EditorConfig): HTMLElement;
|
|
14
|
+
updateDOM(prevNode: CalloutNode, dom: HTMLElement): boolean;
|
|
15
|
+
static importDOM(): DOMConversionMap | null;
|
|
16
|
+
exportDOM(): DOMExportOutput;
|
|
17
|
+
static importJSON(serializedNode: SerializedCalloutNode): CalloutNode;
|
|
18
|
+
exportJSON(): SerializedCalloutNode;
|
|
19
|
+
canBeEmpty(): boolean;
|
|
20
|
+
isShadowRoot(): boolean;
|
|
21
|
+
}
|
|
22
|
+
export declare function $createCalloutNode(calloutType: CalloutType, content?: string): CalloutNode;
|
|
23
|
+
export declare function $isCalloutNode(node: LexicalNode | null | undefined): node is CalloutNode;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { $createParagraphNode, $createTextNode, ElementNode, } from 'lexical';
|
|
2
|
+
export class CalloutNode extends ElementNode {
|
|
3
|
+
__calloutType;
|
|
4
|
+
static getType() {
|
|
5
|
+
return 'callout';
|
|
6
|
+
}
|
|
7
|
+
static clone(node) {
|
|
8
|
+
return new CalloutNode(node.__calloutType, node.__key);
|
|
9
|
+
}
|
|
10
|
+
constructor(calloutType, key) {
|
|
11
|
+
super(key);
|
|
12
|
+
this.__calloutType = calloutType;
|
|
13
|
+
}
|
|
14
|
+
getCalloutType() {
|
|
15
|
+
return this.__calloutType;
|
|
16
|
+
}
|
|
17
|
+
setCalloutType(calloutType) {
|
|
18
|
+
const writable = this.getWritable();
|
|
19
|
+
writable.__calloutType = calloutType;
|
|
20
|
+
}
|
|
21
|
+
createDOM(config) {
|
|
22
|
+
void config;
|
|
23
|
+
const element = document.createElement('div');
|
|
24
|
+
element.className = `callout callout-${this.__calloutType}`;
|
|
25
|
+
element.setAttribute('data-callout-type', this.__calloutType);
|
|
26
|
+
return element;
|
|
27
|
+
}
|
|
28
|
+
updateDOM(prevNode, dom) {
|
|
29
|
+
if (prevNode.__calloutType !== this.__calloutType) {
|
|
30
|
+
dom.className = `callout callout-${this.__calloutType}`;
|
|
31
|
+
dom.setAttribute('data-callout-type', this.__calloutType);
|
|
32
|
+
}
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
static importDOM() {
|
|
36
|
+
return {
|
|
37
|
+
div: (domNode) => {
|
|
38
|
+
if (domNode.classList.contains('callout')) {
|
|
39
|
+
return {
|
|
40
|
+
conversion: convertCalloutElement,
|
|
41
|
+
priority: 1,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
exportDOM() {
|
|
49
|
+
const element = document.createElement('div');
|
|
50
|
+
element.className = `callout callout-${this.__calloutType}`;
|
|
51
|
+
element.setAttribute('data-callout-type', this.__calloutType);
|
|
52
|
+
return { element };
|
|
53
|
+
}
|
|
54
|
+
static importJSON(serializedNode) {
|
|
55
|
+
void serializedNode;
|
|
56
|
+
const node = $createCalloutNode(serializedNode.calloutType);
|
|
57
|
+
return node;
|
|
58
|
+
}
|
|
59
|
+
exportJSON() {
|
|
60
|
+
return {
|
|
61
|
+
...super.exportJSON(),
|
|
62
|
+
type: 'callout',
|
|
63
|
+
calloutType: this.__calloutType,
|
|
64
|
+
version: 1,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
// Allow block-level content inside callouts
|
|
68
|
+
canBeEmpty() {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
isShadowRoot() {
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
function convertCalloutElement(domNode) {
|
|
76
|
+
const calloutType = (domNode.getAttribute('data-callout-type') || 'note');
|
|
77
|
+
const node = $createCalloutNode(calloutType);
|
|
78
|
+
return { node };
|
|
79
|
+
}
|
|
80
|
+
export function $createCalloutNode(calloutType, content) {
|
|
81
|
+
const node = new CalloutNode(calloutType);
|
|
82
|
+
// If content is provided, create a paragraph with text inside
|
|
83
|
+
if (content !== undefined) {
|
|
84
|
+
const paragraph = $createParagraphNode();
|
|
85
|
+
if (content) {
|
|
86
|
+
paragraph.append($createTextNode(content));
|
|
87
|
+
}
|
|
88
|
+
node.append(paragraph);
|
|
89
|
+
}
|
|
90
|
+
return node;
|
|
91
|
+
}
|
|
92
|
+
export function $isCalloutNode(node) {
|
|
93
|
+
return node instanceof CalloutNode;
|
|
94
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { LinkNode, SerializedLinkNode } from '@lexical/link';
|
|
2
|
+
import { DOMConversionMap, EditorConfig, LexicalNode } from 'lexical';
|
|
3
|
+
export type SerializedCustomLinkNode = SerializedLinkNode & {
|
|
4
|
+
wikiAliasState?: 'empty';
|
|
5
|
+
wikiLinkOrigin?: true;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* CustomLinkNode - Extends Lexical's LinkNode to prevent VS Code webview link interception
|
|
9
|
+
*
|
|
10
|
+
* The standard LinkNode renders `<a href="...">` which VS Code webviews intercept and
|
|
11
|
+
* open automatically on click. This custom node renders `<a data-href="...">` instead,
|
|
12
|
+
* allowing us to control navigation via JavaScript (Cmd+click to open).
|
|
13
|
+
*/
|
|
14
|
+
export declare class CustomLinkNode extends LinkNode {
|
|
15
|
+
/** @internal */
|
|
16
|
+
__wikiAliasState: 'empty' | null;
|
|
17
|
+
/**
|
|
18
|
+
* Whether this link was parsed from genuine `[[target]]` / `[[target|alias]]`
|
|
19
|
+
* wiki-link syntax, as opposed to a standard `[text](url)` link whose URL
|
|
20
|
+
* merely looks wiki-link-shaped. Export (`convertLinkNode` in
|
|
21
|
+
* `lexicalToMdast.ts`) always promotes a node with this flag set back to
|
|
22
|
+
* wiki-link syntax, regardless of `wikiLinkPromotionMode` — an opted-out
|
|
23
|
+
* host still must not corrupt a document's existing wiki-links (liminis#951).
|
|
24
|
+
* @internal
|
|
25
|
+
*/
|
|
26
|
+
__wikiLinkOrigin: boolean;
|
|
27
|
+
constructor(url: string, attributes?: {
|
|
28
|
+
rel?: null | string;
|
|
29
|
+
target?: null | string;
|
|
30
|
+
title?: null | string;
|
|
31
|
+
}, key?: string);
|
|
32
|
+
static getType(): string;
|
|
33
|
+
static clone(node: CustomLinkNode): CustomLinkNode;
|
|
34
|
+
createDOM(config: EditorConfig): HTMLAnchorElement;
|
|
35
|
+
/**
|
|
36
|
+
* Check if this link is a wiki-link (internal markdown file)
|
|
37
|
+
*/
|
|
38
|
+
isWikiLink(): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Check if this link is an external link (http/https/mailto)
|
|
41
|
+
*/
|
|
42
|
+
isExternalLink(): boolean;
|
|
43
|
+
updateDOM(prevNode: CustomLinkNode, anchor: HTMLAnchorElement, config: EditorConfig): boolean;
|
|
44
|
+
static importDOM(): DOMConversionMap | null;
|
|
45
|
+
static importJSON(serializedNode: SerializedCustomLinkNode): CustomLinkNode;
|
|
46
|
+
exportJSON(): SerializedCustomLinkNode;
|
|
47
|
+
setWikiAliasState(state: 'empty' | null): void;
|
|
48
|
+
getWikiAliasState(): 'empty' | null;
|
|
49
|
+
setWikiLinkOrigin(origin: boolean): void;
|
|
50
|
+
getWikiLinkOrigin(): boolean;
|
|
51
|
+
}
|
|
52
|
+
export declare function $createCustomLinkNode(url: string, attributes?: {
|
|
53
|
+
rel?: null | string;
|
|
54
|
+
target?: null | string;
|
|
55
|
+
title?: null | string;
|
|
56
|
+
}): CustomLinkNode;
|
|
57
|
+
export declare function $isCustomLinkNode(node: LexicalNode | null | undefined): node is CustomLinkNode;
|