@hugobatist/smartcode 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +292 -0
- package/dist/cli.js +4324 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +374 -0
- package/dist/index.js +1167 -0
- package/dist/index.js.map +1 -0
- package/dist/static/annotations-panel.js +133 -0
- package/dist/static/annotations-svg.js +108 -0
- package/dist/static/annotations.css +367 -0
- package/dist/static/annotations.js +367 -0
- package/dist/static/app-init.js +497 -0
- package/dist/static/breakpoints.css +69 -0
- package/dist/static/breakpoints.js +197 -0
- package/dist/static/clipboard.js +94 -0
- package/dist/static/collapse-ui.js +325 -0
- package/dist/static/command-history.js +89 -0
- package/dist/static/context-menu.js +334 -0
- package/dist/static/custom-renderer.js +201 -0
- package/dist/static/dagre-layout.js +291 -0
- package/dist/static/diagram-dom.js +241 -0
- package/dist/static/diagram-editor.js +368 -0
- package/dist/static/editor-panel.js +107 -0
- package/dist/static/editor-popovers.js +187 -0
- package/dist/static/event-bus.js +57 -0
- package/dist/static/export.js +181 -0
- package/dist/static/file-tree.js +470 -0
- package/dist/static/ghost-paths.js +397 -0
- package/dist/static/heatmap.css +116 -0
- package/dist/static/heatmap.js +308 -0
- package/dist/static/icons.js +66 -0
- package/dist/static/inline-edit.js +294 -0
- package/dist/static/interaction-state.js +155 -0
- package/dist/static/interaction-tracker.js +93 -0
- package/dist/static/live.html +239 -0
- package/dist/static/main-layout.css +220 -0
- package/dist/static/main.css +334 -0
- package/dist/static/mcp-sessions.js +202 -0
- package/dist/static/modal.css +109 -0
- package/dist/static/modal.js +171 -0
- package/dist/static/node-drag.js +293 -0
- package/dist/static/pan-zoom.js +199 -0
- package/dist/static/renderer.js +280 -0
- package/dist/static/search.css +103 -0
- package/dist/static/search.js +304 -0
- package/dist/static/selection.js +353 -0
- package/dist/static/session-player.css +137 -0
- package/dist/static/session-player.js +411 -0
- package/dist/static/sidebar.css +248 -0
- package/dist/static/svg-renderer.js +313 -0
- package/dist/static/svg-shapes.js +218 -0
- package/dist/static/tokens.css +76 -0
- package/dist/static/vendor/dagre-bundle.js +43 -0
- package/dist/static/vendor/dagre.min.js +3 -0
- package/dist/static/vendor/graphlib.min.js +2 -0
- package/dist/static/viewport-transform.js +107 -0
- package/dist/static/workspace-switcher.js +202 -0
- package/dist/static/ws-client.js +71 -0
- package/dist/static/ws-handler.js +125 -0
- package/package.json +74 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SmartCode Event Bus — lightweight pub/sub using native EventTarget API.
|
|
3
|
+
* All inter-module communication flows through this bus.
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* SmartCodeEventBus.on('diagram:rendered', (data) => { ... });
|
|
7
|
+
* SmartCodeEventBus.emit('diagram:rendered', { svg });
|
|
8
|
+
* SmartCodeEventBus.off('diagram:rendered', handler);
|
|
9
|
+
* SmartCodeEventBus.once('diagram:rendered', (data) => { ... });
|
|
10
|
+
*/
|
|
11
|
+
(function() {
|
|
12
|
+
'use strict';
|
|
13
|
+
|
|
14
|
+
var target = new EventTarget();
|
|
15
|
+
|
|
16
|
+
// Store wrapped handlers so off() can remove the correct listener.
|
|
17
|
+
// WeakMap<originalHandler, Map<eventName, wrappedHandler>>
|
|
18
|
+
var handlerMap = new WeakMap();
|
|
19
|
+
|
|
20
|
+
function getWrapped(event, handler) {
|
|
21
|
+
var byEvent = handlerMap.get(handler);
|
|
22
|
+
if (!byEvent) return null;
|
|
23
|
+
return byEvent.get(event) || null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function setWrapped(event, handler, wrapped) {
|
|
27
|
+
var byEvent = handlerMap.get(handler);
|
|
28
|
+
if (!byEvent) {
|
|
29
|
+
byEvent = new Map();
|
|
30
|
+
handlerMap.set(handler, byEvent);
|
|
31
|
+
}
|
|
32
|
+
byEvent.set(event, wrapped);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
var SmartCodeEventBus = {
|
|
36
|
+
on: function(event, handler) {
|
|
37
|
+
var wrapped = function(e) { handler(e.detail); };
|
|
38
|
+
setWrapped(event, handler, wrapped);
|
|
39
|
+
target.addEventListener(event, wrapped);
|
|
40
|
+
},
|
|
41
|
+
off: function(event, handler) {
|
|
42
|
+
var wrapped = getWrapped(event, handler);
|
|
43
|
+
if (wrapped) {
|
|
44
|
+
target.removeEventListener(event, wrapped);
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
emit: function(event, data) {
|
|
48
|
+
target.dispatchEvent(new CustomEvent(event, { detail: data }));
|
|
49
|
+
},
|
|
50
|
+
once: function(event, handler) {
|
|
51
|
+
var wrapped = function(e) { handler(e.detail); };
|
|
52
|
+
target.addEventListener(event, wrapped, { once: true });
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
window.SmartCodeEventBus = SmartCodeEventBus;
|
|
57
|
+
})();
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SmartCode Export -- SVG and PNG export of current diagram.
|
|
3
|
+
* Extracted from live.html (Phase 9 Plan 02).
|
|
4
|
+
*
|
|
5
|
+
* Dependencies: mermaid (CDN), renderer.js (SmartCodeRenderer.MERMAID_CONFIG)
|
|
6
|
+
* Dependents: none (triggered by UI buttons)
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* SmartCodeExport.exportSVG();
|
|
10
|
+
* SmartCodeExport.exportPNG();
|
|
11
|
+
*/
|
|
12
|
+
(function() {
|
|
13
|
+
'use strict';
|
|
14
|
+
|
|
15
|
+
// ── Download helper ──
|
|
16
|
+
function download(blob, name) {
|
|
17
|
+
var a = document.createElement('a');
|
|
18
|
+
a.href = URL.createObjectURL(blob);
|
|
19
|
+
a.download = name;
|
|
20
|
+
a.click();
|
|
21
|
+
URL.revokeObjectURL(a.href);
|
|
22
|
+
if (window.toast) toast('Exported: ' + name);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// ── Ghost path cloning for export (QUAL-03) ──
|
|
26
|
+
// Copies visible ghost path SVG elements from the live SVG into the export SVG
|
|
27
|
+
// so PNG exports include ghost paths.
|
|
28
|
+
function copyGhostPathsToExport(exportSvg) {
|
|
29
|
+
if (!window.SmartCodeGhostPaths || !SmartCodeGhostPaths.isVisible()) return;
|
|
30
|
+
|
|
31
|
+
var liveSvg = document.querySelector('#preview svg');
|
|
32
|
+
if (!liveSvg) return;
|
|
33
|
+
|
|
34
|
+
var ghostEls = liveSvg.querySelectorAll('.ghost-path');
|
|
35
|
+
if (ghostEls.length === 0) return;
|
|
36
|
+
|
|
37
|
+
// Clone the ghost-arrow marker definition if present
|
|
38
|
+
var ghostMarker = liveSvg.querySelector('#ghost-arrow');
|
|
39
|
+
if (ghostMarker) {
|
|
40
|
+
var exportDefs = exportSvg.querySelector('defs');
|
|
41
|
+
if (!exportDefs) {
|
|
42
|
+
exportDefs = document.createElementNS('http://www.w3.org/2000/svg', 'defs');
|
|
43
|
+
exportSvg.insertBefore(exportDefs, exportSvg.firstChild);
|
|
44
|
+
}
|
|
45
|
+
// Only add if not already present
|
|
46
|
+
if (!exportDefs.querySelector('#ghost-arrow')) {
|
|
47
|
+
exportDefs.appendChild(ghostMarker.cloneNode(true));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Clone each ghost path group into the export SVG
|
|
52
|
+
for (var i = 0; i < ghostEls.length; i++) {
|
|
53
|
+
exportSvg.appendChild(ghostEls[i].cloneNode(true));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// ── SVG Export ──
|
|
58
|
+
function exportSVG() {
|
|
59
|
+
var svg = document.querySelector('#preview svg');
|
|
60
|
+
if (!svg) return window.toast && toast('Nothing to export');
|
|
61
|
+
var blob = new Blob([svg.outerHTML], { type: 'image/svg+xml' });
|
|
62
|
+
var currentFile = (window.SmartCodeFileTree && SmartCodeFileTree.getCurrentFile()) || 'export';
|
|
63
|
+
download(blob, currentFile.replace('.mmd', '.svg'));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// ── PNG Export ──
|
|
67
|
+
// Uses SmartCodeRenderer.MERMAID_CONFIG to avoid triplicating the config object.
|
|
68
|
+
// Re-initializes mermaid with htmlLabels:false to avoid foreignObject Canvas taint,
|
|
69
|
+
// then restores original config after rendering.
|
|
70
|
+
async function exportPNG() {
|
|
71
|
+
var currentSvg = document.querySelector('#preview svg');
|
|
72
|
+
if (!currentSvg) return window.toast && toast('Nothing to export');
|
|
73
|
+
|
|
74
|
+
// Custom SVG: direct PNG export without mermaid re-render
|
|
75
|
+
if (window.DiagramDOM && DiagramDOM.getRendererType() === 'custom') {
|
|
76
|
+
var currentFile = (window.SmartCodeFileTree && SmartCodeFileTree.getCurrentFile()) || 'export';
|
|
77
|
+
var clone = currentSvg.cloneNode(true);
|
|
78
|
+
copyGhostPathsToExport(clone);
|
|
79
|
+
var canvas = document.createElement('canvas');
|
|
80
|
+
var ctx = canvas.getContext('2d');
|
|
81
|
+
var data = new XMLSerializer().serializeToString(clone);
|
|
82
|
+
var img = new Image();
|
|
83
|
+
img.onload = function() {
|
|
84
|
+
canvas.width = img.width * 2;
|
|
85
|
+
canvas.height = img.height * 2;
|
|
86
|
+
ctx.scale(2, 2);
|
|
87
|
+
ctx.drawImage(img, 0, 0);
|
|
88
|
+
canvas.toBlob(function(blob) {
|
|
89
|
+
download(blob, currentFile.replace('.mmd', '.png'));
|
|
90
|
+
}, 'image/png');
|
|
91
|
+
};
|
|
92
|
+
img.onerror = function() {
|
|
93
|
+
if (window.toast) toast('Error exporting PNG -- try SVG');
|
|
94
|
+
};
|
|
95
|
+
img.src = 'data:image/svg+xml;base64,' + btoa(unescape(encodeURIComponent(data)));
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
var baseConfig = window.SmartCodeRenderer && SmartCodeRenderer.MERMAID_CONFIG;
|
|
100
|
+
if (!baseConfig) {
|
|
101
|
+
if (window.toast) toast('Error: renderer not loaded');
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
var currentFile = (window.SmartCodeFileTree && SmartCodeFileTree.getCurrentFile()) || 'export';
|
|
106
|
+
|
|
107
|
+
try {
|
|
108
|
+
// Get current diagram source code (same pipeline as render())
|
|
109
|
+
var editor = document.getElementById('editor');
|
|
110
|
+
var code = editor.value;
|
|
111
|
+
var cleanCode = window.SmartCodeAnnotations
|
|
112
|
+
? SmartCodeAnnotations.getCleanContent(code)
|
|
113
|
+
: code;
|
|
114
|
+
var styledCode = window.injectStatusStyles
|
|
115
|
+
? injectStatusStyles(cleanCode)
|
|
116
|
+
: cleanCode;
|
|
117
|
+
|
|
118
|
+
// Build export config: clone base config with htmlLabels:false
|
|
119
|
+
var exportConfig = JSON.parse(JSON.stringify(baseConfig));
|
|
120
|
+
exportConfig.flowchart.htmlLabels = false;
|
|
121
|
+
|
|
122
|
+
// Temporarily re-initialize mermaid for Canvas-safe rendering
|
|
123
|
+
mermaid.initialize(exportConfig);
|
|
124
|
+
|
|
125
|
+
// Render a Canvas-safe SVG (no foreignObject)
|
|
126
|
+
var result = await mermaid.render('export-png-' + Date.now(), styledCode.trim());
|
|
127
|
+
var exportSvgStr = result.svg;
|
|
128
|
+
|
|
129
|
+
// Restore original mermaid config
|
|
130
|
+
mermaid.initialize(baseConfig);
|
|
131
|
+
|
|
132
|
+
// Parse export SVG to get dimensions
|
|
133
|
+
var tempDiv = document.createElement('div');
|
|
134
|
+
tempDiv.style.cssText = 'position:absolute;left:-9999px;top:-9999px;';
|
|
135
|
+
document.body.appendChild(tempDiv);
|
|
136
|
+
// Safe: SVG from mermaid.render(), not user input
|
|
137
|
+
tempDiv.textContent = '';
|
|
138
|
+
tempDiv.insertAdjacentHTML('afterbegin', exportSvgStr);
|
|
139
|
+
var exportSvg = tempDiv.querySelector('svg');
|
|
140
|
+
|
|
141
|
+
// Copy ghost paths into the export SVG (QUAL-03)
|
|
142
|
+
copyGhostPathsToExport(exportSvg);
|
|
143
|
+
|
|
144
|
+
var canvas = document.createElement('canvas');
|
|
145
|
+
var ctx = canvas.getContext('2d');
|
|
146
|
+
var data = new XMLSerializer().serializeToString(exportSvg);
|
|
147
|
+
|
|
148
|
+
document.body.removeChild(tempDiv);
|
|
149
|
+
|
|
150
|
+
var img = new Image();
|
|
151
|
+
img.onload = function() {
|
|
152
|
+
try {
|
|
153
|
+
canvas.width = img.width * 2;
|
|
154
|
+
canvas.height = img.height * 2;
|
|
155
|
+
ctx.scale(2, 2);
|
|
156
|
+
ctx.drawImage(img, 0, 0);
|
|
157
|
+
canvas.toBlob(function(blob) {
|
|
158
|
+
download(blob, currentFile.replace('.mmd', '.png'));
|
|
159
|
+
}, 'image/png');
|
|
160
|
+
} catch (taintErr) {
|
|
161
|
+
if (window.toast) toast('Error exporting PNG -- try SVG');
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
img.onerror = function() {
|
|
165
|
+
if (window.toast) toast('Error exporting PNG -- try SVG');
|
|
166
|
+
};
|
|
167
|
+
img.src = 'data:image/svg+xml;base64,' + btoa(unescape(encodeURIComponent(data)));
|
|
168
|
+
} catch (e) {
|
|
169
|
+
// Restore original config on error
|
|
170
|
+
if (baseConfig) mermaid.initialize(baseConfig);
|
|
171
|
+
if (window.toast) toast('Error exporting PNG -- try SVG');
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// ── Public API ──
|
|
176
|
+
window.SmartCodeExport = { exportSVG: exportSVG, exportPNG: exportPNG };
|
|
177
|
+
|
|
178
|
+
// Backward compat -- onclick handlers in HTML call these directly
|
|
179
|
+
window.exportSVG = exportSVG;
|
|
180
|
+
window.exportPNG = exportPNG;
|
|
181
|
+
})();
|