@jotx-labs/editor 2.4.130
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bridge/BridgeContext.d.ts +14 -0
- package/dist/bridge/BridgeContext.d.ts.map +1 -0
- package/dist/bridge/BridgeContext.js +20 -0
- package/dist/bridge/BridgeContext.js.map +1 -0
- package/dist/bridge/bridge-utils.d.ts +24 -0
- package/dist/bridge/bridge-utils.d.ts.map +1 -0
- package/dist/bridge/bridge-utils.js +77 -0
- package/dist/bridge/bridge-utils.js.map +1 -0
- package/dist/bridge/types.d.ts +34 -0
- package/dist/bridge/types.d.ts.map +1 -0
- package/dist/bridge/types.js +27 -0
- package/dist/bridge/types.js.map +1 -0
- package/dist/bridge/vscode-api.d.ts +13 -0
- package/dist/bridge/vscode-api.d.ts.map +1 -0
- package/dist/bridge/vscode-api.js +27 -0
- package/dist/bridge/vscode-api.js.map +1 -0
- package/dist/components/AttachBlockNodeView.d.ts +2 -0
- package/dist/components/AttachBlockNodeView.d.ts.map +1 -0
- package/dist/components/AttachBlockNodeView.js +37 -0
- package/dist/components/AttachBlockNodeView.js.map +1 -0
- package/dist/components/BlockMenu.d.ts +11 -0
- package/dist/components/BlockMenu.d.ts.map +1 -0
- package/dist/components/BlockMenu.js +344 -0
- package/dist/components/BlockMenu.js.map +1 -0
- package/dist/components/ButtonNodeView.d.ts +17 -0
- package/dist/components/ButtonNodeView.d.ts.map +1 -0
- package/dist/components/ButtonNodeView.js +55 -0
- package/dist/components/ButtonNodeView.js.map +1 -0
- package/dist/components/CardNodeView.d.ts +18 -0
- package/dist/components/CardNodeView.d.ts.map +1 -0
- package/dist/components/CardNodeView.js +46 -0
- package/dist/components/CardNodeView.js.map +1 -0
- package/dist/components/ChartNodeView.d.ts +4 -0
- package/dist/components/ChartNodeView.d.ts.map +1 -0
- package/dist/components/ChartNodeView.js +247 -0
- package/dist/components/ChartNodeView.js.map +1 -0
- package/dist/components/CodeBlockNodeView.d.ts +4 -0
- package/dist/components/CodeBlockNodeView.d.ts.map +1 -0
- package/dist/components/CodeBlockNodeView.js +105 -0
- package/dist/components/CodeBlockNodeView.js.map +1 -0
- package/dist/components/CodeReferenceNodeView.d.ts +4 -0
- package/dist/components/CodeReferenceNodeView.d.ts.map +1 -0
- package/dist/components/CodeReferenceNodeView.js +71 -0
- package/dist/components/CodeReferenceNodeView.js.map +1 -0
- package/dist/components/DateTimeNodeView.d.ts +3 -0
- package/dist/components/DateTimeNodeView.d.ts.map +1 -0
- package/dist/components/DateTimeNodeView.js +55 -0
- package/dist/components/DateTimeNodeView.js.map +1 -0
- package/dist/components/EditorRibbon.d.ts +13 -0
- package/dist/components/EditorRibbon.d.ts.map +1 -0
- package/dist/components/EditorRibbon.js +12 -0
- package/dist/components/EditorRibbon.js.map +1 -0
- package/dist/components/FloatImageBlockNodeView.d.ts +6 -0
- package/dist/components/FloatImageBlockNodeView.d.ts.map +1 -0
- package/dist/components/FloatImageBlockNodeView.js +96 -0
- package/dist/components/FloatImageBlockNodeView.js.map +1 -0
- package/dist/components/GridCardNodeView.d.ts +13 -0
- package/dist/components/GridCardNodeView.d.ts.map +1 -0
- package/dist/components/GridCardNodeView.js +31 -0
- package/dist/components/GridCardNodeView.js.map +1 -0
- package/dist/components/ImageBlockNodeView.d.ts +7 -0
- package/dist/components/ImageBlockNodeView.d.ts.map +1 -0
- package/dist/components/ImageBlockNodeView.js +132 -0
- package/dist/components/ImageBlockNodeView.js.map +1 -0
- package/dist/components/ImageToolbar.d.ts +6 -0
- package/dist/components/ImageToolbar.d.ts.map +1 -0
- package/dist/components/ImageToolbar.js +67 -0
- package/dist/components/ImageToolbar.js.map +1 -0
- package/dist/components/JotxEditor.d.ts +17 -0
- package/dist/components/JotxEditor.d.ts.map +1 -0
- package/dist/components/JotxEditor.js +1121 -0
- package/dist/components/JotxEditor.js.map +1 -0
- package/dist/components/JotxLinkNodeView.d.ts +4 -0
- package/dist/components/JotxLinkNodeView.d.ts.map +1 -0
- package/dist/components/JotxLinkNodeView.js +123 -0
- package/dist/components/JotxLinkNodeView.js.map +1 -0
- package/dist/components/LinkDialog.d.ts +14 -0
- package/dist/components/LinkDialog.d.ts.map +1 -0
- package/dist/components/LinkDialog.js +33 -0
- package/dist/components/LinkDialog.js.map +1 -0
- package/dist/components/MathNodeView.d.ts +3 -0
- package/dist/components/MathNodeView.d.ts.map +1 -0
- package/dist/components/MathNodeView.js +67 -0
- package/dist/components/MathNodeView.js.map +1 -0
- package/dist/components/MermaidNodeView.d.ts +4 -0
- package/dist/components/MermaidNodeView.d.ts.map +1 -0
- package/dist/components/MermaidNodeView.js +442 -0
- package/dist/components/MermaidNodeView.js.map +1 -0
- package/dist/components/NodePickerDialog.d.ts +12 -0
- package/dist/components/NodePickerDialog.d.ts.map +1 -0
- package/dist/components/NodePickerDialog.js +90 -0
- package/dist/components/NodePickerDialog.js.map +1 -0
- package/dist/components/ReadonlyBlockRenderer.d.ts +13 -0
- package/dist/components/ReadonlyBlockRenderer.d.ts.map +1 -0
- package/dist/components/ReadonlyBlockRenderer.js +78 -0
- package/dist/components/ReadonlyBlockRenderer.js.map +1 -0
- package/dist/components/ReadonlyMermaid.d.ts +10 -0
- package/dist/components/ReadonlyMermaid.d.ts.map +1 -0
- package/dist/components/ReadonlyMermaid.js +70 -0
- package/dist/components/ReadonlyMermaid.js.map +1 -0
- package/dist/components/SearchBar.d.ts +16 -0
- package/dist/components/SearchBar.d.ts.map +1 -0
- package/dist/components/SearchBar.js +52 -0
- package/dist/components/SearchBar.js.map +1 -0
- package/dist/components/SectionNodeView.d.ts +4 -0
- package/dist/components/SectionNodeView.d.ts.map +1 -0
- package/dist/components/SectionNodeView.js +39 -0
- package/dist/components/SectionNodeView.js.map +1 -0
- package/dist/components/SlashMenu.d.ts +21 -0
- package/dist/components/SlashMenu.d.ts.map +1 -0
- package/dist/components/SlashMenu.js +356 -0
- package/dist/components/SlashMenu.js.map +1 -0
- package/dist/components/TableToolbar.d.ts +10 -0
- package/dist/components/TableToolbar.d.ts.map +1 -0
- package/dist/components/TableToolbar.js +189 -0
- package/dist/components/TableToolbar.js.map +1 -0
- package/dist/components/ToggleNodeView.d.ts +4 -0
- package/dist/components/ToggleNodeView.d.ts.map +1 -0
- package/dist/components/ToggleNodeView.js +39 -0
- package/dist/components/ToggleNodeView.js.map +1 -0
- package/dist/components/UrlInputDialog.d.ts +13 -0
- package/dist/components/UrlInputDialog.d.ts.map +1 -0
- package/dist/components/UrlInputDialog.js +39 -0
- package/dist/components/UrlInputDialog.js.map +1 -0
- package/dist/components/VideoBlockNodeView.d.ts +12 -0
- package/dist/components/VideoBlockNodeView.d.ts.map +1 -0
- package/dist/components/VideoBlockNodeView.js +97 -0
- package/dist/components/VideoBlockNodeView.js.map +1 -0
- package/dist/contexts/NodeManagerContext.d.ts +34 -0
- package/dist/contexts/NodeManagerContext.d.ts.map +1 -0
- package/dist/contexts/NodeManagerContext.js +31 -0
- package/dist/contexts/NodeManagerContext.js.map +1 -0
- package/dist/extensions/AttachNode.d.ts +7 -0
- package/dist/extensions/AttachNode.d.ts.map +1 -0
- package/dist/extensions/AttachNode.js +50 -0
- package/dist/extensions/AttachNode.js.map +1 -0
- package/dist/extensions/BlockOpsExtension.d.ts +17 -0
- package/dist/extensions/BlockOpsExtension.d.ts.map +1 -0
- package/dist/extensions/BlockOpsExtension.js +248 -0
- package/dist/extensions/BlockOpsExtension.js.map +1 -0
- package/dist/extensions/ButtonNode.d.ts +7 -0
- package/dist/extensions/ButtonNode.d.ts.map +1 -0
- package/dist/extensions/ButtonNode.js +59 -0
- package/dist/extensions/ButtonNode.js.map +1 -0
- package/dist/extensions/CalloutActionsExtension.d.ts +3 -0
- package/dist/extensions/CalloutActionsExtension.d.ts.map +1 -0
- package/dist/extensions/CalloutActionsExtension.js +41 -0
- package/dist/extensions/CalloutActionsExtension.js.map +1 -0
- package/dist/extensions/CalloutNode.d.ts +7 -0
- package/dist/extensions/CalloutNode.d.ts.map +1 -0
- package/dist/extensions/CalloutNode.js +48 -0
- package/dist/extensions/CalloutNode.js.map +1 -0
- package/dist/extensions/CardNode.d.ts +7 -0
- package/dist/extensions/CardNode.d.ts.map +1 -0
- package/dist/extensions/CardNode.js +64 -0
- package/dist/extensions/CardNode.js.map +1 -0
- package/dist/extensions/ChartNode.d.ts +3 -0
- package/dist/extensions/ChartNode.d.ts.map +1 -0
- package/dist/extensions/ChartNode.js +60 -0
- package/dist/extensions/ChartNode.js.map +1 -0
- package/dist/extensions/CodeBlockNode.d.ts +7 -0
- package/dist/extensions/CodeBlockNode.d.ts.map +1 -0
- package/dist/extensions/CodeBlockNode.js +57 -0
- package/dist/extensions/CodeBlockNode.js.map +1 -0
- package/dist/extensions/CodeReferenceNode.d.ts +3 -0
- package/dist/extensions/CodeReferenceNode.d.ts.map +1 -0
- package/dist/extensions/CodeReferenceNode.js +46 -0
- package/dist/extensions/CodeReferenceNode.js.map +1 -0
- package/dist/extensions/DateTimeNode.d.ts +3 -0
- package/dist/extensions/DateTimeNode.d.ts.map +1 -0
- package/dist/extensions/DateTimeNode.js +43 -0
- package/dist/extensions/DateTimeNode.js.map +1 -0
- package/dist/extensions/FloatImageBlockNode.d.ts +7 -0
- package/dist/extensions/FloatImageBlockNode.d.ts.map +1 -0
- package/dist/extensions/FloatImageBlockNode.js +73 -0
- package/dist/extensions/FloatImageBlockNode.js.map +1 -0
- package/dist/extensions/GridCardNode.d.ts +7 -0
- package/dist/extensions/GridCardNode.d.ts.map +1 -0
- package/dist/extensions/GridCardNode.js +56 -0
- package/dist/extensions/GridCardNode.js.map +1 -0
- package/dist/extensions/ImageBlockNode.d.ts +7 -0
- package/dist/extensions/ImageBlockNode.d.ts.map +1 -0
- package/dist/extensions/ImageBlockNode.js +76 -0
- package/dist/extensions/ImageBlockNode.js.map +1 -0
- package/dist/extensions/ImageNode.d.ts +10 -0
- package/dist/extensions/ImageNode.d.ts.map +1 -0
- package/dist/extensions/ImageNode.js +67 -0
- package/dist/extensions/ImageNode.js.map +1 -0
- package/dist/extensions/JotxLinkNode.d.ts +3 -0
- package/dist/extensions/JotxLinkNode.d.ts.map +1 -0
- package/dist/extensions/JotxLinkNode.js +43 -0
- package/dist/extensions/JotxLinkNode.js.map +1 -0
- package/dist/extensions/JotxTable.d.ts +9 -0
- package/dist/extensions/JotxTable.d.ts.map +1 -0
- package/dist/extensions/JotxTable.js +40 -0
- package/dist/extensions/JotxTable.js.map +1 -0
- package/dist/extensions/LinkNode.d.ts +7 -0
- package/dist/extensions/LinkNode.d.ts.map +1 -0
- package/dist/extensions/LinkNode.js +54 -0
- package/dist/extensions/LinkNode.js.map +1 -0
- package/dist/extensions/MathNode.d.ts +3 -0
- package/dist/extensions/MathNode.d.ts.map +1 -0
- package/dist/extensions/MathNode.js +61 -0
- package/dist/extensions/MathNode.js.map +1 -0
- package/dist/extensions/MermaidNode.d.ts +3 -0
- package/dist/extensions/MermaidNode.d.ts.map +1 -0
- package/dist/extensions/MermaidNode.js +59 -0
- package/dist/extensions/MermaidNode.js.map +1 -0
- package/dist/extensions/SearchExtension.d.ts +40 -0
- package/dist/extensions/SearchExtension.d.ts.map +1 -0
- package/dist/extensions/SearchExtension.js +186 -0
- package/dist/extensions/SearchExtension.js.map +1 -0
- package/dist/extensions/SectionNode.d.ts +11 -0
- package/dist/extensions/SectionNode.d.ts.map +1 -0
- package/dist/extensions/SectionNode.js +58 -0
- package/dist/extensions/SectionNode.js.map +1 -0
- package/dist/extensions/SlashMenuExtension.d.ts +17 -0
- package/dist/extensions/SlashMenuExtension.d.ts.map +1 -0
- package/dist/extensions/SlashMenuExtension.js +146 -0
- package/dist/extensions/SlashMenuExtension.js.map +1 -0
- package/dist/extensions/SpellCheckExtension.d.ts +14 -0
- package/dist/extensions/SpellCheckExtension.d.ts.map +1 -0
- package/dist/extensions/SpellCheckExtension.js +278 -0
- package/dist/extensions/SpellCheckExtension.js.map +1 -0
- package/dist/extensions/TableFilterExtension.d.ts +12 -0
- package/dist/extensions/TableFilterExtension.d.ts.map +1 -0
- package/dist/extensions/TableFilterExtension.js +75 -0
- package/dist/extensions/TableFilterExtension.js.map +1 -0
- package/dist/extensions/ToggleNode.d.ts +11 -0
- package/dist/extensions/ToggleNode.d.ts.map +1 -0
- package/dist/extensions/ToggleNode.js +58 -0
- package/dist/extensions/ToggleNode.js.map +1 -0
- package/dist/extensions/VideoBlockNode.d.ts +7 -0
- package/dist/extensions/VideoBlockNode.d.ts.map +1 -0
- package/dist/extensions/VideoBlockNode.js +95 -0
- package/dist/extensions/VideoBlockNode.js.map +1 -0
- package/dist/extensions/formatting.d.ts +2 -0
- package/dist/extensions/formatting.d.ts.map +1 -0
- package/dist/extensions/formatting.js +10 -0
- package/dist/extensions/formatting.js.map +1 -0
- package/dist/index.d.ts +61 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +132 -0
- package/dist/index.js.map +1 -0
- package/dist/services/ImageStorage.d.ts +38 -0
- package/dist/services/ImageStorage.d.ts.map +1 -0
- package/dist/services/ImageStorage.js +32 -0
- package/dist/services/ImageStorage.js.map +1 -0
- package/dist/services/SpellCheckService 2.d.ts +50 -0
- package/dist/services/SpellCheckService 2.d.ts.map +1 -0
- package/dist/services/SpellCheckService 2.js +131 -0
- package/dist/services/SpellCheckService 2.js.map +1 -0
- package/dist/services/SpellCheckService.d.ts +50 -0
- package/dist/services/SpellCheckService.d.ts.map +1 -0
- package/dist/services/SpellCheckService.js +131 -0
- package/dist/services/SpellCheckService.js.map +1 -0
- package/dist/utils/logger.d.ts +14 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +25 -0
- package/dist/utils/logger.js.map +1 -0
- package/package.json +56 -0
|
@@ -0,0 +1,1121 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.JotxEditor = JotxEditor;
|
|
7
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
8
|
+
/**
|
|
9
|
+
* JotxEditor - Main Tiptap editor with block support
|
|
10
|
+
* Modular, extensible, beautiful
|
|
11
|
+
*/
|
|
12
|
+
const react_1 = require("react");
|
|
13
|
+
const react_2 = require("@tiptap/react");
|
|
14
|
+
const core_1 = require("@tiptap/core");
|
|
15
|
+
const starter_kit_1 = __importDefault(require("@tiptap/starter-kit"));
|
|
16
|
+
const extension_placeholder_1 = __importDefault(require("@tiptap/extension-placeholder"));
|
|
17
|
+
const extension_task_list_1 = __importDefault(require("@tiptap/extension-task-list"));
|
|
18
|
+
const extension_task_item_1 = __importDefault(require("@tiptap/extension-task-item"));
|
|
19
|
+
const extension_link_1 = __importDefault(require("@tiptap/extension-link"));
|
|
20
|
+
const extension_table_row_1 = __importDefault(require("@tiptap/extension-table-row"));
|
|
21
|
+
const extension_table_cell_1 = __importDefault(require("@tiptap/extension-table-cell"));
|
|
22
|
+
const extension_table_header_1 = __importDefault(require("@tiptap/extension-table-header"));
|
|
23
|
+
const extension_highlight_1 = __importDefault(require("@tiptap/extension-highlight"));
|
|
24
|
+
// Define Global Attribute Extension for Block IDs
|
|
25
|
+
const BlockIdExtension = core_1.Extension.create({
|
|
26
|
+
name: 'blockId',
|
|
27
|
+
addGlobalAttributes() {
|
|
28
|
+
return [
|
|
29
|
+
{
|
|
30
|
+
types: [
|
|
31
|
+
'heading', 'paragraph', 'codeBlock', 'blockquote',
|
|
32
|
+
'imageBlock', 'videoBlock', 'floatImageBlock',
|
|
33
|
+
'math', 'mermaid', 'chart', 'datetime', 'linkCard',
|
|
34
|
+
'callout', 'toggle', 'section', 'jotxlink',
|
|
35
|
+
'bulletList', 'orderedList', 'listItem', 'taskItem', 'taskList',
|
|
36
|
+
'horizontalRule', 'linkBlock', 'attach', 'table', 'tableRow', 'tableCell',
|
|
37
|
+
'codeReference'
|
|
38
|
+
],
|
|
39
|
+
attributes: {
|
|
40
|
+
blockId: {
|
|
41
|
+
default: null,
|
|
42
|
+
keepOnSplit: false,
|
|
43
|
+
renderHTML: attributes => {
|
|
44
|
+
if (!attributes.blockId)
|
|
45
|
+
return {};
|
|
46
|
+
return { 'data-id': attributes.blockId };
|
|
47
|
+
},
|
|
48
|
+
parseHTML: element => element.getAttribute('data-id'),
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
];
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
const react_renderer_1 = require("@jotx-labs/react-renderer");
|
|
56
|
+
const SlashMenuExtension_1 = require("../extensions/SlashMenuExtension");
|
|
57
|
+
const formatting_1 = require("../extensions/formatting");
|
|
58
|
+
const CalloutNode_1 = require("../extensions/CalloutNode");
|
|
59
|
+
const AttachNode_1 = require("../extensions/AttachNode");
|
|
60
|
+
const MermaidNode_1 = require("../extensions/MermaidNode");
|
|
61
|
+
const ChartNode_1 = require("../extensions/ChartNode");
|
|
62
|
+
const JotxLinkNode_1 = require("../extensions/JotxLinkNode");
|
|
63
|
+
const ImageNode_1 = require("../extensions/ImageNode");
|
|
64
|
+
const ImageBlockNode_1 = require("../extensions/ImageBlockNode");
|
|
65
|
+
const vscode_api_1 = require("../bridge/vscode-api");
|
|
66
|
+
const FloatImageBlockNode_1 = require("../extensions/FloatImageBlockNode");
|
|
67
|
+
const VideoBlockNode_1 = require("../extensions/VideoBlockNode");
|
|
68
|
+
const CodeBlockNode_1 = require("../extensions/CodeBlockNode");
|
|
69
|
+
const CodeReferenceNode_1 = require("../extensions/CodeReferenceNode");
|
|
70
|
+
const JotxTable_1 = require("../extensions/JotxTable");
|
|
71
|
+
const TableFilterExtension_1 = require("../extensions/TableFilterExtension");
|
|
72
|
+
const DateTimeNode_1 = require("../extensions/DateTimeNode");
|
|
73
|
+
const MathNode_1 = require("../extensions/MathNode");
|
|
74
|
+
const BlockOpsExtension_1 = require("../extensions/BlockOpsExtension");
|
|
75
|
+
const CalloutActionsExtension_1 = require("../extensions/CalloutActionsExtension");
|
|
76
|
+
const LinkNode_1 = require("../extensions/LinkNode");
|
|
77
|
+
const GridCardNode_1 = require("../extensions/GridCardNode");
|
|
78
|
+
const CardNode_1 = require("../extensions/CardNode");
|
|
79
|
+
const ButtonNode_1 = require("../extensions/ButtonNode");
|
|
80
|
+
const ToggleNode_1 = require("../extensions/ToggleNode");
|
|
81
|
+
const UrlInputDialog_1 = require("./UrlInputDialog");
|
|
82
|
+
const SectionNode_1 = require("../extensions/SectionNode");
|
|
83
|
+
const SlashMenu_1 = require("./SlashMenu");
|
|
84
|
+
require("./JotxEditor.css");
|
|
85
|
+
require("./ImageVideoBlocks.css");
|
|
86
|
+
const bridge_utils_1 = require("../bridge/bridge-utils");
|
|
87
|
+
const logger_1 = require("../utils/logger");
|
|
88
|
+
const LinkDialog_1 = require("./LinkDialog");
|
|
89
|
+
const TableToolbar_1 = require("./TableToolbar");
|
|
90
|
+
const ImageToolbar_1 = require("./ImageToolbar");
|
|
91
|
+
const BlockMenu_1 = require("./BlockMenu");
|
|
92
|
+
const SearchBar_1 = require("./SearchBar");
|
|
93
|
+
const SearchExtension_1 = require("../extensions/SearchExtension");
|
|
94
|
+
const SpellCheckExtension_1 = require("../extensions/SpellCheckExtension");
|
|
95
|
+
const EditorRibbon_1 = require("./EditorRibbon");
|
|
96
|
+
require("./SearchHighlight.css");
|
|
97
|
+
require("./SpellCheck.css");
|
|
98
|
+
function JotxEditor({ documentId, documentType, tiptapDoc, onChange, ribbonExpanded = false }) {
|
|
99
|
+
logger_1.logger.log('🎨 JotxEditor component rendering (jotx 2.0)', { documentId, documentType, tiptapDoc });
|
|
100
|
+
// Debug: Check for jotxlink nodes in the document
|
|
101
|
+
const checkForJotxLink = (content) => {
|
|
102
|
+
let count = 0;
|
|
103
|
+
for (const node of content || []) {
|
|
104
|
+
if (node.type === 'jotxlink')
|
|
105
|
+
count++;
|
|
106
|
+
if (node.content)
|
|
107
|
+
count += checkForJotxLink(node.content);
|
|
108
|
+
}
|
|
109
|
+
return count;
|
|
110
|
+
};
|
|
111
|
+
const jotxLinkCount = tiptapDoc?.content ? checkForJotxLink(tiptapDoc.content) : 0;
|
|
112
|
+
logger_1.logger.log(`🔗 JotxLink nodes in document: ${jotxLinkCount}`);
|
|
113
|
+
const [showSlashMenu, setShowSlashMenu] = (0, react_1.useState)(false);
|
|
114
|
+
const [slashMenuPosition, setSlashMenuPosition] = (0, react_1.useState)({ x: 0, y: 0 });
|
|
115
|
+
const [slashMenuQuery, setSlashMenuQuery] = (0, react_1.useState)('');
|
|
116
|
+
const [calloutToolbar, setCalloutToolbar] = (0, react_1.useState)({ visible: false, x: 0, y: 0, variant: 'info' });
|
|
117
|
+
const [showLinkDialog, setShowLinkDialog] = (0, react_1.useState)(false);
|
|
118
|
+
const [showSearchBar, setShowSearchBar] = (0, react_1.useState)(false);
|
|
119
|
+
const [searchState, setSearchState] = (0, react_1.useState)({ currentMatch: 0, totalMatches: 0 });
|
|
120
|
+
const [showUrlInputDialog, setShowUrlInputDialog] = (0, react_1.useState)(false);
|
|
121
|
+
const [urlInputType, setUrlInputType] = (0, react_1.useState)('image');
|
|
122
|
+
const [showTemplatePicker, setShowTemplatePicker] = (0, react_1.useState)(false);
|
|
123
|
+
const [availableTemplates, setAvailableTemplates] = (0, react_1.useState)([]);
|
|
124
|
+
const [editorContext, setEditorContext] = (0, react_1.useState)('paragraph');
|
|
125
|
+
const isLoadingExternalChange = (0, react_1.useRef)(false);
|
|
126
|
+
logger_1.logger.log('⚙️ Creating Tiptap editor with initial content...');
|
|
127
|
+
logger_1.logger.log('🔍 Registering extensions:', {
|
|
128
|
+
ImageBlockNode: ImageBlockNode_1.ImageBlockNode.name,
|
|
129
|
+
FloatImageBlockNode: FloatImageBlockNode_1.FloatImageBlockNode.name,
|
|
130
|
+
VideoBlockNode: VideoBlockNode_1.VideoBlockNode.name
|
|
131
|
+
});
|
|
132
|
+
// Initialize Generic Adapter
|
|
133
|
+
const genericAdapter = new react_renderer_1.GenericTiptapAdapter();
|
|
134
|
+
const genericExtensions = genericAdapter.getExtensions();
|
|
135
|
+
const editor = (0, react_2.useEditor)({
|
|
136
|
+
content: tiptapDoc || { type: 'doc', content: [] },
|
|
137
|
+
extensions: [
|
|
138
|
+
BlockIdExtension, // Add Custom Global Attribute Extension
|
|
139
|
+
BlockOpsExtension_1.BlockOpsExtension,
|
|
140
|
+
CalloutActionsExtension_1.CalloutActionsExtension,
|
|
141
|
+
SearchExtension_1.SearchExtension,
|
|
142
|
+
starter_kit_1.default.configure({
|
|
143
|
+
codeBlock: false, // Registry (We use CodeBlockNode)
|
|
144
|
+
heading: {},
|
|
145
|
+
bulletList: {},
|
|
146
|
+
orderedList: {},
|
|
147
|
+
listItem: {},
|
|
148
|
+
dropcursor: {
|
|
149
|
+
color: 'var(--vscode-editorCursor-foreground)',
|
|
150
|
+
width: 2,
|
|
151
|
+
},
|
|
152
|
+
gapcursor: false,
|
|
153
|
+
}),
|
|
154
|
+
// Dynamic blocks from Registry
|
|
155
|
+
...genericExtensions,
|
|
156
|
+
// Keep these for now until migrated
|
|
157
|
+
CodeReferenceNode_1.CodeReferenceNode,
|
|
158
|
+
CodeBlockNode_1.CodeBlockNode,
|
|
159
|
+
extension_link_1.default.configure({
|
|
160
|
+
openOnClick: true,
|
|
161
|
+
autolink: true,
|
|
162
|
+
linkOnPaste: false
|
|
163
|
+
}),
|
|
164
|
+
ImageNode_1.ImageNode.configure({
|
|
165
|
+
inline: false,
|
|
166
|
+
allowBase64: true
|
|
167
|
+
}),
|
|
168
|
+
ImageBlockNode_1.ImageBlockNode,
|
|
169
|
+
FloatImageBlockNode_1.FloatImageBlockNode,
|
|
170
|
+
VideoBlockNode_1.VideoBlockNode,
|
|
171
|
+
extension_task_list_1.default.configure({}),
|
|
172
|
+
extension_task_item_1.default.configure({
|
|
173
|
+
nested: true
|
|
174
|
+
}),
|
|
175
|
+
// Custom table nodes so we can persist filter/sort state as data attributes
|
|
176
|
+
JotxTable_1.JotxTable.configure({ resizable: true }),
|
|
177
|
+
extension_table_row_1.default,
|
|
178
|
+
extension_table_header_1.default,
|
|
179
|
+
extension_table_cell_1.default,
|
|
180
|
+
TableFilterExtension_1.TableFilterExtension,
|
|
181
|
+
extension_highlight_1.default.configure({
|
|
182
|
+
multicolor: false
|
|
183
|
+
}),
|
|
184
|
+
CalloutNode_1.CalloutNode,
|
|
185
|
+
AttachNode_1.AttachNode,
|
|
186
|
+
LinkNode_1.LinkNode,
|
|
187
|
+
MermaidNode_1.MermaidNode,
|
|
188
|
+
ChartNode_1.ChartNode,
|
|
189
|
+
JotxLinkNode_1.JotxLinkNode,
|
|
190
|
+
DateTimeNode_1.DateTimeNode,
|
|
191
|
+
MathNode_1.MathNode,
|
|
192
|
+
ToggleNode_1.ToggleNode,
|
|
193
|
+
SectionNode_1.SectionNode,
|
|
194
|
+
GridCardNode_1.GridCardNode,
|
|
195
|
+
CardNode_1.CardNode,
|
|
196
|
+
ButtonNode_1.ButtonNode,
|
|
197
|
+
extension_placeholder_1.default.configure({
|
|
198
|
+
placeholder: ({ node }) => {
|
|
199
|
+
if (node.type.name === 'heading') {
|
|
200
|
+
return 'Heading';
|
|
201
|
+
}
|
|
202
|
+
return 'Type \'/\' for commands...';
|
|
203
|
+
}
|
|
204
|
+
}),
|
|
205
|
+
...formatting_1.FormattingExtensions,
|
|
206
|
+
SlashMenuExtension_1.SlashMenuExtension.configure({
|
|
207
|
+
onOpen: (position, query) => {
|
|
208
|
+
logger_1.logger.log('🎉 SlashMenu onOpen called!', { position, query });
|
|
209
|
+
setShowSlashMenu(true);
|
|
210
|
+
setSlashMenuPosition(position);
|
|
211
|
+
setSlashMenuQuery(query);
|
|
212
|
+
},
|
|
213
|
+
onClose: () => {
|
|
214
|
+
logger_1.logger.log('🚪 SlashMenu onClose called!');
|
|
215
|
+
setShowSlashMenu(false);
|
|
216
|
+
setSlashMenuQuery('');
|
|
217
|
+
},
|
|
218
|
+
onQueryChange: (query) => {
|
|
219
|
+
logger_1.logger.log('📝 SlashMenu onQueryChange:', query);
|
|
220
|
+
setSlashMenuQuery(query);
|
|
221
|
+
}
|
|
222
|
+
}),
|
|
223
|
+
SpellCheckExtension_1.SpellCheckExtension.configure({
|
|
224
|
+
enabled: true,
|
|
225
|
+
debounceMs: 300,
|
|
226
|
+
})
|
|
227
|
+
],
|
|
228
|
+
editorProps: {
|
|
229
|
+
attributes: {
|
|
230
|
+
class: 'jotx-editor-content'
|
|
231
|
+
},
|
|
232
|
+
handlePaste: (_view, event) => {
|
|
233
|
+
try {
|
|
234
|
+
const dt = event.clipboardData;
|
|
235
|
+
if (!dt)
|
|
236
|
+
return false;
|
|
237
|
+
// 2) Check for images first (raster or SVG)
|
|
238
|
+
const items = Array.from(dt.items || []);
|
|
239
|
+
const imgItem = items.find((it) => it.kind === 'file' && it.type.startsWith('image/'));
|
|
240
|
+
if (imgItem) {
|
|
241
|
+
// Image file from clipboard - AUTO CREATE IMAGE BLOCK
|
|
242
|
+
const file = imgItem.getAsFile();
|
|
243
|
+
if (!file)
|
|
244
|
+
return false;
|
|
245
|
+
(async () => {
|
|
246
|
+
logger_1.logger.log('📋 PASTED IMAGE - Auto-creating image block', file);
|
|
247
|
+
// Convert to PNG (preferred) via canvas
|
|
248
|
+
let pngBase64 = null;
|
|
249
|
+
try {
|
|
250
|
+
const bmp = await window.createImageBitmap?.(file);
|
|
251
|
+
if (bmp) {
|
|
252
|
+
const canvas = document.createElement('canvas');
|
|
253
|
+
canvas.width = bmp.width;
|
|
254
|
+
canvas.height = bmp.height;
|
|
255
|
+
const ctx = canvas.getContext('2d');
|
|
256
|
+
ctx?.drawImage(bmp, 0, 0);
|
|
257
|
+
const blob = await new Promise((resolve) => canvas.toBlob(resolve, 'image/png'));
|
|
258
|
+
if (blob) {
|
|
259
|
+
pngBase64 = await new Promise((resolve, reject) => {
|
|
260
|
+
const reader = new FileReader();
|
|
261
|
+
reader.onerror = () => reject(new Error('Failed to read PNG blob'));
|
|
262
|
+
reader.onload = () => {
|
|
263
|
+
const s = (reader.result || '').toString();
|
|
264
|
+
const idx = s.indexOf(',');
|
|
265
|
+
resolve(idx >= 0 ? s.slice(idx + 1) : s);
|
|
266
|
+
};
|
|
267
|
+
reader.readAsDataURL(blob);
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
catch {
|
|
273
|
+
// ignore, fallback below
|
|
274
|
+
}
|
|
275
|
+
const base64 = pngBase64 ||
|
|
276
|
+
(await new Promise((resolve, reject) => {
|
|
277
|
+
const reader = new FileReader();
|
|
278
|
+
reader.onerror = () => reject(new Error('Failed to read image from clipboard'));
|
|
279
|
+
reader.onload = () => {
|
|
280
|
+
const s = (reader.result || '').toString();
|
|
281
|
+
const idx = s.indexOf(',');
|
|
282
|
+
resolve(idx >= 0 ? s.slice(idx + 1) : s);
|
|
283
|
+
};
|
|
284
|
+
reader.readAsDataURL(file);
|
|
285
|
+
}));
|
|
286
|
+
const res = await (0, bridge_utils_1.savePastedImage)({ mime: 'image/png', base64 });
|
|
287
|
+
// AUTO INSERT IMAGE BLOCK (not inline image)
|
|
288
|
+
editor
|
|
289
|
+
?.chain()
|
|
290
|
+
.focus()
|
|
291
|
+
.insertContent([
|
|
292
|
+
{
|
|
293
|
+
type: 'imageBlock',
|
|
294
|
+
attrs: {
|
|
295
|
+
src: res.webviewUri,
|
|
296
|
+
alt: '',
|
|
297
|
+
width: 800,
|
|
298
|
+
height: 'auto',
|
|
299
|
+
align: 'center',
|
|
300
|
+
caption: ''
|
|
301
|
+
}
|
|
302
|
+
},
|
|
303
|
+
{ type: 'paragraph' }
|
|
304
|
+
])
|
|
305
|
+
.run();
|
|
306
|
+
logger_1.logger.log('✅ Image block auto-created!');
|
|
307
|
+
})();
|
|
308
|
+
event.preventDefault();
|
|
309
|
+
return true;
|
|
310
|
+
}
|
|
311
|
+
// 1) SVG paste as text (fallback)
|
|
312
|
+
const text = dt.getData('text/plain') || '';
|
|
313
|
+
if (text.trim().startsWith('<svg')) {
|
|
314
|
+
;
|
|
315
|
+
(async () => {
|
|
316
|
+
const res = await (0, bridge_utils_1.savePastedImage)({ mime: 'image/svg+xml', text });
|
|
317
|
+
editor
|
|
318
|
+
?.chain()
|
|
319
|
+
.focus()
|
|
320
|
+
.insertContent([
|
|
321
|
+
{
|
|
322
|
+
type: 'imageBlock',
|
|
323
|
+
attrs: {
|
|
324
|
+
src: res.webviewUri,
|
|
325
|
+
alt: '',
|
|
326
|
+
width: 800,
|
|
327
|
+
height: 'auto',
|
|
328
|
+
align: 'center',
|
|
329
|
+
caption: ''
|
|
330
|
+
}
|
|
331
|
+
},
|
|
332
|
+
{ type: 'paragraph' }
|
|
333
|
+
])
|
|
334
|
+
.run();
|
|
335
|
+
})();
|
|
336
|
+
event.preventDefault();
|
|
337
|
+
return true;
|
|
338
|
+
}
|
|
339
|
+
// No image found
|
|
340
|
+
return false;
|
|
341
|
+
}
|
|
342
|
+
catch (e) {
|
|
343
|
+
logger_1.logger.warn('paste handler failed', e);
|
|
344
|
+
return false;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
},
|
|
348
|
+
onUpdate: ({ editor }) => {
|
|
349
|
+
// Don't trigger onChange if we're loading an external change
|
|
350
|
+
if (isLoadingExternalChange.current) {
|
|
351
|
+
logger_1.logger.log('⏭️ Skipping onChange - loading external change');
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
// Send Tiptap JSON instead of HTML for proper conversion
|
|
355
|
+
const json = editor.getJSON();
|
|
356
|
+
onChange?.(JSON.stringify(json));
|
|
357
|
+
}
|
|
358
|
+
});
|
|
359
|
+
// Update search state from plugin
|
|
360
|
+
const updateSearchState = () => {
|
|
361
|
+
if (!editor) {
|
|
362
|
+
setSearchState({ currentMatch: 0, totalMatches: 0 });
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
const state = editor.state;
|
|
366
|
+
const pluginState = SearchExtension_1.searchPluginKey.getState(state);
|
|
367
|
+
if (!pluginState) {
|
|
368
|
+
setSearchState({ currentMatch: 0, totalMatches: 0 });
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
setSearchState({
|
|
372
|
+
currentMatch: pluginState.matches.length > 0 ? pluginState.currentIndex + 1 : 0,
|
|
373
|
+
totalMatches: pluginState.matches.length
|
|
374
|
+
});
|
|
375
|
+
};
|
|
376
|
+
// Search handlers
|
|
377
|
+
const handleSearch = (query) => {
|
|
378
|
+
if (!editor)
|
|
379
|
+
return;
|
|
380
|
+
editor.commands.setSearchTerm(query);
|
|
381
|
+
// Update state and scroll after plugin updates
|
|
382
|
+
setTimeout(() => {
|
|
383
|
+
updateSearchState();
|
|
384
|
+
const state = editor.state;
|
|
385
|
+
const pluginState = SearchExtension_1.searchPluginKey.getState(state);
|
|
386
|
+
if (pluginState && pluginState.matches.length > 0) {
|
|
387
|
+
scrollToCurrentMatch();
|
|
388
|
+
}
|
|
389
|
+
}, 10);
|
|
390
|
+
};
|
|
391
|
+
const handleNextMatch = () => {
|
|
392
|
+
if (!editor)
|
|
393
|
+
return;
|
|
394
|
+
editor.commands.nextSearchMatch();
|
|
395
|
+
setTimeout(() => {
|
|
396
|
+
updateSearchState();
|
|
397
|
+
scrollToCurrentMatch();
|
|
398
|
+
}, 10);
|
|
399
|
+
};
|
|
400
|
+
const handlePreviousMatch = () => {
|
|
401
|
+
if (!editor)
|
|
402
|
+
return;
|
|
403
|
+
editor.commands.previousSearchMatch();
|
|
404
|
+
setTimeout(() => {
|
|
405
|
+
updateSearchState();
|
|
406
|
+
scrollToCurrentMatch();
|
|
407
|
+
}, 10);
|
|
408
|
+
};
|
|
409
|
+
const handleCloseSearch = () => {
|
|
410
|
+
if (!editor)
|
|
411
|
+
return;
|
|
412
|
+
editor.commands.clearSearch();
|
|
413
|
+
setShowSearchBar(false);
|
|
414
|
+
setSearchState({ currentMatch: 0, totalMatches: 0 });
|
|
415
|
+
};
|
|
416
|
+
const scrollToCurrentMatch = () => {
|
|
417
|
+
if (!editor)
|
|
418
|
+
return;
|
|
419
|
+
const state = editor.state;
|
|
420
|
+
const pluginState = SearchExtension_1.searchPluginKey.getState(state);
|
|
421
|
+
if (!pluginState || pluginState.matches.length === 0)
|
|
422
|
+
return;
|
|
423
|
+
const currentMatch = pluginState.matches[pluginState.currentIndex];
|
|
424
|
+
if (!currentMatch)
|
|
425
|
+
return;
|
|
426
|
+
try {
|
|
427
|
+
// Find the DOM node at the current match position
|
|
428
|
+
const view = editor.view;
|
|
429
|
+
const domAtPos = view.domAtPos(currentMatch.from);
|
|
430
|
+
if (domAtPos.node) {
|
|
431
|
+
// Get the element (either the node itself or its parent if it's a text node)
|
|
432
|
+
const element = domAtPos.node.nodeType === Node.TEXT_NODE
|
|
433
|
+
? domAtPos.node.parentElement
|
|
434
|
+
: domAtPos.node;
|
|
435
|
+
if (element && element instanceof HTMLElement) {
|
|
436
|
+
// Scroll the element into view with smooth behavior
|
|
437
|
+
element.scrollIntoView({
|
|
438
|
+
behavior: 'smooth',
|
|
439
|
+
block: 'center',
|
|
440
|
+
inline: 'nearest'
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
catch (error) {
|
|
446
|
+
logger_1.logger.warn('Failed to scroll to match:', error);
|
|
447
|
+
}
|
|
448
|
+
};
|
|
449
|
+
// Keyboard shortcuts for search
|
|
450
|
+
(0, react_1.useEffect)(() => {
|
|
451
|
+
const handleKeyDown = (e) => {
|
|
452
|
+
// Cmd/Ctrl+F to open search
|
|
453
|
+
if ((e.metaKey || e.ctrlKey) && e.key === 'f') {
|
|
454
|
+
e.preventDefault();
|
|
455
|
+
setShowSearchBar(true);
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
// Escape to close search (only if search is open)
|
|
459
|
+
if (showSearchBar && e.key === 'Escape') {
|
|
460
|
+
e.preventDefault();
|
|
461
|
+
e.stopPropagation();
|
|
462
|
+
handleCloseSearch();
|
|
463
|
+
return;
|
|
464
|
+
}
|
|
465
|
+
};
|
|
466
|
+
window.addEventListener('keydown', handleKeyDown, true); // Use capture phase
|
|
467
|
+
return () => window.removeEventListener('keydown', handleKeyDown, true);
|
|
468
|
+
}, [showSearchBar, editor]);
|
|
469
|
+
(0, react_1.useEffect)(() => {
|
|
470
|
+
logger_1.logger.log('✅ Editor initialized:', !!editor);
|
|
471
|
+
if (editor && !editor.isDestroyed) {
|
|
472
|
+
logger_1.logger.log('🔍 Registered node types in schema:', Object.keys(editor.schema.nodes));
|
|
473
|
+
logger_1.logger.log('🔍 imageBlock node:', editor.schema.nodes.imageBlock);
|
|
474
|
+
logger_1.logger.log('🔍 floatImageBlock node:', editor.schema.nodes.floatImageBlock);
|
|
475
|
+
logger_1.logger.log('🔍 videoBlock node:', editor.schema.nodes.videoBlock);
|
|
476
|
+
const currentContent = JSON.stringify(editor.getJSON());
|
|
477
|
+
const newContent = JSON.stringify(tiptapDoc);
|
|
478
|
+
logger_1.logger.log('📄 Editor content update check:');
|
|
479
|
+
logger_1.logger.log(' - New tiptapDoc:', newContent?.substring(0, 200));
|
|
480
|
+
logger_1.logger.log(' - Current content:', currentContent?.substring(0, 200));
|
|
481
|
+
logger_1.logger.log(' - Are different?', currentContent !== newContent);
|
|
482
|
+
if (currentContent !== newContent) {
|
|
483
|
+
logger_1.logger.log(' ➡️ Setting content in Tiptap from external change');
|
|
484
|
+
isLoadingExternalChange.current = true;
|
|
485
|
+
// Update content without triggering onUpdate callback
|
|
486
|
+
editor.commands.setContent(tiptapDoc || { type: 'doc', content: [] });
|
|
487
|
+
// Reset flag immediately after setContent completes
|
|
488
|
+
setTimeout(() => {
|
|
489
|
+
isLoadingExternalChange.current = false;
|
|
490
|
+
logger_1.logger.log(' ✅ Content set, onChange re-enabled');
|
|
491
|
+
}, 50);
|
|
492
|
+
}
|
|
493
|
+
else {
|
|
494
|
+
logger_1.logger.log(' ⏭️ Content unchanged, skipping');
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
}, [tiptapDoc, editor]);
|
|
498
|
+
const handleSlashCommand = (command) => {
|
|
499
|
+
logger_1.logger.log('⚡ handleSlashCommand:', command);
|
|
500
|
+
if (!editor) {
|
|
501
|
+
logger_1.logger.error('❌ Editor not available!');
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
setShowSlashMenu(false);
|
|
505
|
+
// Delete the "/query" trigger text before inserting the block (Notion-like UX)
|
|
506
|
+
try {
|
|
507
|
+
const pluginState = SlashMenuExtension_1.slashMenuPluginKey.getState(editor.state);
|
|
508
|
+
if (pluginState?.range?.from != null && pluginState?.range?.to != null) {
|
|
509
|
+
editor
|
|
510
|
+
.chain()
|
|
511
|
+
.focus()
|
|
512
|
+
.deleteRange({ from: pluginState.range.from, to: pluginState.range.to })
|
|
513
|
+
.run();
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
catch {
|
|
517
|
+
// non-fatal
|
|
518
|
+
}
|
|
519
|
+
switch (command) {
|
|
520
|
+
case 'heading1':
|
|
521
|
+
logger_1.logger.log('📝 Setting Heading 1');
|
|
522
|
+
editor.chain().focus().setNode('heading', { level: 1 }).run();
|
|
523
|
+
break;
|
|
524
|
+
case 'heading2':
|
|
525
|
+
logger_1.logger.log('📝 Setting Heading 2');
|
|
526
|
+
editor.chain().focus().setNode('heading', { level: 2 }).run();
|
|
527
|
+
break;
|
|
528
|
+
case 'heading3':
|
|
529
|
+
logger_1.logger.log('📝 Setting Heading 3');
|
|
530
|
+
editor.chain().focus().setNode('heading', { level: 3 }).run();
|
|
531
|
+
break;
|
|
532
|
+
case 'paragraph':
|
|
533
|
+
logger_1.logger.log('📝 Setting Paragraph');
|
|
534
|
+
editor.chain().focus().setParagraph().run();
|
|
535
|
+
break;
|
|
536
|
+
case 'bulletList':
|
|
537
|
+
logger_1.logger.log('📝 Setting Bullet List');
|
|
538
|
+
editor.chain().focus().toggleBulletList().run();
|
|
539
|
+
break;
|
|
540
|
+
case 'orderedList':
|
|
541
|
+
logger_1.logger.log('📝 Setting Ordered List');
|
|
542
|
+
editor.chain().focus().toggleOrderedList().run();
|
|
543
|
+
break;
|
|
544
|
+
case 'checklist':
|
|
545
|
+
logger_1.logger.log('📝 Setting Checklist');
|
|
546
|
+
editor.chain().focus().toggleTaskList().run();
|
|
547
|
+
break;
|
|
548
|
+
case 'blockquote':
|
|
549
|
+
logger_1.logger.log('📝 Setting Blockquote');
|
|
550
|
+
editor.chain().focus().toggleBlockquote().run();
|
|
551
|
+
break;
|
|
552
|
+
case 'codeBlock':
|
|
553
|
+
logger_1.logger.log('📝 Setting Code Block');
|
|
554
|
+
editor.chain().focus().setNode('codeBlock', { language: 'plaintext' }).run();
|
|
555
|
+
break;
|
|
556
|
+
case 'divider':
|
|
557
|
+
logger_1.logger.log('📝 Setting Divider');
|
|
558
|
+
editor.chain().focus().setHorizontalRule().run();
|
|
559
|
+
// Force update to ensure persistence
|
|
560
|
+
setTimeout(() => editor.commands.focus(), 10);
|
|
561
|
+
break;
|
|
562
|
+
case 'callout': {
|
|
563
|
+
editor.chain().focus().wrapIn('callout', { variant: 'info' }).run();
|
|
564
|
+
break;
|
|
565
|
+
}
|
|
566
|
+
case 'image': {
|
|
567
|
+
setUrlInputType('image');
|
|
568
|
+
setShowUrlInputDialog(true);
|
|
569
|
+
break;
|
|
570
|
+
}
|
|
571
|
+
case 'link': {
|
|
572
|
+
setShowLinkDialog(true);
|
|
573
|
+
break;
|
|
574
|
+
}
|
|
575
|
+
case 'attach': {
|
|
576
|
+
;
|
|
577
|
+
(async () => {
|
|
578
|
+
const picked = await (0, bridge_utils_1.pickAttachmentFile)();
|
|
579
|
+
if (!picked)
|
|
580
|
+
return;
|
|
581
|
+
editor
|
|
582
|
+
.chain()
|
|
583
|
+
.focus()
|
|
584
|
+
.insertContent([
|
|
585
|
+
{
|
|
586
|
+
type: 'attach',
|
|
587
|
+
attrs: { path: picked.path },
|
|
588
|
+
content: [{ type: 'paragraph', content: [{ type: 'text', text: picked.name }] }]
|
|
589
|
+
},
|
|
590
|
+
{ type: 'paragraph' }
|
|
591
|
+
])
|
|
592
|
+
.run();
|
|
593
|
+
})();
|
|
594
|
+
break;
|
|
595
|
+
}
|
|
596
|
+
case 'table': {
|
|
597
|
+
editor.chain().focus().insertTable({ rows: 3, cols: 3, withHeaderRow: true }).run();
|
|
598
|
+
break;
|
|
599
|
+
}
|
|
600
|
+
case 'mermaid': {
|
|
601
|
+
editor
|
|
602
|
+
.chain()
|
|
603
|
+
.focus()
|
|
604
|
+
.insertContent([
|
|
605
|
+
{
|
|
606
|
+
type: 'mermaid',
|
|
607
|
+
attrs: {
|
|
608
|
+
src: 'flowchart TD\n A[Start] --> B{Decision}\n B -->|Yes| C[OK]\n B -->|No| D[Fix]\n'
|
|
609
|
+
}
|
|
610
|
+
},
|
|
611
|
+
{ type: 'paragraph' }
|
|
612
|
+
])
|
|
613
|
+
.run();
|
|
614
|
+
break;
|
|
615
|
+
}
|
|
616
|
+
case 'chart': {
|
|
617
|
+
const json = JSON.stringify({ labels: ['Jan', 'Feb', 'Mar', 'Apr'], datasets: [{ label: 'Events', data: [12, 19, 8, 15] }] }, null, 2);
|
|
618
|
+
editor.chain().focus().insertContent([{ type: 'chart', attrs: { chartType: 'bar', json } }, { type: 'paragraph' }]).run();
|
|
619
|
+
break;
|
|
620
|
+
}
|
|
621
|
+
case 'datetime': {
|
|
622
|
+
editor
|
|
623
|
+
.chain()
|
|
624
|
+
.focus()
|
|
625
|
+
.insertContent([{ type: 'datetime', attrs: { mode: 'datetime', value: '' } }, { type: 'paragraph' }])
|
|
626
|
+
.run();
|
|
627
|
+
break;
|
|
628
|
+
}
|
|
629
|
+
case 'math': {
|
|
630
|
+
editor.chain().focus().insertContent([{ type: 'math', attrs: { src: '', display: 'block' } }, { type: 'paragraph' }]).run();
|
|
631
|
+
break;
|
|
632
|
+
}
|
|
633
|
+
case 'jotxlink': {
|
|
634
|
+
editor.chain().focus().insertContent([{ type: 'jotxlink', attrs: { refType: '', refId: '' } }, { type: 'paragraph' }]).run();
|
|
635
|
+
break;
|
|
636
|
+
}
|
|
637
|
+
case 'toggle': {
|
|
638
|
+
editor
|
|
639
|
+
.chain()
|
|
640
|
+
.focus()
|
|
641
|
+
.insertContent([
|
|
642
|
+
{
|
|
643
|
+
type: 'toggle',
|
|
644
|
+
attrs: { title: 'Toggle', collapsed: false },
|
|
645
|
+
content: [{ type: 'paragraph' }]
|
|
646
|
+
},
|
|
647
|
+
{ type: 'paragraph' }
|
|
648
|
+
])
|
|
649
|
+
.run();
|
|
650
|
+
break;
|
|
651
|
+
}
|
|
652
|
+
case 'section': {
|
|
653
|
+
editor
|
|
654
|
+
.chain()
|
|
655
|
+
.focus()
|
|
656
|
+
.insertContent([
|
|
657
|
+
{
|
|
658
|
+
type: 'section',
|
|
659
|
+
attrs: { title: 'Section', collapsed: false },
|
|
660
|
+
content: [{ type: 'paragraph' }]
|
|
661
|
+
},
|
|
662
|
+
{ type: 'paragraph' }
|
|
663
|
+
])
|
|
664
|
+
.run();
|
|
665
|
+
break;
|
|
666
|
+
}
|
|
667
|
+
case 'gridcard': {
|
|
668
|
+
editor
|
|
669
|
+
.chain()
|
|
670
|
+
.focus()
|
|
671
|
+
.insertContent([
|
|
672
|
+
{
|
|
673
|
+
type: 'gridcard',
|
|
674
|
+
attrs: { layout: '2x2' },
|
|
675
|
+
content: [
|
|
676
|
+
{ type: 'card', attrs: { title: 'Card 1', value: '', icon: '📝', color: 'teal', link: '' } },
|
|
677
|
+
{ type: 'card', attrs: { title: 'Card 2', value: '', icon: '📊', color: 'blue', link: '' } },
|
|
678
|
+
{ type: 'card', attrs: { title: 'Card 3', value: '', icon: '🚀', color: 'green', link: '' } },
|
|
679
|
+
{ type: 'card', attrs: { title: 'Card 4', value: '', icon: '⚙️', color: 'purple', link: '' } }
|
|
680
|
+
]
|
|
681
|
+
},
|
|
682
|
+
{ type: 'paragraph' }
|
|
683
|
+
])
|
|
684
|
+
.run();
|
|
685
|
+
break;
|
|
686
|
+
}
|
|
687
|
+
case 'button': {
|
|
688
|
+
editor
|
|
689
|
+
.chain()
|
|
690
|
+
.focus()
|
|
691
|
+
.insertContent([
|
|
692
|
+
{ type: 'button', attrs: { label: 'Click Me', link: '', style: 'primary', align: 'left' } },
|
|
693
|
+
{ type: 'paragraph' }
|
|
694
|
+
])
|
|
695
|
+
.run();
|
|
696
|
+
break;
|
|
697
|
+
}
|
|
698
|
+
case 'imageBlock': {
|
|
699
|
+
logger_1.logger.log('📝 Inserting Image Block');
|
|
700
|
+
logger_1.logger.log('🔍 Editor state BEFORE insert:', editor.state.doc.toJSON());
|
|
701
|
+
logger_1.logger.log('🔍 Available node types:', Object.keys(editor.schema.nodes));
|
|
702
|
+
logger_1.logger.log('🔍 ImageBlock node exists?', !!editor.schema.nodes.imageBlock);
|
|
703
|
+
const content = {
|
|
704
|
+
type: 'imageBlock',
|
|
705
|
+
attrs: {
|
|
706
|
+
src: '',
|
|
707
|
+
alt: '',
|
|
708
|
+
width: 800,
|
|
709
|
+
height: 'auto',
|
|
710
|
+
align: 'center',
|
|
711
|
+
caption: ''
|
|
712
|
+
}
|
|
713
|
+
};
|
|
714
|
+
logger_1.logger.log('🔍 Inserting content:', JSON.stringify(content, null, 2));
|
|
715
|
+
try {
|
|
716
|
+
const result = editor
|
|
717
|
+
.chain()
|
|
718
|
+
.focus()
|
|
719
|
+
.insertContent([content, { type: 'paragraph' }])
|
|
720
|
+
.run();
|
|
721
|
+
logger_1.logger.log('✅ insertContent result:', result);
|
|
722
|
+
logger_1.logger.log('🔍 Editor state AFTER insert:', editor.state.doc.toJSON());
|
|
723
|
+
}
|
|
724
|
+
catch (error) {
|
|
725
|
+
logger_1.logger.error('❌ insertContent ERROR:', error);
|
|
726
|
+
}
|
|
727
|
+
break;
|
|
728
|
+
}
|
|
729
|
+
case 'floatImageBlock': {
|
|
730
|
+
logger_1.logger.log('📝 Inserting Float Image Block (CONTAINER)');
|
|
731
|
+
logger_1.logger.log('🔍 FloatImageBlock node exists?', !!editor.schema.nodes.floatImageBlock);
|
|
732
|
+
// Float image is now a CONTAINER with content inside
|
|
733
|
+
const content = {
|
|
734
|
+
type: 'floatImageBlock',
|
|
735
|
+
attrs: {
|
|
736
|
+
src: '',
|
|
737
|
+
alt: '',
|
|
738
|
+
width: 400,
|
|
739
|
+
height: 'auto',
|
|
740
|
+
float: 'left',
|
|
741
|
+
caption: ''
|
|
742
|
+
},
|
|
743
|
+
content: [
|
|
744
|
+
{
|
|
745
|
+
type: 'paragraph'
|
|
746
|
+
}
|
|
747
|
+
]
|
|
748
|
+
};
|
|
749
|
+
logger_1.logger.log('🔍 Inserting content:', JSON.stringify(content, null, 2));
|
|
750
|
+
try {
|
|
751
|
+
const result = editor
|
|
752
|
+
.chain()
|
|
753
|
+
.insertContent([content, { type: 'paragraph' }])
|
|
754
|
+
.run();
|
|
755
|
+
logger_1.logger.log('✅ insertContent result:', result);
|
|
756
|
+
}
|
|
757
|
+
catch (error) {
|
|
758
|
+
logger_1.logger.error('❌ insertContent ERROR:', error);
|
|
759
|
+
}
|
|
760
|
+
break;
|
|
761
|
+
}
|
|
762
|
+
case 'videoBlock': {
|
|
763
|
+
logger_1.logger.log('📝 Inserting Video Block');
|
|
764
|
+
logger_1.logger.log('🔍 VideoBlock node exists?', !!editor.schema.nodes.videoBlock);
|
|
765
|
+
const content = {
|
|
766
|
+
type: 'videoBlock',
|
|
767
|
+
attrs: {
|
|
768
|
+
type: 'youtube',
|
|
769
|
+
url: '',
|
|
770
|
+
src: '',
|
|
771
|
+
title: '',
|
|
772
|
+
width: 800,
|
|
773
|
+
height: 450,
|
|
774
|
+
controls: 'true',
|
|
775
|
+
autoplay: 'false',
|
|
776
|
+
muted: 'false',
|
|
777
|
+
loop: 'false'
|
|
778
|
+
}
|
|
779
|
+
};
|
|
780
|
+
logger_1.logger.log('🔍 Inserting content:', JSON.stringify(content, null, 2));
|
|
781
|
+
try {
|
|
782
|
+
const result = editor
|
|
783
|
+
.chain()
|
|
784
|
+
.focus()
|
|
785
|
+
.insertContent([content, { type: 'paragraph' }])
|
|
786
|
+
.run();
|
|
787
|
+
logger_1.logger.log('✅ insertContent result:', result);
|
|
788
|
+
}
|
|
789
|
+
catch (error) {
|
|
790
|
+
logger_1.logger.error('❌ insertContent ERROR:', error);
|
|
791
|
+
}
|
|
792
|
+
break;
|
|
793
|
+
}
|
|
794
|
+
case 'properties': {
|
|
795
|
+
// Disallow nesting properties/table/headings inside table cells
|
|
796
|
+
if (editor.isActive('table')) {
|
|
797
|
+
return;
|
|
798
|
+
}
|
|
799
|
+
// Insert as a valid ProseMirror table node (NOT raw HTML) so it's editable everywhere.
|
|
800
|
+
// No samples: header + 1 empty row.
|
|
801
|
+
editor
|
|
802
|
+
.chain()
|
|
803
|
+
.focus()
|
|
804
|
+
.insertContent([
|
|
805
|
+
{
|
|
806
|
+
type: 'table',
|
|
807
|
+
content: [
|
|
808
|
+
{
|
|
809
|
+
type: 'tableRow',
|
|
810
|
+
content: [
|
|
811
|
+
{ type: 'tableHeader', content: [{ type: 'paragraph', content: [{ type: 'text', text: 'Key' }] }] },
|
|
812
|
+
{ type: 'tableHeader', content: [{ type: 'paragraph', content: [{ type: 'text', text: 'Value' }] }] },
|
|
813
|
+
{ type: 'tableHeader', content: [{ type: 'paragraph', content: [{ type: 'text', text: 'Type' }] }] }
|
|
814
|
+
]
|
|
815
|
+
},
|
|
816
|
+
{
|
|
817
|
+
type: 'tableRow',
|
|
818
|
+
content: [
|
|
819
|
+
{ type: 'tableCell', content: [{ type: 'paragraph' }] },
|
|
820
|
+
{ type: 'tableCell', content: [{ type: 'paragraph' }] },
|
|
821
|
+
{ type: 'tableCell', content: [{ type: 'paragraph', content: [{ type: 'text', text: 'text' }] }] }
|
|
822
|
+
]
|
|
823
|
+
}
|
|
824
|
+
]
|
|
825
|
+
},
|
|
826
|
+
{ type: 'paragraph' }
|
|
827
|
+
])
|
|
828
|
+
.run();
|
|
829
|
+
break;
|
|
830
|
+
}
|
|
831
|
+
case 'codeReference': {
|
|
832
|
+
editor
|
|
833
|
+
.chain()
|
|
834
|
+
.focus()
|
|
835
|
+
.insertContent([
|
|
836
|
+
{
|
|
837
|
+
type: 'codeReference',
|
|
838
|
+
attrs: { path: '', lines: '', language: '' }
|
|
839
|
+
},
|
|
840
|
+
{ type: 'paragraph' }
|
|
841
|
+
])
|
|
842
|
+
.run();
|
|
843
|
+
break;
|
|
844
|
+
}
|
|
845
|
+
case 'useTemplate': {
|
|
846
|
+
// Request template list from backend
|
|
847
|
+
logger_1.logger.log('🔵 useTemplate clicked - requesting template list from backend');
|
|
848
|
+
const vscode = (0, vscode_api_1.getVSCodeAPI)();
|
|
849
|
+
vscode.postMessage({
|
|
850
|
+
type: 'requestTemplateList'
|
|
851
|
+
});
|
|
852
|
+
logger_1.logger.log('📤 postMessage sent: requestTemplateList');
|
|
853
|
+
break;
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
// CRITICAL: Force trigger save after any block insertion
|
|
857
|
+
// Tiptap's onUpdate may not fire synchronously, causing data loss on close
|
|
858
|
+
setTimeout(() => {
|
|
859
|
+
if (editor) {
|
|
860
|
+
const json = editor.getJSON();
|
|
861
|
+
onChange?.(JSON.stringify(json));
|
|
862
|
+
logger_1.logger.log('🔄 Flushed save after block insertion');
|
|
863
|
+
}
|
|
864
|
+
}, 50);
|
|
865
|
+
};
|
|
866
|
+
const getTableContext = () => {
|
|
867
|
+
if (!editor)
|
|
868
|
+
return { inTableCell: false, inPropertiesTable: false };
|
|
869
|
+
const inTableCell = editor.isActive('table');
|
|
870
|
+
if (!inTableCell)
|
|
871
|
+
return { inTableCell: false, inPropertiesTable: false };
|
|
872
|
+
try {
|
|
873
|
+
const { from } = editor.state.selection;
|
|
874
|
+
const domAt = editor.view.domAtPos(from).node;
|
|
875
|
+
const el = domAt?.nodeType === 1 ? domAt : domAt?.parentElement;
|
|
876
|
+
const table = el?.closest?.('table');
|
|
877
|
+
if (!table)
|
|
878
|
+
return { inTableCell: true, inPropertiesTable: false };
|
|
879
|
+
const ths = Array.from(table.querySelectorAll('th')).slice(0, 3);
|
|
880
|
+
const header = ths.map((t) => (t.textContent || '').trim().toLowerCase());
|
|
881
|
+
const inPropertiesTable = header[0] === 'key' && header[1] === 'value' && header[2] === 'type';
|
|
882
|
+
return { inTableCell: true, inPropertiesTable };
|
|
883
|
+
}
|
|
884
|
+
catch {
|
|
885
|
+
return { inTableCell: true, inPropertiesTable: false };
|
|
886
|
+
}
|
|
887
|
+
};
|
|
888
|
+
const getActiveCalloutVariant = () => {
|
|
889
|
+
if (!editor)
|
|
890
|
+
return null;
|
|
891
|
+
const { $from } = editor.state.selection;
|
|
892
|
+
for (let d = $from.depth; d > 0; d--) {
|
|
893
|
+
const node = $from.node(d);
|
|
894
|
+
if (node.type?.name === 'callout') {
|
|
895
|
+
return node.attrs?.variant || 'info';
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
return null;
|
|
899
|
+
};
|
|
900
|
+
const setCalloutVariant = (variant) => {
|
|
901
|
+
if (!editor)
|
|
902
|
+
return;
|
|
903
|
+
const { $from } = editor.state.selection;
|
|
904
|
+
for (let d = $from.depth; d > 0; d--) {
|
|
905
|
+
const node = $from.node(d);
|
|
906
|
+
if (node.type?.name === 'callout') {
|
|
907
|
+
const pos = $from.before(d);
|
|
908
|
+
const tr = editor.state.tr.setNodeMarkup(pos, undefined, {
|
|
909
|
+
...node.attrs,
|
|
910
|
+
variant
|
|
911
|
+
});
|
|
912
|
+
editor.view.dispatch(tr);
|
|
913
|
+
editor.commands.focus();
|
|
914
|
+
setCalloutToolbar((s) => ({ ...s, variant }));
|
|
915
|
+
return;
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
};
|
|
919
|
+
// Floating callout toolbar (variant picker)
|
|
920
|
+
(0, react_1.useEffect)(() => {
|
|
921
|
+
if (!editor)
|
|
922
|
+
return;
|
|
923
|
+
const update = () => {
|
|
924
|
+
const variant = getActiveCalloutVariant();
|
|
925
|
+
if (!variant) {
|
|
926
|
+
setCalloutToolbar((s) => (s.visible ? { ...s, visible: false } : s));
|
|
927
|
+
return;
|
|
928
|
+
}
|
|
929
|
+
const v = variant;
|
|
930
|
+
const { from } = editor.state.selection;
|
|
931
|
+
const coords = editor.view.coordsAtPos(from);
|
|
932
|
+
const inTable = editor.isActive('table');
|
|
933
|
+
// Position above selection; if inside a table, offset further up so it doesn't overlap table toolbar
|
|
934
|
+
const x = Math.max(12, Math.min(window.innerWidth - 220, coords.left));
|
|
935
|
+
const y = Math.max(12, coords.top - (inTable ? 92 : 48));
|
|
936
|
+
setCalloutToolbar({ visible: true, x, y, variant: v || 'info' });
|
|
937
|
+
};
|
|
938
|
+
update();
|
|
939
|
+
editor.on('selectionUpdate', update);
|
|
940
|
+
editor.on('transaction', update);
|
|
941
|
+
return () => {
|
|
942
|
+
editor.off('selectionUpdate', update);
|
|
943
|
+
editor.off('transaction', update);
|
|
944
|
+
};
|
|
945
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
946
|
+
}, [editor]);
|
|
947
|
+
// Context detection for ribbon toolbar
|
|
948
|
+
(0, react_1.useEffect)(() => {
|
|
949
|
+
if (!editor)
|
|
950
|
+
return;
|
|
951
|
+
const detectContext = () => {
|
|
952
|
+
if (editor.isActive('table')) {
|
|
953
|
+
setEditorContext('table');
|
|
954
|
+
}
|
|
955
|
+
else if (editor.isActive('bulletList') || editor.isActive('orderedList') || editor.isActive('taskList')) {
|
|
956
|
+
setEditorContext('list');
|
|
957
|
+
}
|
|
958
|
+
else if (editor.isActive('mermaid')) {
|
|
959
|
+
setEditorContext('mermaid');
|
|
960
|
+
}
|
|
961
|
+
else if (editor.isActive('chart')) {
|
|
962
|
+
setEditorContext('chart');
|
|
963
|
+
}
|
|
964
|
+
else if (editor.isActive('codeBlock')) {
|
|
965
|
+
setEditorContext('code');
|
|
966
|
+
}
|
|
967
|
+
else if (editor.isActive('math')) {
|
|
968
|
+
setEditorContext('math');
|
|
969
|
+
}
|
|
970
|
+
else if (editor.isActive('callout')) {
|
|
971
|
+
setEditorContext('callout');
|
|
972
|
+
}
|
|
973
|
+
else if (editor.isActive('image') || editor.isActive('imageBlock')) {
|
|
974
|
+
setEditorContext('image');
|
|
975
|
+
}
|
|
976
|
+
else if (editor.isActive('heading')) {
|
|
977
|
+
setEditorContext('heading');
|
|
978
|
+
}
|
|
979
|
+
else {
|
|
980
|
+
setEditorContext('paragraph');
|
|
981
|
+
}
|
|
982
|
+
};
|
|
983
|
+
detectContext();
|
|
984
|
+
editor.on('selectionUpdate', detectContext);
|
|
985
|
+
editor.on('transaction', detectContext);
|
|
986
|
+
return () => {
|
|
987
|
+
editor.off('selectionUpdate', detectContext);
|
|
988
|
+
editor.off('transaction', detectContext);
|
|
989
|
+
};
|
|
990
|
+
}, [editor]);
|
|
991
|
+
// Update search state when editor state changes
|
|
992
|
+
(0, react_1.useEffect)(() => {
|
|
993
|
+
if (!editor || !showSearchBar)
|
|
994
|
+
return;
|
|
995
|
+
const updateHandler = () => {
|
|
996
|
+
updateSearchState();
|
|
997
|
+
};
|
|
998
|
+
editor.on('transaction', updateHandler);
|
|
999
|
+
return () => {
|
|
1000
|
+
editor.off('transaction', updateHandler);
|
|
1001
|
+
};
|
|
1002
|
+
}, [editor, showSearchBar]);
|
|
1003
|
+
// Listen for template list from backend
|
|
1004
|
+
(0, react_1.useEffect)(() => {
|
|
1005
|
+
const handleTemplateList = (event) => {
|
|
1006
|
+
logger_1.logger.log('📥 Received templateList event:', event.detail);
|
|
1007
|
+
const templates = event.detail;
|
|
1008
|
+
logger_1.logger.log('📋 Templates:', templates);
|
|
1009
|
+
setAvailableTemplates(templates);
|
|
1010
|
+
setShowTemplatePicker(true);
|
|
1011
|
+
logger_1.logger.log('✅ Modal should now be visible');
|
|
1012
|
+
};
|
|
1013
|
+
const handleTemplateContent = (event) => {
|
|
1014
|
+
logger_1.logger.log('📥 handleTemplateContent called');
|
|
1015
|
+
logger_1.logger.log('📥 event.detail:', event.detail);
|
|
1016
|
+
const tiptapBlocks = event.detail;
|
|
1017
|
+
logger_1.logger.log('📥 tiptapBlocks:', tiptapBlocks);
|
|
1018
|
+
logger_1.logger.log('📥 tiptapBlocks?.content:', tiptapBlocks?.content);
|
|
1019
|
+
logger_1.logger.log('📥 editor available:', !!editor);
|
|
1020
|
+
if (editor && tiptapBlocks && tiptapBlocks.content) {
|
|
1021
|
+
logger_1.logger.log('📥 Inserting template content:', tiptapBlocks.content.length, 'blocks');
|
|
1022
|
+
// Insert the template blocks at the current cursor position
|
|
1023
|
+
editor
|
|
1024
|
+
.chain()
|
|
1025
|
+
.focus()
|
|
1026
|
+
.insertContent(tiptapBlocks.content)
|
|
1027
|
+
.run();
|
|
1028
|
+
logger_1.logger.log('✅ Template inserted successfully');
|
|
1029
|
+
}
|
|
1030
|
+
else {
|
|
1031
|
+
logger_1.logger.warn('⚠️ Cannot insert template - missing data:', {
|
|
1032
|
+
hasEditor: !!editor,
|
|
1033
|
+
hasTiptapBlocks: !!tiptapBlocks,
|
|
1034
|
+
hasContent: !!tiptapBlocks?.content
|
|
1035
|
+
});
|
|
1036
|
+
}
|
|
1037
|
+
};
|
|
1038
|
+
window.addEventListener('templateList', handleTemplateList);
|
|
1039
|
+
window.addEventListener('templateContent', handleTemplateContent);
|
|
1040
|
+
return () => {
|
|
1041
|
+
window.removeEventListener('templateList', handleTemplateList);
|
|
1042
|
+
window.removeEventListener('templateContent', handleTemplateContent);
|
|
1043
|
+
};
|
|
1044
|
+
}, [editor]);
|
|
1045
|
+
// Open links externally (VS Code) instead of navigating inside the webview
|
|
1046
|
+
(0, react_1.useEffect)(() => {
|
|
1047
|
+
if (!editor)
|
|
1048
|
+
return;
|
|
1049
|
+
const el = editor.view.dom;
|
|
1050
|
+
const onClick = (e) => {
|
|
1051
|
+
const target = e.target;
|
|
1052
|
+
const a = target?.closest?.('a[href]');
|
|
1053
|
+
if (!a)
|
|
1054
|
+
return;
|
|
1055
|
+
const href = a.getAttribute('href') || '';
|
|
1056
|
+
if (!href)
|
|
1057
|
+
return;
|
|
1058
|
+
e.preventDefault();
|
|
1059
|
+
e.stopPropagation();
|
|
1060
|
+
(0, bridge_utils_1.openExternal)(href).catch(() => { });
|
|
1061
|
+
};
|
|
1062
|
+
el.addEventListener('click', onClick);
|
|
1063
|
+
return () => el.removeEventListener('click', onClick);
|
|
1064
|
+
}, [editor]);
|
|
1065
|
+
// Close link dialog on Escape
|
|
1066
|
+
(0, react_1.useEffect)(() => {
|
|
1067
|
+
if (!showLinkDialog)
|
|
1068
|
+
return;
|
|
1069
|
+
const onKeyDown = (e) => {
|
|
1070
|
+
if (e.key === 'Escape')
|
|
1071
|
+
setShowLinkDialog(false);
|
|
1072
|
+
};
|
|
1073
|
+
window.addEventListener('keydown', onKeyDown);
|
|
1074
|
+
return () => window.removeEventListener('keydown', onKeyDown);
|
|
1075
|
+
}, [showLinkDialog]);
|
|
1076
|
+
if (!editor) {
|
|
1077
|
+
return (0, jsx_runtime_1.jsx)("div", { className: "jotx-editor-loading", children: "Initializing editor..." });
|
|
1078
|
+
}
|
|
1079
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "jotx-editor", children: [(0, jsx_runtime_1.jsx)(EditorRibbon_1.EditorRibbon, { editor: editor, expanded: ribbonExpanded, context: editorContext }), (0, jsx_runtime_1.jsxs)("div", { className: "jotx-editor-wrapper", children: [(0, jsx_runtime_1.jsx)(LinkDialog_1.LinkDialog, { isOpen: showLinkDialog, onCancel: () => setShowLinkDialog(false), onSubmit: ({ href, label }) => {
|
|
1080
|
+
setShowLinkDialog(false);
|
|
1081
|
+
const text = (label || href).trim();
|
|
1082
|
+
editor
|
|
1083
|
+
?.chain()
|
|
1084
|
+
.focus()
|
|
1085
|
+
// insert as its own paragraph so it roundtrips cleanly as `def link`
|
|
1086
|
+
.insertContent([
|
|
1087
|
+
{
|
|
1088
|
+
type: 'paragraph',
|
|
1089
|
+
content: [
|
|
1090
|
+
{
|
|
1091
|
+
type: 'text',
|
|
1092
|
+
text,
|
|
1093
|
+
marks: [{ type: 'link', attrs: { href } }]
|
|
1094
|
+
}
|
|
1095
|
+
]
|
|
1096
|
+
},
|
|
1097
|
+
{ type: 'paragraph' }
|
|
1098
|
+
])
|
|
1099
|
+
.run();
|
|
1100
|
+
} }), calloutToolbar.visible && ((0, jsx_runtime_1.jsx)("div", { className: "jotx-callout-toolbar jotx-callout-toolbar-floating", style: { left: `${calloutToolbar.x}px`, top: `${calloutToolbar.y}px` }, children: ['info', 'warning', 'success', 'danger'].map((v) => ((0, jsx_runtime_1.jsx)("button", { "data-variant": v, className: `jotx-callout-chip ${calloutToolbar.variant === v ? 'active' : ''}`, onMouseDown: (e) => {
|
|
1101
|
+
// prevent editor losing selection
|
|
1102
|
+
e.preventDefault();
|
|
1103
|
+
}, onClick: (e) => {
|
|
1104
|
+
e.preventDefault();
|
|
1105
|
+
e.stopPropagation();
|
|
1106
|
+
setCalloutVariant(v);
|
|
1107
|
+
}, title: `Callout: ${v}`, children: v }, v))) })), (0, jsx_runtime_1.jsx)(BlockMenu_1.BlockMenu, { editor: editor }), (0, jsx_runtime_1.jsx)(TableToolbar_1.TableToolbar, { editor: editor }), (0, jsx_runtime_1.jsx)(ImageToolbar_1.ImageToolbar, { editor: editor }), (0, jsx_runtime_1.jsx)(SearchBar_1.SearchBar, { visible: showSearchBar, onSearch: handleSearch, onNext: handleNextMatch, onPrevious: handlePreviousMatch, onClose: handleCloseSearch, currentMatch: searchState.currentMatch, totalMatches: searchState.totalMatches }), (0, jsx_runtime_1.jsx)(react_2.EditorContent, { editor: editor })] }), showSlashMenu && ((0, jsx_runtime_1.jsx)(SlashMenu_1.SlashMenu, { documentType: documentType, query: slashMenuQuery, position: slashMenuPosition, context: getTableContext(), onSelect: handleSlashCommand, onClose: () => setShowSlashMenu(false) })), showUrlInputDialog && ((0, jsx_runtime_1.jsx)(UrlInputDialog_1.UrlInputDialog, { isOpen: showUrlInputDialog, title: 'Insert Image URL', onCancel: () => setShowUrlInputDialog(false), onSubmit: ({ url }) => {
|
|
1108
|
+
setShowUrlInputDialog(false);
|
|
1109
|
+
if (urlInputType === 'image') {
|
|
1110
|
+
editor.chain().focus().setImage({ src: url, alt: '', dataSrc: null, width: 70, align: 'left' }).run();
|
|
1111
|
+
}
|
|
1112
|
+
} })), showTemplatePicker && ((0, jsx_runtime_1.jsx)("div", { className: "jotx-modal-overlay", onClick: () => setShowTemplatePicker(false), children: (0, jsx_runtime_1.jsxs)("div", { className: "jotx-modal-content jotx-template-picker", onClick: (e) => e.stopPropagation(), children: [(0, jsx_runtime_1.jsxs)("div", { className: "jotx-modal-header", children: [(0, jsx_runtime_1.jsx)("h3", { children: "\uD83D\uDCCB Choose a Template" }), (0, jsx_runtime_1.jsx)("button", { className: "jotx-modal-close", onClick: () => setShowTemplatePicker(false), children: "\u2715" })] }), (0, jsx_runtime_1.jsx)("div", { className: "jotx-template-list", children: availableTemplates.map((template) => ((0, jsx_runtime_1.jsxs)("button", { className: "jotx-template-item", onClick: () => {
|
|
1113
|
+
setShowTemplatePicker(false);
|
|
1114
|
+
const vscode = (0, vscode_api_1.getVSCodeAPI)();
|
|
1115
|
+
vscode.postMessage({
|
|
1116
|
+
type: 'requestTemplateContent',
|
|
1117
|
+
fileName: template.fileName
|
|
1118
|
+
});
|
|
1119
|
+
}, children: [(0, jsx_runtime_1.jsx)("span", { className: "jotx-template-icon", children: "\uD83D\uDCC4" }), (0, jsx_runtime_1.jsx)("span", { className: "jotx-template-name", children: template.name })] }, template.fileName))) })] }) }))] }));
|
|
1120
|
+
}
|
|
1121
|
+
//# sourceMappingURL=JotxEditor.js.map
|