notations 1.0.2 → 1.0.4
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/notations.umd.js +3933 -12155
- package/dist/notations.umd.min.js +2 -3
- package/dist/notations.umd.min.js.map +1 -1
- package/lib/cjs/parser.js +1 -1
- package/lib/cjs/parser.js.map +1 -1
- package/lib/cjs/web/components/DockViewPlayground.d.ts +51 -0
- package/lib/cjs/web/components/DockViewPlayground.js +364 -0
- package/lib/cjs/web/components/DockViewPlayground.js.map +1 -0
- package/lib/cjs/web/components/NotationBlock.d.ts +35 -0
- package/lib/cjs/web/components/NotationBlock.js +219 -0
- package/lib/cjs/web/components/NotationBlock.js.map +1 -0
- package/lib/cjs/web/components/NotebookCell.d.ts +41 -0
- package/lib/cjs/web/components/NotebookCell.js +269 -0
- package/lib/cjs/web/components/NotebookCell.js.map +1 -0
- package/lib/cjs/web/components/NotebookView.d.ts +37 -0
- package/lib/cjs/web/components/NotebookView.js +379 -0
- package/lib/cjs/web/components/NotebookView.js.map +1 -0
- package/lib/cjs/web/components/SideBySideEditor.d.ts +47 -0
- package/lib/cjs/web/components/SideBySideEditor.js +171 -0
- package/lib/cjs/web/components/SideBySideEditor.js.map +1 -0
- package/lib/cjs/web/dockview.d.ts +2 -0
- package/lib/cjs/web/dockview.js +11 -0
- package/lib/cjs/web/dockview.js.map +1 -0
- package/lib/cjs/web/index.d.ts +8 -0
- package/lib/cjs/web/index.js +34 -0
- package/lib/cjs/web/index.js.map +1 -0
- package/lib/cjs/web/types/notebook.d.ts +64 -0
- package/lib/cjs/web/types/notebook.js +56 -0
- package/lib/cjs/web/types/notebook.js.map +1 -0
- package/lib/cjs/web/utils/cellFactory.d.ts +16 -0
- package/lib/cjs/web/utils/cellFactory.js +137 -0
- package/lib/cjs/web/utils/cellFactory.js.map +1 -0
- package/lib/cjs/web/utils/sourceSerializer.d.ts +19 -0
- package/lib/cjs/web/utils/sourceSerializer.js +162 -0
- package/lib/cjs/web/utils/sourceSerializer.js.map +1 -0
- package/lib/esm/parser.js +1 -1
- package/lib/esm/parser.js.map +1 -1
- package/lib/esm/web/components/DockViewPlayground.d.ts +51 -0
- package/lib/esm/web/components/DockViewPlayground.js +358 -0
- package/lib/esm/web/components/DockViewPlayground.js.map +1 -0
- package/lib/esm/web/components/NotationBlock.d.ts +35 -0
- package/lib/esm/web/components/NotationBlock.js +216 -0
- package/lib/esm/web/components/NotationBlock.js.map +1 -0
- package/lib/esm/web/components/NotebookCell.d.ts +41 -0
- package/lib/esm/web/components/NotebookCell.js +266 -0
- package/lib/esm/web/components/NotebookCell.js.map +1 -0
- package/lib/esm/web/components/NotebookView.d.ts +37 -0
- package/lib/esm/web/components/NotebookView.js +376 -0
- package/lib/esm/web/components/NotebookView.js.map +1 -0
- package/lib/esm/web/components/SideBySideEditor.d.ts +47 -0
- package/lib/esm/web/components/SideBySideEditor.js +168 -0
- package/lib/esm/web/components/SideBySideEditor.js.map +1 -0
- package/lib/esm/web/dockview.d.ts +2 -0
- package/lib/esm/web/dockview.js +3 -0
- package/lib/esm/web/dockview.js.map +1 -0
- package/lib/esm/web/index.d.ts +8 -0
- package/lib/esm/web/index.js +9 -0
- package/lib/esm/web/index.js.map +1 -0
- package/lib/esm/web/types/notebook.d.ts +64 -0
- package/lib/esm/web/types/notebook.js +50 -0
- package/lib/esm/web/types/notebook.js.map +1 -0
- package/lib/esm/web/utils/cellFactory.d.ts +16 -0
- package/lib/esm/web/utils/cellFactory.js +127 -0
- package/lib/esm/web/utils/cellFactory.js.map +1 -0
- package/lib/esm/web/utils/sourceSerializer.d.ts +19 -0
- package/lib/esm/web/utils/sourceSerializer.js +154 -0
- package/lib/esm/web/utils/sourceSerializer.js.map +1 -0
- package/package.json +41 -1
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { load } from "../../loader";
|
|
11
|
+
export default class NotationBlock {
|
|
12
|
+
constructor(container, config) {
|
|
13
|
+
var _a, _b, _c, _d, _e, _f;
|
|
14
|
+
this.container = container;
|
|
15
|
+
this.config = config;
|
|
16
|
+
this.caption = "";
|
|
17
|
+
this.isEditing = false;
|
|
18
|
+
this.editTextarea = null;
|
|
19
|
+
this.sourceCodeElement = null;
|
|
20
|
+
this.id = (container.getAttribute("id") || "").trim();
|
|
21
|
+
this.caption = (container.getAttribute("caption") || "").trim();
|
|
22
|
+
const sourceFrom = (container.getAttribute("sourceFrom") || "").trim();
|
|
23
|
+
this.source = container.textContent || "";
|
|
24
|
+
if (sourceFrom.length > 0) {
|
|
25
|
+
const sourceElem = document.getElementById(sourceFrom);
|
|
26
|
+
if (sourceElem) {
|
|
27
|
+
this.source = sourceElem.textContent || "";
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
this.height = container.getAttribute("height") || "";
|
|
31
|
+
this.showSource = (container.getAttribute("showSource") || "false") == "true";
|
|
32
|
+
const parent = container.parentNode;
|
|
33
|
+
const newRoot = document.createElement("div");
|
|
34
|
+
newRoot.classList.add("notationBlockRoot");
|
|
35
|
+
if ((_a = config.cssClasses) === null || _a === void 0 ? void 0 : _a.root) {
|
|
36
|
+
newRoot.className += " " + config.cssClasses.root;
|
|
37
|
+
}
|
|
38
|
+
this.newRoot = newRoot;
|
|
39
|
+
let html = "";
|
|
40
|
+
if (this.showSource) {
|
|
41
|
+
const sourceLines = this.source.split("\n");
|
|
42
|
+
const sourceClass = ((_b = config.cssClasses) === null || _b === void 0 ? void 0 : _b.sourceContainer) || "";
|
|
43
|
+
const captionClass = ((_c = config.cssClasses) === null || _c === void 0 ? void 0 : _c.sourceCaption) || "";
|
|
44
|
+
const codeClass = ((_d = config.cssClasses) === null || _d === void 0 ? void 0 : _d.sourceCode) || "";
|
|
45
|
+
html += `
|
|
46
|
+
<figure class="notation-source-block ${sourceClass}">
|
|
47
|
+
<div class="notation-source-header">
|
|
48
|
+
<figcaption class="notation-caption ${captionClass}">${this.caption}</figcaption>
|
|
49
|
+
<div class="notation-source-actions">
|
|
50
|
+
<button class="notation-btn notation-copy-btn" id="copyBtn_${this.id}" title="Copy to clipboard">
|
|
51
|
+
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
|
|
52
|
+
<path d="M4 2a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V2zm2-1a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1H6zM2 5a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1v-1h1v1a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h1v1H2z"/>
|
|
53
|
+
</svg>
|
|
54
|
+
<span class="notation-btn-text">Copy</span>
|
|
55
|
+
</button>
|
|
56
|
+
<button class="notation-btn notation-edit-btn" id="editBtn_${this.id}" title="Edit notation">
|
|
57
|
+
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
|
|
58
|
+
<path d="M12.146.146a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1 0 .708l-10 10a.5.5 0 0 1-.168.11l-5 2a.5.5 0 0 1-.65-.65l2-5a.5.5 0 0 1 .11-.168l10-10zM11.207 2.5 13.5 4.793 14.793 3.5 12.5 1.207 11.207 2.5zm1.586 3L10.5 3.207 4 9.707V10h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.293l6.5-6.5zm-9.761 5.175-.106.106-1.528 3.821 3.821-1.528.106-.106A.5.5 0 0 1 5 12.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.468-.325z"/>
|
|
59
|
+
</svg>
|
|
60
|
+
<span class="notation-btn-text">Edit</span>
|
|
61
|
+
</button>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
<div class="notation-source" id="notationSource_${this.id}">
|
|
65
|
+
<pre class="notation-source-pre">
|
|
66
|
+
<code class="${codeClass}" id="sourceCode_${this.id}">${sourceLines.map((x) => `<span>${x}</span>`).join("\n")}</code>
|
|
67
|
+
</pre>
|
|
68
|
+
<textarea class="notation-edit-textarea" id="editTextarea_${this.id}" style="display: none;"></textarea>
|
|
69
|
+
</div>
|
|
70
|
+
<div class="notation-edit-actions" id="editActions_${this.id}" style="display: none;">
|
|
71
|
+
<button class="notation-btn notation-apply-btn" id="applyBtn_${this.id}">Apply</button>
|
|
72
|
+
<button class="notation-btn notation-cancel-btn" id="cancelBtn_${this.id}">Cancel</button>
|
|
73
|
+
</div>
|
|
74
|
+
</figure>`;
|
|
75
|
+
}
|
|
76
|
+
const outputLabelClass = ((_e = config.cssClasses) === null || _e === void 0 ? void 0 : _e.outputLabel) || "";
|
|
77
|
+
const outputClass = ((_f = config.cssClasses) === null || _f === void 0 ? void 0 : _f.outputContainer) || "";
|
|
78
|
+
html += `
|
|
79
|
+
<div class="notation-output">
|
|
80
|
+
<span class="notation-output-label ${outputLabelClass}"><strong>Output:</strong></span>
|
|
81
|
+
<div id="notationViewer_${this.id}" class="notation-view ${outputClass}">
|
|
82
|
+
</div>
|
|
83
|
+
</div>`;
|
|
84
|
+
newRoot.innerHTML = html;
|
|
85
|
+
parent.insertBefore(newRoot, container);
|
|
86
|
+
parent.removeChild(container);
|
|
87
|
+
const notationViewerBlock = newRoot.querySelector(".notation-view");
|
|
88
|
+
this.notationView = config.createViewer(notationViewerBlock);
|
|
89
|
+
if (this.showSource) {
|
|
90
|
+
this.sourceCodeElement = newRoot.querySelector(`#sourceCode_${this.id}`);
|
|
91
|
+
this.editTextarea = newRoot.querySelector(`#editTextarea_${this.id}`);
|
|
92
|
+
const copyBtn = newRoot.querySelector(`#copyBtn_${this.id}`);
|
|
93
|
+
if (copyBtn) {
|
|
94
|
+
copyBtn.addEventListener("click", () => this.copyToClipboard());
|
|
95
|
+
}
|
|
96
|
+
const editBtn = newRoot.querySelector(`#editBtn_${this.id}`);
|
|
97
|
+
if (editBtn) {
|
|
98
|
+
editBtn.addEventListener("click", () => this.toggleEditMode());
|
|
99
|
+
}
|
|
100
|
+
const applyBtn = newRoot.querySelector(`#applyBtn_${this.id}`);
|
|
101
|
+
if (applyBtn) {
|
|
102
|
+
applyBtn.addEventListener("click", () => this.applyEdit());
|
|
103
|
+
}
|
|
104
|
+
const cancelBtn = newRoot.querySelector(`#cancelBtn_${this.id}`);
|
|
105
|
+
if (cancelBtn) {
|
|
106
|
+
cancelBtn.addEventListener("click", () => this.cancelEdit());
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
this.updatePreview();
|
|
110
|
+
console.log("Done Rendering... Adjusting height");
|
|
111
|
+
}
|
|
112
|
+
updatePreview() {
|
|
113
|
+
const fullContents = this.source;
|
|
114
|
+
this.notationView.tableElement.innerHTML = "";
|
|
115
|
+
const [notation, beatLayout, errors, timings] = load(fullContents, { log: true });
|
|
116
|
+
if (errors.length > 0) {
|
|
117
|
+
console.log("Errors: ", errors);
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
console.log("Rendering notation...");
|
|
121
|
+
this.notationView.renderNotation(notation, beatLayout);
|
|
122
|
+
}
|
|
123
|
+
const msg = `Document parsed (${Math.trunc(timings.parseTime * 100) / 100} ms) and built (${Math.trunc(timings.buildTime * 100) / 100} ms)`;
|
|
124
|
+
console.log(msg);
|
|
125
|
+
}
|
|
126
|
+
get captionId() {
|
|
127
|
+
return "notationCaption_" + this.id;
|
|
128
|
+
}
|
|
129
|
+
copyToClipboard() {
|
|
130
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
131
|
+
try {
|
|
132
|
+
yield navigator.clipboard.writeText(this.source);
|
|
133
|
+
const copyBtn = this.newRoot.querySelector(`#copyBtn_${this.id}`);
|
|
134
|
+
if (copyBtn) {
|
|
135
|
+
const btnText = copyBtn.querySelector(".notation-btn-text");
|
|
136
|
+
const originalText = btnText === null || btnText === void 0 ? void 0 : btnText.textContent;
|
|
137
|
+
if (btnText) {
|
|
138
|
+
btnText.textContent = "Copied!";
|
|
139
|
+
setTimeout(() => {
|
|
140
|
+
if (btnText)
|
|
141
|
+
btnText.textContent = originalText || "Copy";
|
|
142
|
+
}, 2000);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
catch (err) {
|
|
147
|
+
console.error("Failed to copy to clipboard:", err);
|
|
148
|
+
alert("Failed to copy to clipboard");
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
toggleEditMode() {
|
|
153
|
+
this.isEditing = !this.isEditing;
|
|
154
|
+
if (this.isEditing) {
|
|
155
|
+
this.enterEditMode();
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
this.exitEditMode();
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
enterEditMode() {
|
|
162
|
+
if (!this.editTextarea || !this.sourceCodeElement)
|
|
163
|
+
return;
|
|
164
|
+
this.editTextarea.value = this.source;
|
|
165
|
+
if (this.sourceCodeElement.parentElement) {
|
|
166
|
+
this.sourceCodeElement.parentElement.style.display = "none";
|
|
167
|
+
}
|
|
168
|
+
this.editTextarea.style.display = "block";
|
|
169
|
+
this.editTextarea.style.height = "auto";
|
|
170
|
+
this.editTextarea.style.height = this.editTextarea.scrollHeight + "px";
|
|
171
|
+
const editActions = this.newRoot.querySelector(`#editActions_${this.id}`);
|
|
172
|
+
if (editActions) {
|
|
173
|
+
editActions.style.display = "flex";
|
|
174
|
+
}
|
|
175
|
+
const editBtn = this.newRoot.querySelector(`#editBtn_${this.id}`);
|
|
176
|
+
const btnText = editBtn === null || editBtn === void 0 ? void 0 : editBtn.querySelector(".notation-btn-text");
|
|
177
|
+
if (btnText) {
|
|
178
|
+
btnText.textContent = "Editing...";
|
|
179
|
+
}
|
|
180
|
+
this.editTextarea.focus();
|
|
181
|
+
}
|
|
182
|
+
exitEditMode() {
|
|
183
|
+
if (!this.editTextarea || !this.sourceCodeElement)
|
|
184
|
+
return;
|
|
185
|
+
this.editTextarea.style.display = "none";
|
|
186
|
+
if (this.sourceCodeElement.parentElement) {
|
|
187
|
+
this.sourceCodeElement.parentElement.style.display = "block";
|
|
188
|
+
}
|
|
189
|
+
const editActions = this.newRoot.querySelector(`#editActions_${this.id}`);
|
|
190
|
+
if (editActions) {
|
|
191
|
+
editActions.style.display = "none";
|
|
192
|
+
}
|
|
193
|
+
const editBtn = this.newRoot.querySelector(`#editBtn_${this.id}`);
|
|
194
|
+
const btnText = editBtn === null || editBtn === void 0 ? void 0 : editBtn.querySelector(".notation-btn-text");
|
|
195
|
+
if (btnText) {
|
|
196
|
+
btnText.textContent = "Edit";
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
applyEdit() {
|
|
200
|
+
if (!this.editTextarea)
|
|
201
|
+
return;
|
|
202
|
+
this.source = this.editTextarea.value;
|
|
203
|
+
if (this.sourceCodeElement) {
|
|
204
|
+
const sourceLines = this.source.split("\n");
|
|
205
|
+
this.sourceCodeElement.innerHTML = sourceLines.map((x) => `<span>${x}</span>`).join("\n");
|
|
206
|
+
}
|
|
207
|
+
this.updatePreview();
|
|
208
|
+
this.isEditing = false;
|
|
209
|
+
this.exitEditMode();
|
|
210
|
+
}
|
|
211
|
+
cancelEdit() {
|
|
212
|
+
this.isEditing = false;
|
|
213
|
+
this.exitEditMode();
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
//# sourceMappingURL=NotationBlock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NotationBlock.js","sourceRoot":"","sources":["../../../../src/web/components/NotationBlock.ts"],"names":[],"mappings":"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","sourcesContent":["import { load } from \"../../loader\";\nimport { NotationView } from \"../../carnatic\";\n\nexport interface NotationBlockConfig {\n /** Function to create a notation viewer - allows different implementations */\n createViewer: (container: HTMLDivElement) => NotationView;\n\n /** CSS classes to apply to various elements */\n cssClasses?: {\n root?: string;\n sourceContainer?: string;\n sourceCaption?: string;\n sourceCode?: string;\n outputLabel?: string;\n outputContainer?: string;\n };\n}\n\nexport default class NotationBlock {\n id: string;\n source: string;\n caption = \"\";\n height: string;\n newRoot: HTMLDivElement;\n notationView: NotationView;\n showSource: boolean;\n isEditing = false;\n editTextarea: HTMLTextAreaElement | null = null;\n sourceCodeElement: HTMLElement | null = null;\n\n constructor(\n public readonly container: HTMLElement,\n public readonly config: NotationBlockConfig,\n ) {\n this.id = (container.getAttribute(\"id\") || \"\").trim();\n this.caption = (container.getAttribute(\"caption\") || \"\").trim();\n const sourceFrom = (container.getAttribute(\"sourceFrom\") || \"\").trim();\n this.source = container.textContent || \"\";\n\n if (sourceFrom.length > 0) {\n const sourceElem = document.getElementById(sourceFrom);\n if (sourceElem) {\n this.source = sourceElem.textContent || \"\";\n }\n }\n\n this.height = container.getAttribute(\"height\") || \"\";\n this.showSource = (container.getAttribute(\"showSource\") || \"false\") == \"true\";\n\n const parent = container.parentNode as HTMLDivElement;\n const newRoot = document.createElement(\"div\");\n newRoot.classList.add(\"notationBlockRoot\");\n if (config.cssClasses?.root) {\n newRoot.className += \" \" + config.cssClasses.root;\n }\n this.newRoot = newRoot;\n\n // Build HTML structure\n let html = \"\";\n\n // Add source code section if showSource is true\n if (this.showSource) {\n const sourceLines = this.source.split(\"\\n\");\n const sourceClass = config.cssClasses?.sourceContainer || \"\";\n const captionClass = config.cssClasses?.sourceCaption || \"\";\n const codeClass = config.cssClasses?.sourceCode || \"\";\n\n html += `\n <figure class=\"notation-source-block ${sourceClass}\">\n <div class=\"notation-source-header\">\n <figcaption class=\"notation-caption ${captionClass}\">${this.caption}</figcaption>\n <div class=\"notation-source-actions\">\n <button class=\"notation-btn notation-copy-btn\" id=\"copyBtn_${this.id}\" title=\"Copy to clipboard\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"currentColor\">\n <path d=\"M4 2a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V2zm2-1a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1H6zM2 5a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1v-1h1v1a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h1v1H2z\"/>\n </svg>\n <span class=\"notation-btn-text\">Copy</span>\n </button>\n <button class=\"notation-btn notation-edit-btn\" id=\"editBtn_${this.id}\" title=\"Edit notation\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"currentColor\">\n <path d=\"M12.146.146a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1 0 .708l-10 10a.5.5 0 0 1-.168.11l-5 2a.5.5 0 0 1-.65-.65l2-5a.5.5 0 0 1 .11-.168l10-10zM11.207 2.5 13.5 4.793 14.793 3.5 12.5 1.207 11.207 2.5zm1.586 3L10.5 3.207 4 9.707V10h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.293l6.5-6.5zm-9.761 5.175-.106.106-1.528 3.821 3.821-1.528.106-.106A.5.5 0 0 1 5 12.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.468-.325z\"/>\n </svg>\n <span class=\"notation-btn-text\">Edit</span>\n </button>\n </div>\n </div>\n <div class=\"notation-source\" id=\"notationSource_${this.id}\">\n <pre class=\"notation-source-pre\">\n <code class=\"${codeClass}\" id=\"sourceCode_${this.id}\">${sourceLines.map((x) => `<span>${x}</span>`).join(\"\\n\")}</code>\n </pre>\n <textarea class=\"notation-edit-textarea\" id=\"editTextarea_${this.id}\" style=\"display: none;\"></textarea>\n </div>\n <div class=\"notation-edit-actions\" id=\"editActions_${this.id}\" style=\"display: none;\">\n <button class=\"notation-btn notation-apply-btn\" id=\"applyBtn_${this.id}\">Apply</button>\n <button class=\"notation-btn notation-cancel-btn\" id=\"cancelBtn_${this.id}\">Cancel</button>\n </div>\n </figure>`;\n }\n\n // Add output section\n const outputLabelClass = config.cssClasses?.outputLabel || \"\";\n const outputClass = config.cssClasses?.outputContainer || \"\";\n\n html += `\n <div class=\"notation-output\">\n <span class=\"notation-output-label ${outputLabelClass}\"><strong>Output:</strong></span>\n <div id=\"notationViewer_${this.id}\" class=\"notation-view ${outputClass}\">\n </div>\n </div>`;\n\n newRoot.innerHTML = html;\n parent.insertBefore(newRoot, container);\n parent.removeChild(container);\n\n const notationViewerBlock = newRoot.querySelector(\".notation-view\") as HTMLDivElement;\n this.notationView = config.createViewer(notationViewerBlock);\n\n // Set up event handlers\n if (this.showSource) {\n this.sourceCodeElement = newRoot.querySelector(`#sourceCode_${this.id}`);\n this.editTextarea = newRoot.querySelector(`#editTextarea_${this.id}`);\n\n // Copy button\n const copyBtn = newRoot.querySelector(`#copyBtn_${this.id}`);\n if (copyBtn) {\n copyBtn.addEventListener(\"click\", () => this.copyToClipboard());\n }\n\n // Edit button\n const editBtn = newRoot.querySelector(`#editBtn_${this.id}`);\n if (editBtn) {\n editBtn.addEventListener(\"click\", () => this.toggleEditMode());\n }\n\n // Apply button\n const applyBtn = newRoot.querySelector(`#applyBtn_${this.id}`);\n if (applyBtn) {\n applyBtn.addEventListener(\"click\", () => this.applyEdit());\n }\n\n // Cancel button\n const cancelBtn = newRoot.querySelector(`#cancelBtn_${this.id}`);\n if (cancelBtn) {\n cancelBtn.addEventListener(\"click\", () => this.cancelEdit());\n }\n }\n\n this.updatePreview();\n console.log(\"Done Rendering... Adjusting height\");\n }\n\n updatePreview(): void {\n const fullContents = this.source;\n // Clear previous render to avoid appending multiple times\n this.notationView.tableElement.innerHTML = \"\";\n\n const [notation, beatLayout, errors, timings] = load(fullContents, { log: true });\n\n if (errors.length > 0) {\n console.log(\"Errors: \", errors);\n } else {\n console.log(\"Rendering notation...\");\n this.notationView.renderNotation(notation, beatLayout);\n }\n\n const msg = `Document parsed (${Math.trunc(timings.parseTime * 100) / 100} ms) and built (${\n Math.trunc(timings.buildTime * 100) / 100\n } ms)`;\n console.log(msg);\n }\n\n get captionId(): string {\n return \"notationCaption_\" + this.id;\n }\n\n async copyToClipboard(): Promise<void> {\n try {\n await navigator.clipboard.writeText(this.source);\n const copyBtn = this.newRoot.querySelector(`#copyBtn_${this.id}`);\n if (copyBtn) {\n const btnText = copyBtn.querySelector(\".notation-btn-text\");\n const originalText = btnText?.textContent;\n if (btnText) {\n btnText.textContent = \"Copied!\";\n setTimeout(() => {\n if (btnText) btnText.textContent = originalText || \"Copy\";\n }, 2000);\n }\n }\n } catch (err) {\n console.error(\"Failed to copy to clipboard:\", err);\n alert(\"Failed to copy to clipboard\");\n }\n }\n\n toggleEditMode(): void {\n this.isEditing = !this.isEditing;\n\n if (this.isEditing) {\n this.enterEditMode();\n } else {\n this.exitEditMode();\n }\n }\n\n enterEditMode(): void {\n if (!this.editTextarea || !this.sourceCodeElement) return;\n\n // Populate textarea with current source\n this.editTextarea.value = this.source;\n\n // Hide source code, show textarea\n if (this.sourceCodeElement.parentElement) {\n this.sourceCodeElement.parentElement.style.display = \"none\";\n }\n this.editTextarea.style.display = \"block\";\n\n // Auto-resize textarea to fit content\n this.editTextarea.style.height = \"auto\";\n this.editTextarea.style.height = this.editTextarea.scrollHeight + \"px\";\n\n // Show edit actions\n const editActions = this.newRoot.querySelector(`#editActions_${this.id}`) as HTMLElement;\n if (editActions) {\n editActions.style.display = \"flex\";\n }\n\n // Update edit button text\n const editBtn = this.newRoot.querySelector(`#editBtn_${this.id}`);\n const btnText = editBtn?.querySelector(\".notation-btn-text\");\n if (btnText) {\n btnText.textContent = \"Editing...\";\n }\n\n this.editTextarea.focus();\n }\n\n exitEditMode(): void {\n if (!this.editTextarea || !this.sourceCodeElement) return;\n\n // Hide textarea, show source code\n this.editTextarea.style.display = \"none\";\n if (this.sourceCodeElement.parentElement) {\n this.sourceCodeElement.parentElement.style.display = \"block\";\n }\n\n // Hide edit actions\n const editActions = this.newRoot.querySelector(`#editActions_${this.id}`) as HTMLElement;\n if (editActions) {\n editActions.style.display = \"none\";\n }\n\n // Update edit button text\n const editBtn = this.newRoot.querySelector(`#editBtn_${this.id}`);\n const btnText = editBtn?.querySelector(\".notation-btn-text\");\n if (btnText) {\n btnText.textContent = \"Edit\";\n }\n }\n\n applyEdit(): void {\n if (!this.editTextarea) return;\n\n // Update source\n this.source = this.editTextarea.value;\n\n // Update source code display\n if (this.sourceCodeElement) {\n const sourceLines = this.source.split(\"\\n\");\n this.sourceCodeElement.innerHTML = sourceLines.map((x) => `<span>${x}</span>`).join(\"\\n\");\n }\n\n // Re-render notation\n this.updatePreview();\n\n // Exit edit mode\n this.isEditing = false;\n this.exitEditMode();\n }\n\n cancelEdit(): void {\n // Simply exit edit mode without applying changes\n this.isEditing = false;\n this.exitEditMode();\n }\n}\n"]}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { CellModel, NotebookCssClasses } from "../types/notebook";
|
|
2
|
+
export interface NotebookCellConfig {
|
|
3
|
+
cssClasses?: NotebookCssClasses;
|
|
4
|
+
markdownParser?: (content: string) => string;
|
|
5
|
+
showDeleteButton?: boolean;
|
|
6
|
+
showMoveButtons?: boolean;
|
|
7
|
+
onStartEdit?: (cellId: string) => void;
|
|
8
|
+
onApplyEdit?: (cellId: string, newSource: string) => void;
|
|
9
|
+
onCancelEdit?: (cellId: string) => void;
|
|
10
|
+
onDelete?: (cellId: string) => void;
|
|
11
|
+
onMoveUp?: (cellId: string) => void;
|
|
12
|
+
onMoveDown?: (cellId: string) => void;
|
|
13
|
+
onToggleExpanded?: (cellId: string) => void;
|
|
14
|
+
createChildCell?: (cell: CellModel, parent: HTMLElement) => NotebookCell;
|
|
15
|
+
}
|
|
16
|
+
export default class NotebookCell {
|
|
17
|
+
readonly element: HTMLDivElement;
|
|
18
|
+
readonly cell: CellModel;
|
|
19
|
+
readonly config: NotebookCellConfig;
|
|
20
|
+
private childCells;
|
|
21
|
+
private editTextarea;
|
|
22
|
+
constructor(cell: CellModel, config?: NotebookCellConfig);
|
|
23
|
+
private buildRootClassName;
|
|
24
|
+
private render;
|
|
25
|
+
private renderHeader;
|
|
26
|
+
private createBadge;
|
|
27
|
+
private createControls;
|
|
28
|
+
private renderError;
|
|
29
|
+
private renderContent;
|
|
30
|
+
private renderPreviewMode;
|
|
31
|
+
private renderEditMode;
|
|
32
|
+
private renderChildren;
|
|
33
|
+
private handleStartEdit;
|
|
34
|
+
private handleApplyEdit;
|
|
35
|
+
private handleCancelEdit;
|
|
36
|
+
private handleDelete;
|
|
37
|
+
private handleToggleExpanded;
|
|
38
|
+
getEditSource(): string;
|
|
39
|
+
update(newCell: CellModel): void;
|
|
40
|
+
destroy(): void;
|
|
41
|
+
}
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import { isBlock, isLine, isRawBlock } from "../../block";
|
|
2
|
+
import { getCellTypeBadge } from "../types/notebook";
|
|
3
|
+
export default class NotebookCell {
|
|
4
|
+
constructor(cell, config = {}) {
|
|
5
|
+
this.childCells = [];
|
|
6
|
+
this.editTextarea = null;
|
|
7
|
+
this.cell = cell;
|
|
8
|
+
this.config = config;
|
|
9
|
+
this.element = document.createElement("div");
|
|
10
|
+
this.element.className = this.buildRootClassName();
|
|
11
|
+
this.element.dataset.cellId = cell.state.id;
|
|
12
|
+
this.element.dataset.depth = String(cell.state.depth);
|
|
13
|
+
this.render();
|
|
14
|
+
}
|
|
15
|
+
buildRootClassName() {
|
|
16
|
+
var _a;
|
|
17
|
+
const classes = [
|
|
18
|
+
"notebook-cell",
|
|
19
|
+
`notebook-cell-${this.cell.state.type}`,
|
|
20
|
+
`notebook-cell-depth-${this.cell.state.depth}`,
|
|
21
|
+
];
|
|
22
|
+
if (this.cell.state.isEditing) {
|
|
23
|
+
classes.push("notebook-cell-editing");
|
|
24
|
+
}
|
|
25
|
+
if (this.cell.state.hasError) {
|
|
26
|
+
classes.push("notebook-cell-error");
|
|
27
|
+
}
|
|
28
|
+
if (!this.cell.state.isExpanded && this.cell.children.length > 0) {
|
|
29
|
+
classes.push("notebook-cell-collapsed");
|
|
30
|
+
}
|
|
31
|
+
if ((_a = this.config.cssClasses) === null || _a === void 0 ? void 0 : _a.cell) {
|
|
32
|
+
classes.push(this.config.cssClasses.cell);
|
|
33
|
+
}
|
|
34
|
+
return classes.join(" ");
|
|
35
|
+
}
|
|
36
|
+
render() {
|
|
37
|
+
this.element.innerHTML = "";
|
|
38
|
+
this.renderHeader();
|
|
39
|
+
if (this.cell.state.hasError && this.cell.state.errorMessage) {
|
|
40
|
+
this.renderError();
|
|
41
|
+
}
|
|
42
|
+
this.renderContent();
|
|
43
|
+
if (this.cell.state.isExpanded && this.cell.children.length > 0) {
|
|
44
|
+
this.renderChildren();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
renderHeader() {
|
|
48
|
+
var _a;
|
|
49
|
+
const header = document.createElement("div");
|
|
50
|
+
header.className = "notebook-cell-header";
|
|
51
|
+
if ((_a = this.config.cssClasses) === null || _a === void 0 ? void 0 : _a.cellHeader) {
|
|
52
|
+
header.className += " " + this.config.cssClasses.cellHeader;
|
|
53
|
+
}
|
|
54
|
+
const leftSide = document.createElement("div");
|
|
55
|
+
leftSide.className = "notebook-cell-header-left";
|
|
56
|
+
const badge = this.createBadge();
|
|
57
|
+
leftSide.appendChild(badge);
|
|
58
|
+
if (isBlock(this.cell.blockItem)) {
|
|
59
|
+
const block = this.cell.blockItem;
|
|
60
|
+
if (block.name) {
|
|
61
|
+
const nameSpan = document.createElement("span");
|
|
62
|
+
nameSpan.className = "notebook-cell-name";
|
|
63
|
+
nameSpan.textContent = block.name;
|
|
64
|
+
leftSide.appendChild(nameSpan);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (this.cell.children.length > 0) {
|
|
68
|
+
const expandBtn = document.createElement("button");
|
|
69
|
+
expandBtn.className = "notebook-btn notebook-expand-btn";
|
|
70
|
+
expandBtn.innerHTML = this.cell.state.isExpanded
|
|
71
|
+
? '<svg width="12" height="12" viewBox="0 0 12 12"><path d="M2 4l4 4 4-4" stroke="currentColor" fill="none"/></svg>'
|
|
72
|
+
: '<svg width="12" height="12" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" stroke="currentColor" fill="none"/></svg>';
|
|
73
|
+
expandBtn.title = this.cell.state.isExpanded ? "Collapse" : "Expand";
|
|
74
|
+
expandBtn.addEventListener("click", () => this.handleToggleExpanded());
|
|
75
|
+
leftSide.appendChild(expandBtn);
|
|
76
|
+
const countSpan = document.createElement("span");
|
|
77
|
+
countSpan.className = "notebook-cell-child-count";
|
|
78
|
+
countSpan.textContent = `(${this.cell.children.length})`;
|
|
79
|
+
leftSide.appendChild(countSpan);
|
|
80
|
+
}
|
|
81
|
+
header.appendChild(leftSide);
|
|
82
|
+
const controls = this.createControls();
|
|
83
|
+
header.appendChild(controls);
|
|
84
|
+
this.element.appendChild(header);
|
|
85
|
+
}
|
|
86
|
+
createBadge() {
|
|
87
|
+
const badgeInfo = getCellTypeBadge(this.cell.state.type);
|
|
88
|
+
const badge = document.createElement("span");
|
|
89
|
+
badge.className = `notebook-cell-badge ${badgeInfo.cssClass}`;
|
|
90
|
+
badge.textContent = badgeInfo.label;
|
|
91
|
+
return badge;
|
|
92
|
+
}
|
|
93
|
+
createControls() {
|
|
94
|
+
var _a;
|
|
95
|
+
const controls = document.createElement("div");
|
|
96
|
+
controls.className = "notebook-cell-controls";
|
|
97
|
+
if ((_a = this.config.cssClasses) === null || _a === void 0 ? void 0 : _a.cellControls) {
|
|
98
|
+
controls.className += " " + this.config.cssClasses.cellControls;
|
|
99
|
+
}
|
|
100
|
+
if (this.config.showMoveButtons && !this.cell.state.isEditing) {
|
|
101
|
+
const moveUpBtn = document.createElement("button");
|
|
102
|
+
moveUpBtn.className = "notebook-btn notebook-move-btn";
|
|
103
|
+
moveUpBtn.innerHTML = "↑";
|
|
104
|
+
moveUpBtn.title = "Move up";
|
|
105
|
+
moveUpBtn.addEventListener("click", () => { var _a, _b; return (_b = (_a = this.config).onMoveUp) === null || _b === void 0 ? void 0 : _b.call(_a, this.cell.state.id); });
|
|
106
|
+
controls.appendChild(moveUpBtn);
|
|
107
|
+
const moveDownBtn = document.createElement("button");
|
|
108
|
+
moveDownBtn.className = "notebook-btn notebook-move-btn";
|
|
109
|
+
moveDownBtn.innerHTML = "↓";
|
|
110
|
+
moveDownBtn.title = "Move down";
|
|
111
|
+
moveDownBtn.addEventListener("click", () => { var _a, _b; return (_b = (_a = this.config).onMoveDown) === null || _b === void 0 ? void 0 : _b.call(_a, this.cell.state.id); });
|
|
112
|
+
controls.appendChild(moveDownBtn);
|
|
113
|
+
}
|
|
114
|
+
const editBtn = document.createElement("button");
|
|
115
|
+
editBtn.className = "notebook-btn notebook-edit-btn";
|
|
116
|
+
if (this.cell.state.isEditing) {
|
|
117
|
+
editBtn.textContent = "Cancel";
|
|
118
|
+
editBtn.addEventListener("click", () => this.handleCancelEdit());
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
editBtn.textContent = "Edit";
|
|
122
|
+
editBtn.addEventListener("click", () => this.handleStartEdit());
|
|
123
|
+
}
|
|
124
|
+
controls.appendChild(editBtn);
|
|
125
|
+
if (this.config.showDeleteButton && !this.cell.state.isEditing) {
|
|
126
|
+
const deleteBtn = document.createElement("button");
|
|
127
|
+
deleteBtn.className = "notebook-btn notebook-delete-btn";
|
|
128
|
+
deleteBtn.textContent = "Delete";
|
|
129
|
+
deleteBtn.addEventListener("click", () => this.handleDelete());
|
|
130
|
+
controls.appendChild(deleteBtn);
|
|
131
|
+
}
|
|
132
|
+
return controls;
|
|
133
|
+
}
|
|
134
|
+
renderError() {
|
|
135
|
+
var _a;
|
|
136
|
+
const errorDiv = document.createElement("div");
|
|
137
|
+
errorDiv.className = "notebook-cell-error-message";
|
|
138
|
+
if ((_a = this.config.cssClasses) === null || _a === void 0 ? void 0 : _a.errorMessage) {
|
|
139
|
+
errorDiv.className += " " + this.config.cssClasses.errorMessage;
|
|
140
|
+
}
|
|
141
|
+
errorDiv.textContent = this.cell.state.errorMessage || "Error";
|
|
142
|
+
this.element.appendChild(errorDiv);
|
|
143
|
+
}
|
|
144
|
+
renderContent() {
|
|
145
|
+
var _a;
|
|
146
|
+
const content = document.createElement("div");
|
|
147
|
+
content.className = "notebook-cell-content";
|
|
148
|
+
if ((_a = this.config.cssClasses) === null || _a === void 0 ? void 0 : _a.cellContent) {
|
|
149
|
+
content.className += " " + this.config.cssClasses.cellContent;
|
|
150
|
+
}
|
|
151
|
+
if (this.cell.state.isEditing) {
|
|
152
|
+
this.renderEditMode(content);
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
this.renderPreviewMode(content);
|
|
156
|
+
}
|
|
157
|
+
this.element.appendChild(content);
|
|
158
|
+
}
|
|
159
|
+
renderPreviewMode(container) {
|
|
160
|
+
if (isRawBlock(this.cell.blockItem)) {
|
|
161
|
+
const rawBlock = this.cell.blockItem;
|
|
162
|
+
const contentDiv = document.createElement("div");
|
|
163
|
+
contentDiv.className = "notebook-rawblock-content";
|
|
164
|
+
if (this.config.markdownParser && rawBlock.contentType === "md") {
|
|
165
|
+
contentDiv.innerHTML = this.config.markdownParser(rawBlock.content);
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
contentDiv.textContent = rawBlock.content;
|
|
169
|
+
}
|
|
170
|
+
container.appendChild(contentDiv);
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
const preview = document.createElement("div");
|
|
174
|
+
preview.className = "notebook-notation-preview";
|
|
175
|
+
if (isLine(this.cell.blockItem)) {
|
|
176
|
+
preview.textContent = "[Line content]";
|
|
177
|
+
}
|
|
178
|
+
else if (isBlock(this.cell.blockItem)) {
|
|
179
|
+
const block = this.cell.blockItem;
|
|
180
|
+
const itemCount = block.blockItems.length;
|
|
181
|
+
preview.textContent = `[${block.blockType}: ${itemCount} item${itemCount !== 1 ? "s" : ""}]`;
|
|
182
|
+
}
|
|
183
|
+
container.appendChild(preview);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
renderEditMode(container) {
|
|
187
|
+
var _a;
|
|
188
|
+
this.editTextarea = document.createElement("textarea");
|
|
189
|
+
this.editTextarea.className = "notebook-edit-textarea";
|
|
190
|
+
if ((_a = this.config.cssClasses) === null || _a === void 0 ? void 0 : _a.editTextarea) {
|
|
191
|
+
this.editTextarea.className += " " + this.config.cssClasses.editTextarea;
|
|
192
|
+
}
|
|
193
|
+
this.editTextarea.value = this.cell.source;
|
|
194
|
+
this.editTextarea.rows = Math.max(3, this.cell.source.split("\n").length + 1);
|
|
195
|
+
container.appendChild(this.editTextarea);
|
|
196
|
+
const actions = document.createElement("div");
|
|
197
|
+
actions.className = "notebook-edit-actions";
|
|
198
|
+
const applyBtn = document.createElement("button");
|
|
199
|
+
applyBtn.className = "notebook-btn notebook-apply-btn";
|
|
200
|
+
applyBtn.textContent = "Apply";
|
|
201
|
+
applyBtn.addEventListener("click", () => this.handleApplyEdit());
|
|
202
|
+
actions.appendChild(applyBtn);
|
|
203
|
+
const cancelBtn = document.createElement("button");
|
|
204
|
+
cancelBtn.className = "notebook-btn notebook-cancel-btn";
|
|
205
|
+
cancelBtn.textContent = "Cancel";
|
|
206
|
+
cancelBtn.addEventListener("click", () => this.handleCancelEdit());
|
|
207
|
+
actions.appendChild(cancelBtn);
|
|
208
|
+
container.appendChild(actions);
|
|
209
|
+
setTimeout(() => { var _a; return (_a = this.editTextarea) === null || _a === void 0 ? void 0 : _a.focus(); }, 0);
|
|
210
|
+
}
|
|
211
|
+
renderChildren() {
|
|
212
|
+
const childrenContainer = document.createElement("div");
|
|
213
|
+
childrenContainer.className = "notebook-cell-children";
|
|
214
|
+
this.element.appendChild(childrenContainer);
|
|
215
|
+
this.childCells = [];
|
|
216
|
+
for (const childModel of this.cell.children) {
|
|
217
|
+
if (this.config.createChildCell) {
|
|
218
|
+
const childCell = this.config.createChildCell(childModel, childrenContainer);
|
|
219
|
+
this.childCells.push(childCell);
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
const childCell = new NotebookCell(childModel, this.config);
|
|
223
|
+
childrenContainer.appendChild(childCell.element);
|
|
224
|
+
this.childCells.push(childCell);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
handleStartEdit() {
|
|
229
|
+
var _a, _b;
|
|
230
|
+
(_b = (_a = this.config).onStartEdit) === null || _b === void 0 ? void 0 : _b.call(_a, this.cell.state.id);
|
|
231
|
+
}
|
|
232
|
+
handleApplyEdit() {
|
|
233
|
+
var _a, _b, _c;
|
|
234
|
+
const newSource = ((_a = this.editTextarea) === null || _a === void 0 ? void 0 : _a.value) || "";
|
|
235
|
+
(_c = (_b = this.config).onApplyEdit) === null || _c === void 0 ? void 0 : _c.call(_b, this.cell.state.id, newSource);
|
|
236
|
+
}
|
|
237
|
+
handleCancelEdit() {
|
|
238
|
+
var _a, _b;
|
|
239
|
+
(_b = (_a = this.config).onCancelEdit) === null || _b === void 0 ? void 0 : _b.call(_a, this.cell.state.id);
|
|
240
|
+
}
|
|
241
|
+
handleDelete() {
|
|
242
|
+
var _a, _b;
|
|
243
|
+
(_b = (_a = this.config).onDelete) === null || _b === void 0 ? void 0 : _b.call(_a, this.cell.state.id);
|
|
244
|
+
}
|
|
245
|
+
handleToggleExpanded() {
|
|
246
|
+
var _a, _b;
|
|
247
|
+
(_b = (_a = this.config).onToggleExpanded) === null || _b === void 0 ? void 0 : _b.call(_a, this.cell.state.id);
|
|
248
|
+
}
|
|
249
|
+
getEditSource() {
|
|
250
|
+
var _a;
|
|
251
|
+
return ((_a = this.editTextarea) === null || _a === void 0 ? void 0 : _a.value) || this.cell.source;
|
|
252
|
+
}
|
|
253
|
+
update(newCell) {
|
|
254
|
+
this.cell = newCell;
|
|
255
|
+
this.element.className = this.buildRootClassName();
|
|
256
|
+
this.render();
|
|
257
|
+
}
|
|
258
|
+
destroy() {
|
|
259
|
+
for (const child of this.childCells) {
|
|
260
|
+
child.destroy();
|
|
261
|
+
}
|
|
262
|
+
this.childCells = [];
|
|
263
|
+
this.element.remove();
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
//# sourceMappingURL=NotebookCell.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NotebookCell.js","sourceRoot":"","sources":["../../../../src/web/components/NotebookCell.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * NotebookCell - Individual cell component for notebook-style editing.\n *\n * A cell represents a single BlockItem (Block, Line, or RawBlock) with\n * preview/edit modes, controls, and optional nested children.\n */\n\nimport { isBlock, isLine, isRawBlock, Block, RawBlock } from \"../../block\";\nimport { CellModel, CellTypeBadge, getCellTypeBadge, NotebookCssClasses } from \"../types/notebook\";\n\n/**\n * Configuration for NotebookCell.\n */\nexport interface NotebookCellConfig {\n /** CSS classes for cell elements */\n cssClasses?: NotebookCssClasses;\n\n /** Markdown parser for RawBlock content */\n markdownParser?: (content: string) => string;\n\n /** Whether to show delete button */\n showDeleteButton?: boolean;\n\n /** Whether to show move buttons (for reordering) */\n showMoveButtons?: boolean;\n\n /** Callback when edit is started */\n onStartEdit?: (cellId: string) => void;\n\n /** Callback when edit is applied */\n onApplyEdit?: (cellId: string, newSource: string) => void;\n\n /** Callback when edit is cancelled */\n onCancelEdit?: (cellId: string) => void;\n\n /** Callback when cell is deleted */\n onDelete?: (cellId: string) => void;\n\n /** Callback when cell is moved up */\n onMoveUp?: (cellId: string) => void;\n\n /** Callback when cell is moved down */\n onMoveDown?: (cellId: string) => void;\n\n /** Callback when expand/collapse is toggled */\n onToggleExpanded?: (cellId: string) => void;\n\n /** Factory to create child cells (for nesting) */\n createChildCell?: (cell: CellModel, parent: HTMLElement) => NotebookCell;\n}\n\n/**\n * NotebookCell renders a single cell with header, content, and controls.\n *\n * Features:\n * - Type badge showing block type\n * - Preview mode showing rendered content\n * - Edit mode with textarea\n * - Controls for edit, delete, move\n * - Support for nested children\n */\nexport default class NotebookCell {\n /** The root element for this cell */\n readonly element: HTMLDivElement;\n\n /** The cell model */\n readonly cell: CellModel;\n\n /** Configuration */\n readonly config: NotebookCellConfig;\n\n /** Child cell instances (for nested blocks) */\n private childCells: NotebookCell[] = [];\n\n /** Reference to textarea in edit mode */\n private editTextarea: HTMLTextAreaElement | null = null;\n\n /**\n * Creates a new NotebookCell.\n *\n * @param cell The cell model to render\n * @param config Configuration options\n */\n constructor(cell: CellModel, config: NotebookCellConfig = {}) {\n this.cell = cell;\n this.config = config;\n\n // Create root element\n this.element = document.createElement(\"div\");\n this.element.className = this.buildRootClassName();\n this.element.dataset.cellId = cell.state.id;\n this.element.dataset.depth = String(cell.state.depth);\n\n // Render content\n this.render();\n }\n\n /**\n * Builds the root element class name.\n */\n private buildRootClassName(): string {\n const classes = [\n \"notebook-cell\",\n `notebook-cell-${this.cell.state.type}`,\n `notebook-cell-depth-${this.cell.state.depth}`,\n ];\n\n if (this.cell.state.isEditing) {\n classes.push(\"notebook-cell-editing\");\n }\n if (this.cell.state.hasError) {\n classes.push(\"notebook-cell-error\");\n }\n if (!this.cell.state.isExpanded && this.cell.children.length > 0) {\n classes.push(\"notebook-cell-collapsed\");\n }\n\n if (this.config.cssClasses?.cell) {\n classes.push(this.config.cssClasses.cell);\n }\n\n return classes.join(\" \");\n }\n\n /**\n * Renders the cell content.\n */\n private render(): void {\n this.element.innerHTML = \"\";\n\n // Render header\n this.renderHeader();\n\n // Render error message if any\n if (this.cell.state.hasError && this.cell.state.errorMessage) {\n this.renderError();\n }\n\n // Render content (preview or edit mode)\n this.renderContent();\n\n // Render children if expanded\n if (this.cell.state.isExpanded && this.cell.children.length > 0) {\n this.renderChildren();\n }\n }\n\n /**\n * Renders the cell header.\n */\n private renderHeader(): void {\n const header = document.createElement(\"div\");\n header.className = \"notebook-cell-header\";\n if (this.config.cssClasses?.cellHeader) {\n header.className += \" \" + this.config.cssClasses.cellHeader;\n }\n\n // Left side: badge, name, expand/collapse\n const leftSide = document.createElement(\"div\");\n leftSide.className = \"notebook-cell-header-left\";\n\n // Type badge\n const badge = this.createBadge();\n leftSide.appendChild(badge);\n\n // Name (if block has one)\n if (isBlock(this.cell.blockItem)) {\n const block = this.cell.blockItem as Block;\n if (block.name) {\n const nameSpan = document.createElement(\"span\");\n nameSpan.className = \"notebook-cell-name\";\n nameSpan.textContent = block.name;\n leftSide.appendChild(nameSpan);\n }\n }\n\n // Expand/collapse toggle for cells with children\n if (this.cell.children.length > 0) {\n const expandBtn = document.createElement(\"button\");\n expandBtn.className = \"notebook-btn notebook-expand-btn\";\n expandBtn.innerHTML = this.cell.state.isExpanded\n ? '<svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\"><path d=\"M2 4l4 4 4-4\" stroke=\"currentColor\" fill=\"none\"/></svg>'\n : '<svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\"><path d=\"M4 2l4 4-4 4\" stroke=\"currentColor\" fill=\"none\"/></svg>';\n expandBtn.title = this.cell.state.isExpanded ? \"Collapse\" : \"Expand\";\n expandBtn.addEventListener(\"click\", () => this.handleToggleExpanded());\n leftSide.appendChild(expandBtn);\n\n // Child count\n const countSpan = document.createElement(\"span\");\n countSpan.className = \"notebook-cell-child-count\";\n countSpan.textContent = `(${this.cell.children.length})`;\n leftSide.appendChild(countSpan);\n }\n\n header.appendChild(leftSide);\n\n // Right side: controls\n const controls = this.createControls();\n header.appendChild(controls);\n\n this.element.appendChild(header);\n }\n\n /**\n * Creates the type badge element.\n */\n private createBadge(): HTMLSpanElement {\n const badgeInfo = getCellTypeBadge(this.cell.state.type);\n const badge = document.createElement(\"span\");\n badge.className = `notebook-cell-badge ${badgeInfo.cssClass}`;\n badge.textContent = badgeInfo.label;\n return badge;\n }\n\n /**\n * Creates the controls container.\n */\n private createControls(): HTMLDivElement {\n const controls = document.createElement(\"div\");\n controls.className = \"notebook-cell-controls\";\n if (this.config.cssClasses?.cellControls) {\n controls.className += \" \" + this.config.cssClasses.cellControls;\n }\n\n // Move buttons (if enabled and not in edit mode)\n if (this.config.showMoveButtons && !this.cell.state.isEditing) {\n const moveUpBtn = document.createElement(\"button\");\n moveUpBtn.className = \"notebook-btn notebook-move-btn\";\n moveUpBtn.innerHTML = \"↑\";\n moveUpBtn.title = \"Move up\";\n moveUpBtn.addEventListener(\"click\", () => this.config.onMoveUp?.(this.cell.state.id));\n controls.appendChild(moveUpBtn);\n\n const moveDownBtn = document.createElement(\"button\");\n moveDownBtn.className = \"notebook-btn notebook-move-btn\";\n moveDownBtn.innerHTML = \"↓\";\n moveDownBtn.title = \"Move down\";\n moveDownBtn.addEventListener(\"click\", () => this.config.onMoveDown?.(this.cell.state.id));\n controls.appendChild(moveDownBtn);\n }\n\n // Edit/Cancel button\n const editBtn = document.createElement(\"button\");\n editBtn.className = \"notebook-btn notebook-edit-btn\";\n if (this.cell.state.isEditing) {\n editBtn.textContent = \"Cancel\";\n editBtn.addEventListener(\"click\", () => this.handleCancelEdit());\n } else {\n editBtn.textContent = \"Edit\";\n editBtn.addEventListener(\"click\", () => this.handleStartEdit());\n }\n controls.appendChild(editBtn);\n\n // Delete button (if enabled and not in edit mode)\n if (this.config.showDeleteButton && !this.cell.state.isEditing) {\n const deleteBtn = document.createElement(\"button\");\n deleteBtn.className = \"notebook-btn notebook-delete-btn\";\n deleteBtn.textContent = \"Delete\";\n deleteBtn.addEventListener(\"click\", () => this.handleDelete());\n controls.appendChild(deleteBtn);\n }\n\n return controls;\n }\n\n /**\n * Renders the error message.\n */\n private renderError(): void {\n const errorDiv = document.createElement(\"div\");\n errorDiv.className = \"notebook-cell-error-message\";\n if (this.config.cssClasses?.errorMessage) {\n errorDiv.className += \" \" + this.config.cssClasses.errorMessage;\n }\n errorDiv.textContent = this.cell.state.errorMessage || \"Error\";\n this.element.appendChild(errorDiv);\n }\n\n /**\n * Renders the cell content (preview or edit mode).\n */\n private renderContent(): void {\n const content = document.createElement(\"div\");\n content.className = \"notebook-cell-content\";\n if (this.config.cssClasses?.cellContent) {\n content.className += \" \" + this.config.cssClasses.cellContent;\n }\n\n if (this.cell.state.isEditing) {\n this.renderEditMode(content);\n } else {\n this.renderPreviewMode(content);\n }\n\n this.element.appendChild(content);\n }\n\n /**\n * Renders preview mode content.\n */\n private renderPreviewMode(container: HTMLElement): void {\n if (isRawBlock(this.cell.blockItem)) {\n const rawBlock = this.cell.blockItem as RawBlock;\n const contentDiv = document.createElement(\"div\");\n contentDiv.className = \"notebook-rawblock-content\";\n\n if (this.config.markdownParser && rawBlock.contentType === \"md\") {\n contentDiv.innerHTML = this.config.markdownParser(rawBlock.content);\n } else {\n contentDiv.textContent = rawBlock.content;\n }\n container.appendChild(contentDiv);\n } else {\n // For Line and Block, show a placeholder or summary\n const preview = document.createElement(\"div\");\n preview.className = \"notebook-notation-preview\";\n\n if (isLine(this.cell.blockItem)) {\n preview.textContent = \"[Line content]\";\n } else if (isBlock(this.cell.blockItem)) {\n const block = this.cell.blockItem as Block;\n const itemCount = block.blockItems.length;\n preview.textContent = `[${block.blockType}: ${itemCount} item${itemCount !== 1 ? \"s\" : \"\"}]`;\n }\n container.appendChild(preview);\n }\n }\n\n /**\n * Renders edit mode content.\n */\n private renderEditMode(container: HTMLElement): void {\n // Textarea for editing\n this.editTextarea = document.createElement(\"textarea\");\n this.editTextarea.className = \"notebook-edit-textarea\";\n if (this.config.cssClasses?.editTextarea) {\n this.editTextarea.className += \" \" + this.config.cssClasses.editTextarea;\n }\n this.editTextarea.value = this.cell.source;\n this.editTextarea.rows = Math.max(3, this.cell.source.split(\"\\n\").length + 1);\n container.appendChild(this.editTextarea);\n\n // Action buttons\n const actions = document.createElement(\"div\");\n actions.className = \"notebook-edit-actions\";\n\n const applyBtn = document.createElement(\"button\");\n applyBtn.className = \"notebook-btn notebook-apply-btn\";\n applyBtn.textContent = \"Apply\";\n applyBtn.addEventListener(\"click\", () => this.handleApplyEdit());\n actions.appendChild(applyBtn);\n\n const cancelBtn = document.createElement(\"button\");\n cancelBtn.className = \"notebook-btn notebook-cancel-btn\";\n cancelBtn.textContent = \"Cancel\";\n cancelBtn.addEventListener(\"click\", () => this.handleCancelEdit());\n actions.appendChild(cancelBtn);\n\n container.appendChild(actions);\n\n // Focus textarea\n setTimeout(() => this.editTextarea?.focus(), 0);\n }\n\n /**\n * Renders child cells.\n */\n private renderChildren(): void {\n const childrenContainer = document.createElement(\"div\");\n childrenContainer.className = \"notebook-cell-children\";\n this.element.appendChild(childrenContainer);\n\n // Clear existing child cells\n this.childCells = [];\n\n // Create child cells\n for (const childModel of this.cell.children) {\n if (this.config.createChildCell) {\n const childCell = this.config.createChildCell(childModel, childrenContainer);\n this.childCells.push(childCell);\n } else {\n // Default: create NotebookCell with same config\n const childCell = new NotebookCell(childModel, this.config);\n childrenContainer.appendChild(childCell.element);\n this.childCells.push(childCell);\n }\n }\n }\n\n // ============================================\n // Event handlers\n // ============================================\n\n private handleStartEdit(): void {\n this.config.onStartEdit?.(this.cell.state.id);\n }\n\n private handleApplyEdit(): void {\n const newSource = this.editTextarea?.value || \"\";\n this.config.onApplyEdit?.(this.cell.state.id, newSource);\n }\n\n private handleCancelEdit(): void {\n this.config.onCancelEdit?.(this.cell.state.id);\n }\n\n private handleDelete(): void {\n this.config.onDelete?.(this.cell.state.id);\n }\n\n private handleToggleExpanded(): void {\n this.config.onToggleExpanded?.(this.cell.state.id);\n }\n\n // ============================================\n // Public methods\n // ============================================\n\n /**\n * Gets the current source text from the edit textarea.\n */\n getEditSource(): string {\n return this.editTextarea?.value || this.cell.source;\n }\n\n /**\n * Updates the cell with a new model and re-renders.\n */\n update(newCell: CellModel): void {\n // Update reference (cast away readonly for internal update)\n (this as { cell: CellModel }).cell = newCell;\n\n // Update class name\n this.element.className = this.buildRootClassName();\n\n // Re-render\n this.render();\n }\n\n /**\n * Destroys the cell and cleans up resources.\n */\n destroy(): void {\n // Destroy child cells\n for (const child of this.childCells) {\n child.destroy();\n }\n this.childCells = [];\n\n // Remove element\n this.element.remove();\n }\n}\n"]}
|