@fieldnotes/core 0.9.0 → 0.10.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/dist/index.cjs +627 -204
- package/dist/index.d.cts +63 -2
- package/dist/index.d.ts +63 -2
- package/dist/index.js +617 -204
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -169,6 +169,120 @@ var Quadtree = class {
|
|
|
169
169
|
}
|
|
170
170
|
};
|
|
171
171
|
|
|
172
|
+
// src/elements/note-sanitizer.ts
|
|
173
|
+
var BOLD_TAGS = /* @__PURE__ */ new Set(["b", "strong"]);
|
|
174
|
+
var ITALIC_TAGS = /* @__PURE__ */ new Set(["i", "em"]);
|
|
175
|
+
var UNDERLINE_TAGS = /* @__PURE__ */ new Set(["u"]);
|
|
176
|
+
var STRIKE_TAGS = /* @__PURE__ */ new Set(["s", "strike", "del"]);
|
|
177
|
+
var BLOCK_TAGS = /* @__PURE__ */ new Set(["div"]);
|
|
178
|
+
function parseStyledRuns(html, baseFontSize) {
|
|
179
|
+
if (!html) return [];
|
|
180
|
+
const doc = new DOMParser().parseFromString(html, "text/html");
|
|
181
|
+
const runs = [];
|
|
182
|
+
const baseStyle = {
|
|
183
|
+
bold: false,
|
|
184
|
+
italic: false,
|
|
185
|
+
underline: false,
|
|
186
|
+
strikethrough: false,
|
|
187
|
+
fontSize: baseFontSize
|
|
188
|
+
};
|
|
189
|
+
walkNodes(doc.body, baseStyle, runs);
|
|
190
|
+
return runs;
|
|
191
|
+
}
|
|
192
|
+
function walkNodes(node, style, runs) {
|
|
193
|
+
for (const child of Array.from(node.childNodes)) {
|
|
194
|
+
if (child.nodeType === Node.TEXT_NODE) {
|
|
195
|
+
const text = child.textContent ?? "";
|
|
196
|
+
if (text) {
|
|
197
|
+
runs.push({ text, ...style });
|
|
198
|
+
}
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
if (child.nodeType !== Node.ELEMENT_NODE) continue;
|
|
202
|
+
const el = child;
|
|
203
|
+
const tag = el.tagName.toLowerCase();
|
|
204
|
+
if (tag === "br") {
|
|
205
|
+
runs.push({ text: "\n", ...style });
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
if (BLOCK_TAGS.has(tag) && runs.length > 0) {
|
|
209
|
+
const lastRun = runs[runs.length - 1];
|
|
210
|
+
if (lastRun && !lastRun.text.endsWith("\n")) {
|
|
211
|
+
runs.push({ text: "\n", ...style });
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
const childStyle = { ...style };
|
|
215
|
+
if (BOLD_TAGS.has(tag)) childStyle.bold = true;
|
|
216
|
+
if (ITALIC_TAGS.has(tag)) childStyle.italic = true;
|
|
217
|
+
if (UNDERLINE_TAGS.has(tag)) childStyle.underline = true;
|
|
218
|
+
if (STRIKE_TAGS.has(tag)) childStyle.strikethrough = true;
|
|
219
|
+
if (tag === "span") {
|
|
220
|
+
const fontSize = el.style.fontSize;
|
|
221
|
+
if (fontSize) {
|
|
222
|
+
childStyle.fontSize = parseInt(fontSize, 10) || style.fontSize;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
walkNodes(el, childStyle, runs);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
var ALLOWED_TAGS = /* @__PURE__ */ new Set([
|
|
229
|
+
"b",
|
|
230
|
+
"strong",
|
|
231
|
+
"i",
|
|
232
|
+
"em",
|
|
233
|
+
"u",
|
|
234
|
+
"s",
|
|
235
|
+
"strike",
|
|
236
|
+
"del",
|
|
237
|
+
"span",
|
|
238
|
+
"br",
|
|
239
|
+
"div"
|
|
240
|
+
]);
|
|
241
|
+
function sanitizeNoteHtml(html) {
|
|
242
|
+
if (!html) return "";
|
|
243
|
+
const doc = new DOMParser().parseFromString(html, "text/html");
|
|
244
|
+
sanitizeNode(doc.body);
|
|
245
|
+
return doc.body.innerHTML;
|
|
246
|
+
}
|
|
247
|
+
function sanitizeNode(node) {
|
|
248
|
+
const children = Array.from(node.childNodes);
|
|
249
|
+
for (const child of children) {
|
|
250
|
+
if (child.nodeType === Node.TEXT_NODE) continue;
|
|
251
|
+
if (child.nodeType !== Node.ELEMENT_NODE) {
|
|
252
|
+
child.remove();
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
const el = child;
|
|
256
|
+
const tag = el.tagName.toLowerCase();
|
|
257
|
+
if (!ALLOWED_TAGS.has(tag)) {
|
|
258
|
+
const fragment = document.createDocumentFragment();
|
|
259
|
+
while (el.firstChild) {
|
|
260
|
+
fragment.appendChild(el.firstChild);
|
|
261
|
+
}
|
|
262
|
+
node.replaceChild(fragment, el);
|
|
263
|
+
sanitizeNode(node);
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
sanitizeAttributes(el, tag);
|
|
267
|
+
sanitizeNode(el);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
function sanitizeAttributes(el, tag) {
|
|
271
|
+
const attrs = Array.from(el.attributes);
|
|
272
|
+
for (const attr of attrs) {
|
|
273
|
+
if (tag === "span" && attr.name === "style") {
|
|
274
|
+
const fontSize = el.style.fontSize;
|
|
275
|
+
if (fontSize) {
|
|
276
|
+
el.setAttribute("style", `font-size: ${fontSize};`);
|
|
277
|
+
} else {
|
|
278
|
+
el.removeAttribute("style");
|
|
279
|
+
}
|
|
280
|
+
continue;
|
|
281
|
+
}
|
|
282
|
+
el.removeAttribute(attr.name);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
172
286
|
// src/core/state-serializer.ts
|
|
173
287
|
var CURRENT_VERSION = 2;
|
|
174
288
|
function exportState(elements, camera, layers = []) {
|
|
@@ -231,7 +345,17 @@ function validateState(data) {
|
|
|
231
345
|
];
|
|
232
346
|
}
|
|
233
347
|
}
|
|
234
|
-
var VALID_TYPES = /* @__PURE__ */ new Set([
|
|
348
|
+
var VALID_TYPES = /* @__PURE__ */ new Set([
|
|
349
|
+
"stroke",
|
|
350
|
+
"note",
|
|
351
|
+
"arrow",
|
|
352
|
+
"image",
|
|
353
|
+
"html",
|
|
354
|
+
"text",
|
|
355
|
+
"shape",
|
|
356
|
+
"grid",
|
|
357
|
+
"template"
|
|
358
|
+
]);
|
|
235
359
|
function validateElement(el) {
|
|
236
360
|
if (!el || typeof el !== "object") {
|
|
237
361
|
throw new Error("Invalid element: expected an object");
|
|
@@ -281,6 +405,9 @@ function migrateElement(obj) {
|
|
|
281
405
|
if (obj["type"] === "note" && typeof obj["textColor"] !== "string") {
|
|
282
406
|
obj["textColor"] = "#000000";
|
|
283
407
|
}
|
|
408
|
+
if (obj["type"] === "note" && typeof obj["text"] === "string") {
|
|
409
|
+
obj["text"] = sanitizeNoteHtml(obj["text"]);
|
|
410
|
+
}
|
|
284
411
|
}
|
|
285
412
|
|
|
286
413
|
// src/core/snap.ts
|
|
@@ -2190,7 +2317,359 @@ var ElementRenderer = class {
|
|
|
2190
2317
|
}
|
|
2191
2318
|
};
|
|
2192
2319
|
|
|
2320
|
+
// src/elements/create-id.ts
|
|
2321
|
+
var counter = 0;
|
|
2322
|
+
function createId(prefix) {
|
|
2323
|
+
return `${prefix}_${Date.now().toString(36)}_${(counter++).toString(36)}`;
|
|
2324
|
+
}
|
|
2325
|
+
|
|
2326
|
+
// src/elements/element-factory.ts
|
|
2327
|
+
var DEFAULT_NOTE_FONT_SIZE = 18;
|
|
2328
|
+
function createStroke(input) {
|
|
2329
|
+
return {
|
|
2330
|
+
id: createId("stroke"),
|
|
2331
|
+
type: "stroke",
|
|
2332
|
+
position: input.position ?? { x: 0, y: 0 },
|
|
2333
|
+
zIndex: input.zIndex ?? 0,
|
|
2334
|
+
locked: input.locked ?? false,
|
|
2335
|
+
layerId: input.layerId ?? "",
|
|
2336
|
+
points: input.points,
|
|
2337
|
+
color: input.color ?? "#000000",
|
|
2338
|
+
width: input.width ?? 2,
|
|
2339
|
+
opacity: input.opacity ?? 1
|
|
2340
|
+
};
|
|
2341
|
+
}
|
|
2342
|
+
function createNote(input) {
|
|
2343
|
+
return {
|
|
2344
|
+
id: createId("note"),
|
|
2345
|
+
type: "note",
|
|
2346
|
+
position: input.position,
|
|
2347
|
+
zIndex: input.zIndex ?? 0,
|
|
2348
|
+
locked: input.locked ?? false,
|
|
2349
|
+
layerId: input.layerId ?? "",
|
|
2350
|
+
size: input.size ?? { w: 200, h: 100 },
|
|
2351
|
+
text: input.text ?? "",
|
|
2352
|
+
backgroundColor: input.backgroundColor ?? "#ffeb3b",
|
|
2353
|
+
textColor: input.textColor ?? "#000000",
|
|
2354
|
+
fontSize: input.fontSize ?? DEFAULT_NOTE_FONT_SIZE
|
|
2355
|
+
};
|
|
2356
|
+
}
|
|
2357
|
+
function createArrow(input) {
|
|
2358
|
+
const bend = input.bend ?? 0;
|
|
2359
|
+
const result = {
|
|
2360
|
+
id: createId("arrow"),
|
|
2361
|
+
type: "arrow",
|
|
2362
|
+
position: input.position ?? { x: 0, y: 0 },
|
|
2363
|
+
zIndex: input.zIndex ?? 0,
|
|
2364
|
+
locked: input.locked ?? false,
|
|
2365
|
+
layerId: input.layerId ?? "",
|
|
2366
|
+
from: input.from,
|
|
2367
|
+
to: input.to,
|
|
2368
|
+
bend,
|
|
2369
|
+
color: input.color ?? "#000000",
|
|
2370
|
+
width: input.width ?? 2,
|
|
2371
|
+
cachedControlPoint: getArrowControlPoint(input.from, input.to, bend)
|
|
2372
|
+
};
|
|
2373
|
+
if (input.fromBinding) result.fromBinding = input.fromBinding;
|
|
2374
|
+
if (input.toBinding) result.toBinding = input.toBinding;
|
|
2375
|
+
return result;
|
|
2376
|
+
}
|
|
2377
|
+
function createImage(input) {
|
|
2378
|
+
return {
|
|
2379
|
+
id: createId("image"),
|
|
2380
|
+
type: "image",
|
|
2381
|
+
position: input.position,
|
|
2382
|
+
zIndex: input.zIndex ?? 0,
|
|
2383
|
+
locked: input.locked ?? false,
|
|
2384
|
+
layerId: input.layerId ?? "",
|
|
2385
|
+
size: input.size,
|
|
2386
|
+
src: input.src
|
|
2387
|
+
};
|
|
2388
|
+
}
|
|
2389
|
+
function createHtmlElement(input) {
|
|
2390
|
+
const el = {
|
|
2391
|
+
id: createId("html"),
|
|
2392
|
+
type: "html",
|
|
2393
|
+
position: input.position,
|
|
2394
|
+
zIndex: input.zIndex ?? 0,
|
|
2395
|
+
locked: input.locked ?? false,
|
|
2396
|
+
layerId: input.layerId ?? "",
|
|
2397
|
+
size: input.size
|
|
2398
|
+
};
|
|
2399
|
+
if (input.domId) el.domId = input.domId;
|
|
2400
|
+
return el;
|
|
2401
|
+
}
|
|
2402
|
+
function createShape(input) {
|
|
2403
|
+
return {
|
|
2404
|
+
id: createId("shape"),
|
|
2405
|
+
type: "shape",
|
|
2406
|
+
position: input.position,
|
|
2407
|
+
zIndex: input.zIndex ?? 0,
|
|
2408
|
+
locked: input.locked ?? false,
|
|
2409
|
+
layerId: input.layerId ?? "",
|
|
2410
|
+
shape: input.shape ?? "rectangle",
|
|
2411
|
+
size: input.size,
|
|
2412
|
+
strokeColor: input.strokeColor ?? "#000000",
|
|
2413
|
+
strokeWidth: input.strokeWidth ?? 2,
|
|
2414
|
+
fillColor: input.fillColor ?? "none"
|
|
2415
|
+
};
|
|
2416
|
+
}
|
|
2417
|
+
function createGrid(input) {
|
|
2418
|
+
return {
|
|
2419
|
+
id: createId("grid"),
|
|
2420
|
+
type: "grid",
|
|
2421
|
+
position: input.position ?? { x: 0, y: 0 },
|
|
2422
|
+
zIndex: input.zIndex ?? 0,
|
|
2423
|
+
locked: input.locked ?? false,
|
|
2424
|
+
layerId: input.layerId ?? "",
|
|
2425
|
+
gridType: input.gridType ?? "square",
|
|
2426
|
+
hexOrientation: input.hexOrientation ?? "pointy",
|
|
2427
|
+
cellSize: input.cellSize ?? 40,
|
|
2428
|
+
strokeColor: input.strokeColor ?? "#000000",
|
|
2429
|
+
strokeWidth: input.strokeWidth ?? 1,
|
|
2430
|
+
opacity: input.opacity ?? 1
|
|
2431
|
+
};
|
|
2432
|
+
}
|
|
2433
|
+
function createText(input) {
|
|
2434
|
+
return {
|
|
2435
|
+
id: createId("text"),
|
|
2436
|
+
type: "text",
|
|
2437
|
+
position: input.position,
|
|
2438
|
+
zIndex: input.zIndex ?? 0,
|
|
2439
|
+
locked: input.locked ?? false,
|
|
2440
|
+
layerId: input.layerId ?? "",
|
|
2441
|
+
size: input.size ?? { w: 200, h: 28 },
|
|
2442
|
+
text: input.text ?? "",
|
|
2443
|
+
fontSize: input.fontSize ?? 16,
|
|
2444
|
+
color: input.color ?? "#1a1a1a",
|
|
2445
|
+
textAlign: input.textAlign ?? "left"
|
|
2446
|
+
};
|
|
2447
|
+
}
|
|
2448
|
+
function createTemplate(input) {
|
|
2449
|
+
return {
|
|
2450
|
+
id: createId("template"),
|
|
2451
|
+
type: "template",
|
|
2452
|
+
position: input.position,
|
|
2453
|
+
zIndex: input.zIndex ?? 0,
|
|
2454
|
+
locked: input.locked ?? false,
|
|
2455
|
+
layerId: input.layerId ?? "",
|
|
2456
|
+
templateShape: input.templateShape,
|
|
2457
|
+
radius: input.radius,
|
|
2458
|
+
angle: input.angle ?? 0,
|
|
2459
|
+
fillColor: input.fillColor ?? "rgba(255, 87, 34, 0.2)",
|
|
2460
|
+
strokeColor: input.strokeColor ?? "#FF5722",
|
|
2461
|
+
strokeWidth: input.strokeWidth ?? 2,
|
|
2462
|
+
opacity: input.opacity ?? 0.6,
|
|
2463
|
+
feetPerCell: input.feetPerCell,
|
|
2464
|
+
radiusFeet: input.radiusFeet
|
|
2465
|
+
};
|
|
2466
|
+
}
|
|
2467
|
+
|
|
2468
|
+
// src/elements/note-formatting.ts
|
|
2469
|
+
function toggleBold() {
|
|
2470
|
+
document.execCommand("bold");
|
|
2471
|
+
}
|
|
2472
|
+
function toggleItalic() {
|
|
2473
|
+
document.execCommand("italic");
|
|
2474
|
+
}
|
|
2475
|
+
function toggleUnderline() {
|
|
2476
|
+
document.execCommand("underline");
|
|
2477
|
+
}
|
|
2478
|
+
function toggleStrikethrough() {
|
|
2479
|
+
document.execCommand("strikeThrough");
|
|
2480
|
+
}
|
|
2481
|
+
function setFontSize(size) {
|
|
2482
|
+
const sel = window.getSelection();
|
|
2483
|
+
if (!sel || sel.rangeCount === 0) return;
|
|
2484
|
+
const range = sel.getRangeAt(0);
|
|
2485
|
+
if (range.collapsed) return;
|
|
2486
|
+
const span = document.createElement("span");
|
|
2487
|
+
span.style.fontSize = `${size}px`;
|
|
2488
|
+
try {
|
|
2489
|
+
range.surroundContents(span);
|
|
2490
|
+
} catch {
|
|
2491
|
+
span.appendChild(range.extractContents());
|
|
2492
|
+
range.insertNode(span);
|
|
2493
|
+
}
|
|
2494
|
+
}
|
|
2495
|
+
function getActiveFormats() {
|
|
2496
|
+
const query = (cmd) => {
|
|
2497
|
+
try {
|
|
2498
|
+
return document.queryCommandState(cmd);
|
|
2499
|
+
} catch {
|
|
2500
|
+
return false;
|
|
2501
|
+
}
|
|
2502
|
+
};
|
|
2503
|
+
return {
|
|
2504
|
+
bold: query("bold"),
|
|
2505
|
+
italic: query("italic"),
|
|
2506
|
+
underline: query("underline"),
|
|
2507
|
+
strikethrough: query("strikeThrough")
|
|
2508
|
+
};
|
|
2509
|
+
}
|
|
2510
|
+
|
|
2511
|
+
// src/elements/note-toolbar.ts
|
|
2512
|
+
var TOOLBAR_HEIGHT = 32;
|
|
2513
|
+
var TOOLBAR_GAP = 4;
|
|
2514
|
+
var FORMAT_BUTTONS = [
|
|
2515
|
+
{ label: "B", format: "bold", command: "bold" },
|
|
2516
|
+
{ label: "I", format: "italic", command: "italic" },
|
|
2517
|
+
{ label: "U", format: "underline", command: "underline" },
|
|
2518
|
+
{ label: "S", format: "strikethrough", command: "strikeThrough" }
|
|
2519
|
+
];
|
|
2520
|
+
var DEFAULT_FONT_SIZE_PRESETS = [
|
|
2521
|
+
{ label: "Small", size: 14 },
|
|
2522
|
+
{ label: "Normal", size: 18 },
|
|
2523
|
+
{ label: "Large", size: 24 },
|
|
2524
|
+
{ label: "Heading", size: 32 }
|
|
2525
|
+
];
|
|
2526
|
+
var NoteToolbar = class {
|
|
2527
|
+
el = null;
|
|
2528
|
+
anchor = null;
|
|
2529
|
+
selectionListener = null;
|
|
2530
|
+
fontSizePresets;
|
|
2531
|
+
constructor(fontSizePresets) {
|
|
2532
|
+
this.fontSizePresets = fontSizePresets ?? DEFAULT_FONT_SIZE_PRESETS;
|
|
2533
|
+
}
|
|
2534
|
+
show(anchor) {
|
|
2535
|
+
this.hide();
|
|
2536
|
+
this.anchor = anchor;
|
|
2537
|
+
this.el = this.createToolbarElement();
|
|
2538
|
+
document.body.appendChild(this.el);
|
|
2539
|
+
this.positionToolbar(anchor);
|
|
2540
|
+
this.selectionListener = () => this.updateActiveStates();
|
|
2541
|
+
document.addEventListener("selectionchange", this.selectionListener);
|
|
2542
|
+
}
|
|
2543
|
+
hide() {
|
|
2544
|
+
if (this.selectionListener) {
|
|
2545
|
+
document.removeEventListener("selectionchange", this.selectionListener);
|
|
2546
|
+
this.selectionListener = null;
|
|
2547
|
+
}
|
|
2548
|
+
if (this.el) {
|
|
2549
|
+
this.el.remove();
|
|
2550
|
+
this.el = null;
|
|
2551
|
+
}
|
|
2552
|
+
this.anchor = null;
|
|
2553
|
+
}
|
|
2554
|
+
getElement() {
|
|
2555
|
+
return this.el;
|
|
2556
|
+
}
|
|
2557
|
+
updatePosition(anchor) {
|
|
2558
|
+
if (this.el) {
|
|
2559
|
+
this.positionToolbar(anchor);
|
|
2560
|
+
}
|
|
2561
|
+
}
|
|
2562
|
+
createToolbarElement() {
|
|
2563
|
+
const toolbar = document.createElement("div");
|
|
2564
|
+
toolbar.dataset["noteToolbar"] = "";
|
|
2565
|
+
Object.assign(toolbar.style, {
|
|
2566
|
+
position: "fixed",
|
|
2567
|
+
display: "flex",
|
|
2568
|
+
alignItems: "center",
|
|
2569
|
+
gap: "2px",
|
|
2570
|
+
padding: "2px 4px",
|
|
2571
|
+
background: "#fff",
|
|
2572
|
+
border: "1px solid #ccc",
|
|
2573
|
+
borderRadius: "4px",
|
|
2574
|
+
boxShadow: "0 2px 8px rgba(0,0,0,0.15)",
|
|
2575
|
+
zIndex: "10000",
|
|
2576
|
+
height: `${TOOLBAR_HEIGHT}px`,
|
|
2577
|
+
userSelect: "none"
|
|
2578
|
+
});
|
|
2579
|
+
for (const btn of FORMAT_BUTTONS) {
|
|
2580
|
+
toolbar.appendChild(this.createFormatButton(btn));
|
|
2581
|
+
}
|
|
2582
|
+
toolbar.appendChild(this.createFontSizeSelect());
|
|
2583
|
+
return toolbar;
|
|
2584
|
+
}
|
|
2585
|
+
createFormatButton(config) {
|
|
2586
|
+
const btn = document.createElement("button");
|
|
2587
|
+
btn.dataset["format"] = config.format;
|
|
2588
|
+
btn.textContent = config.label;
|
|
2589
|
+
Object.assign(btn.style, {
|
|
2590
|
+
border: "1px solid transparent",
|
|
2591
|
+
borderRadius: "3px",
|
|
2592
|
+
background: "none",
|
|
2593
|
+
cursor: "pointer",
|
|
2594
|
+
padding: "2px 6px",
|
|
2595
|
+
fontSize: "13px",
|
|
2596
|
+
fontWeight: config.format === "bold" ? "bold" : "normal",
|
|
2597
|
+
fontStyle: config.format === "italic" ? "italic" : "normal",
|
|
2598
|
+
textDecoration: config.format === "underline" ? "underline" : config.format === "strikethrough" ? "line-through" : "none",
|
|
2599
|
+
minWidth: "24px",
|
|
2600
|
+
height: "24px",
|
|
2601
|
+
lineHeight: "24px"
|
|
2602
|
+
});
|
|
2603
|
+
btn.addEventListener("pointerdown", (e) => {
|
|
2604
|
+
e.preventDefault();
|
|
2605
|
+
document.execCommand(config.command);
|
|
2606
|
+
this.updateActiveStates();
|
|
2607
|
+
});
|
|
2608
|
+
return btn;
|
|
2609
|
+
}
|
|
2610
|
+
createFontSizeSelect() {
|
|
2611
|
+
const select = document.createElement("select");
|
|
2612
|
+
Object.assign(select.style, {
|
|
2613
|
+
border: "1px solid #ccc",
|
|
2614
|
+
borderRadius: "3px",
|
|
2615
|
+
background: "#fff",
|
|
2616
|
+
cursor: "pointer",
|
|
2617
|
+
padding: "2px",
|
|
2618
|
+
fontSize: "12px",
|
|
2619
|
+
height: "24px",
|
|
2620
|
+
marginLeft: "4px"
|
|
2621
|
+
});
|
|
2622
|
+
for (const preset of this.fontSizePresets) {
|
|
2623
|
+
const option = document.createElement("option");
|
|
2624
|
+
option.value = String(preset.size);
|
|
2625
|
+
option.textContent = preset.label;
|
|
2626
|
+
select.appendChild(option);
|
|
2627
|
+
}
|
|
2628
|
+
select.value = String(DEFAULT_NOTE_FONT_SIZE);
|
|
2629
|
+
select.addEventListener("pointerdown", (e) => {
|
|
2630
|
+
e.stopPropagation();
|
|
2631
|
+
});
|
|
2632
|
+
select.addEventListener("change", () => {
|
|
2633
|
+
setFontSize(Number(select.value));
|
|
2634
|
+
this.updateActiveStates();
|
|
2635
|
+
this.anchor?.focus();
|
|
2636
|
+
});
|
|
2637
|
+
return select;
|
|
2638
|
+
}
|
|
2639
|
+
positionToolbar(anchor) {
|
|
2640
|
+
if (!this.el) return;
|
|
2641
|
+
const rect = anchor.getBoundingClientRect();
|
|
2642
|
+
const toolbarWidth = this.el.offsetWidth || 200;
|
|
2643
|
+
let top = rect.top - TOOLBAR_HEIGHT - TOOLBAR_GAP;
|
|
2644
|
+
if (top < 0) {
|
|
2645
|
+
top = rect.bottom + TOOLBAR_GAP;
|
|
2646
|
+
}
|
|
2647
|
+
let left = rect.left + (rect.width - toolbarWidth) / 2;
|
|
2648
|
+
left = Math.max(4, left);
|
|
2649
|
+
Object.assign(this.el.style, {
|
|
2650
|
+
top: `${top}px`,
|
|
2651
|
+
left: `${left}px`
|
|
2652
|
+
});
|
|
2653
|
+
}
|
|
2654
|
+
updateActiveStates() {
|
|
2655
|
+
if (!this.el) return;
|
|
2656
|
+
const active = getActiveFormats();
|
|
2657
|
+
for (const config of FORMAT_BUTTONS) {
|
|
2658
|
+
const btn = this.el.querySelector(`[data-format="${config.format}"]`);
|
|
2659
|
+
if (!btn) continue;
|
|
2660
|
+
const isActive = active[config.format] ?? false;
|
|
2661
|
+
btn.style.background = isActive ? "#e0e0e0" : "none";
|
|
2662
|
+
btn.style.borderColor = isActive ? "#bbb" : "transparent";
|
|
2663
|
+
}
|
|
2664
|
+
}
|
|
2665
|
+
};
|
|
2666
|
+
|
|
2193
2667
|
// src/elements/note-editor.ts
|
|
2668
|
+
var FORMAT_SHORTCUTS = {
|
|
2669
|
+
b: toggleBold,
|
|
2670
|
+
i: toggleItalic,
|
|
2671
|
+
u: toggleUnderline
|
|
2672
|
+
};
|
|
2194
2673
|
var NoteEditor = class {
|
|
2195
2674
|
editingId = null;
|
|
2196
2675
|
editingNode = null;
|
|
@@ -2199,6 +2678,10 @@ var NoteEditor = class {
|
|
|
2199
2678
|
pointerHandler = null;
|
|
2200
2679
|
pendingEditId = null;
|
|
2201
2680
|
onStopCallback = null;
|
|
2681
|
+
toolbar;
|
|
2682
|
+
constructor(options) {
|
|
2683
|
+
this.toolbar = options?.toolbar === false ? null : new NoteToolbar(options?.fontSizePresets);
|
|
2684
|
+
}
|
|
2202
2685
|
get isEditing() {
|
|
2203
2686
|
return this.editingId !== null;
|
|
2204
2687
|
}
|
|
@@ -2223,13 +2706,6 @@ var NoteEditor = class {
|
|
|
2223
2706
|
stopEditing(store) {
|
|
2224
2707
|
this.pendingEditId = null;
|
|
2225
2708
|
if (!this.editingId || !this.editingNode) return;
|
|
2226
|
-
const text = this.editingNode.textContent ?? "";
|
|
2227
|
-
store.update(this.editingId, { text });
|
|
2228
|
-
this.editingNode.contentEditable = "false";
|
|
2229
|
-
Object.assign(this.editingNode.style, {
|
|
2230
|
-
userSelect: "none",
|
|
2231
|
-
cursor: "default"
|
|
2232
|
-
});
|
|
2233
2709
|
if (this.blurHandler) {
|
|
2234
2710
|
this.editingNode.removeEventListener("blur", this.blurHandler);
|
|
2235
2711
|
}
|
|
@@ -2239,6 +2715,14 @@ var NoteEditor = class {
|
|
|
2239
2715
|
if (this.pointerHandler) {
|
|
2240
2716
|
this.editingNode.removeEventListener("pointerdown", this.pointerHandler);
|
|
2241
2717
|
}
|
|
2718
|
+
const text = sanitizeNoteHtml(this.editingNode.innerHTML);
|
|
2719
|
+
store.update(this.editingId, { text });
|
|
2720
|
+
this.editingNode.contentEditable = "false";
|
|
2721
|
+
Object.assign(this.editingNode.style, {
|
|
2722
|
+
userSelect: "none",
|
|
2723
|
+
cursor: "default"
|
|
2724
|
+
});
|
|
2725
|
+
this.toolbar?.hide();
|
|
2242
2726
|
if (this.editingId && this.onStopCallback) {
|
|
2243
2727
|
this.onStopCallback(this.editingId);
|
|
2244
2728
|
}
|
|
@@ -2254,6 +2738,11 @@ var NoteEditor = class {
|
|
|
2254
2738
|
this.stopEditing(store);
|
|
2255
2739
|
}
|
|
2256
2740
|
}
|
|
2741
|
+
updateToolbarPosition() {
|
|
2742
|
+
if (this.editingNode) {
|
|
2743
|
+
this.toolbar?.updatePosition(this.editingNode);
|
|
2744
|
+
}
|
|
2745
|
+
}
|
|
2257
2746
|
activateEditing(node, elementId, store) {
|
|
2258
2747
|
this.editingId = elementId;
|
|
2259
2748
|
this.editingNode = node;
|
|
@@ -2272,8 +2761,21 @@ var NoteEditor = class {
|
|
|
2272
2761
|
selection.removeAllRanges();
|
|
2273
2762
|
selection.addRange(range);
|
|
2274
2763
|
}
|
|
2275
|
-
this.
|
|
2764
|
+
this.toolbar?.show(node);
|
|
2765
|
+
this.blurHandler = (e) => {
|
|
2766
|
+
const related = e.relatedTarget;
|
|
2767
|
+
if (related && this.toolbar?.getElement()?.contains(related)) return;
|
|
2768
|
+
this.stopEditing(store);
|
|
2769
|
+
};
|
|
2276
2770
|
this.keyHandler = (e) => {
|
|
2771
|
+
if ((e.ctrlKey || e.metaKey) && !e.shiftKey && !e.altKey) {
|
|
2772
|
+
const action = FORMAT_SHORTCUTS[e.key.toLowerCase()];
|
|
2773
|
+
if (action) {
|
|
2774
|
+
e.preventDefault();
|
|
2775
|
+
action();
|
|
2776
|
+
return;
|
|
2777
|
+
}
|
|
2778
|
+
}
|
|
2277
2779
|
if (e.key === "Escape") {
|
|
2278
2780
|
node.blur();
|
|
2279
2781
|
}
|
|
@@ -2525,150 +3027,86 @@ var HistoryRecorder = class {
|
|
|
2525
3027
|
}
|
|
2526
3028
|
};
|
|
2527
3029
|
|
|
2528
|
-
// src/
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
locked: input.locked ?? false,
|
|
2556
|
-
layerId: input.layerId ?? "",
|
|
2557
|
-
size: input.size ?? { w: 200, h: 100 },
|
|
2558
|
-
text: input.text ?? "",
|
|
2559
|
-
backgroundColor: input.backgroundColor ?? "#ffeb3b",
|
|
2560
|
-
textColor: input.textColor ?? "#000000"
|
|
2561
|
-
};
|
|
2562
|
-
}
|
|
2563
|
-
function createArrow(input) {
|
|
2564
|
-
const bend = input.bend ?? 0;
|
|
2565
|
-
const result = {
|
|
2566
|
-
id: createId("arrow"),
|
|
2567
|
-
type: "arrow",
|
|
2568
|
-
position: input.position ?? { x: 0, y: 0 },
|
|
2569
|
-
zIndex: input.zIndex ?? 0,
|
|
2570
|
-
locked: input.locked ?? false,
|
|
2571
|
-
layerId: input.layerId ?? "",
|
|
2572
|
-
from: input.from,
|
|
2573
|
-
to: input.to,
|
|
2574
|
-
bend,
|
|
2575
|
-
color: input.color ?? "#000000",
|
|
2576
|
-
width: input.width ?? 2,
|
|
2577
|
-
cachedControlPoint: getArrowControlPoint(input.from, input.to, bend)
|
|
2578
|
-
};
|
|
2579
|
-
if (input.fromBinding) result.fromBinding = input.fromBinding;
|
|
2580
|
-
if (input.toBinding) result.toBinding = input.toBinding;
|
|
2581
|
-
return result;
|
|
2582
|
-
}
|
|
2583
|
-
function createImage(input) {
|
|
2584
|
-
return {
|
|
2585
|
-
id: createId("image"),
|
|
2586
|
-
type: "image",
|
|
2587
|
-
position: input.position,
|
|
2588
|
-
zIndex: input.zIndex ?? 0,
|
|
2589
|
-
locked: input.locked ?? false,
|
|
2590
|
-
layerId: input.layerId ?? "",
|
|
2591
|
-
size: input.size,
|
|
2592
|
-
src: input.src
|
|
2593
|
-
};
|
|
2594
|
-
}
|
|
2595
|
-
function createHtmlElement(input) {
|
|
2596
|
-
const el = {
|
|
2597
|
-
id: createId("html"),
|
|
2598
|
-
type: "html",
|
|
2599
|
-
position: input.position,
|
|
2600
|
-
zIndex: input.zIndex ?? 0,
|
|
2601
|
-
locked: input.locked ?? false,
|
|
2602
|
-
layerId: input.layerId ?? "",
|
|
2603
|
-
size: input.size
|
|
2604
|
-
};
|
|
2605
|
-
if (input.domId) el.domId = input.domId;
|
|
2606
|
-
return el;
|
|
2607
|
-
}
|
|
2608
|
-
function createShape(input) {
|
|
2609
|
-
return {
|
|
2610
|
-
id: createId("shape"),
|
|
2611
|
-
type: "shape",
|
|
2612
|
-
position: input.position,
|
|
2613
|
-
zIndex: input.zIndex ?? 0,
|
|
2614
|
-
locked: input.locked ?? false,
|
|
2615
|
-
layerId: input.layerId ?? "",
|
|
2616
|
-
shape: input.shape ?? "rectangle",
|
|
2617
|
-
size: input.size,
|
|
2618
|
-
strokeColor: input.strokeColor ?? "#000000",
|
|
2619
|
-
strokeWidth: input.strokeWidth ?? 2,
|
|
2620
|
-
fillColor: input.fillColor ?? "none"
|
|
2621
|
-
};
|
|
2622
|
-
}
|
|
2623
|
-
function createGrid(input) {
|
|
2624
|
-
return {
|
|
2625
|
-
id: createId("grid"),
|
|
2626
|
-
type: "grid",
|
|
2627
|
-
position: input.position ?? { x: 0, y: 0 },
|
|
2628
|
-
zIndex: input.zIndex ?? 0,
|
|
2629
|
-
locked: input.locked ?? false,
|
|
2630
|
-
layerId: input.layerId ?? "",
|
|
2631
|
-
gridType: input.gridType ?? "square",
|
|
2632
|
-
hexOrientation: input.hexOrientation ?? "pointy",
|
|
2633
|
-
cellSize: input.cellSize ?? 40,
|
|
2634
|
-
strokeColor: input.strokeColor ?? "#000000",
|
|
2635
|
-
strokeWidth: input.strokeWidth ?? 1,
|
|
2636
|
-
opacity: input.opacity ?? 1
|
|
2637
|
-
};
|
|
3030
|
+
// src/canvas/note-canvas-renderer.ts
|
|
3031
|
+
function renderNoteOnCanvas(ctx, note) {
|
|
3032
|
+
const { x, y } = note.position;
|
|
3033
|
+
const { w, h } = note.size;
|
|
3034
|
+
const r = 4;
|
|
3035
|
+
const pad = 8;
|
|
3036
|
+
const baseFontSize = note.fontSize ?? DEFAULT_NOTE_FONT_SIZE;
|
|
3037
|
+
ctx.save();
|
|
3038
|
+
ctx.fillStyle = note.backgroundColor;
|
|
3039
|
+
ctx.beginPath();
|
|
3040
|
+
ctx.moveTo(x + r, y);
|
|
3041
|
+
ctx.lineTo(x + w - r, y);
|
|
3042
|
+
ctx.arcTo(x + w, y, x + w, y + r, r);
|
|
3043
|
+
ctx.lineTo(x + w, y + h - r);
|
|
3044
|
+
ctx.arcTo(x + w, y + h, x + w - r, y + h, r);
|
|
3045
|
+
ctx.lineTo(x + r, y + h);
|
|
3046
|
+
ctx.arcTo(x, y + h, x, y + h - r, r);
|
|
3047
|
+
ctx.lineTo(x, y + r);
|
|
3048
|
+
ctx.arcTo(x, y, x + r, y, r);
|
|
3049
|
+
ctx.closePath();
|
|
3050
|
+
ctx.fill();
|
|
3051
|
+
if (note.text) {
|
|
3052
|
+
ctx.fillStyle = note.textColor;
|
|
3053
|
+
const runs = parseStyledRuns(note.text, baseFontSize);
|
|
3054
|
+
renderStyledRuns(ctx, runs, x + pad, y + pad, w - pad * 2);
|
|
3055
|
+
}
|
|
3056
|
+
ctx.restore();
|
|
2638
3057
|
}
|
|
2639
|
-
function
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
position: input.position,
|
|
2644
|
-
zIndex: input.zIndex ?? 0,
|
|
2645
|
-
locked: input.locked ?? false,
|
|
2646
|
-
layerId: input.layerId ?? "",
|
|
2647
|
-
size: input.size ?? { w: 200, h: 28 },
|
|
2648
|
-
text: input.text ?? "",
|
|
2649
|
-
fontSize: input.fontSize ?? 16,
|
|
2650
|
-
color: input.color ?? "#1a1a1a",
|
|
2651
|
-
textAlign: input.textAlign ?? "left"
|
|
2652
|
-
};
|
|
3058
|
+
function buildFontString(run) {
|
|
3059
|
+
const style = run.italic ? "italic" : "normal";
|
|
3060
|
+
const weight = run.bold ? "bold" : "normal";
|
|
3061
|
+
return `${style} ${weight} ${run.fontSize}px system-ui, sans-serif`;
|
|
2653
3062
|
}
|
|
2654
|
-
function
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
3063
|
+
function renderStyledRuns(ctx, runs, startX, startY, maxWidth) {
|
|
3064
|
+
ctx.textBaseline = "top";
|
|
3065
|
+
let cursorX = startX;
|
|
3066
|
+
let cursorY = startY;
|
|
3067
|
+
let lineHeight = 0;
|
|
3068
|
+
for (const run of runs) {
|
|
3069
|
+
ctx.font = buildFontString(run);
|
|
3070
|
+
const runLineHeight = run.fontSize * 1.3;
|
|
3071
|
+
lineHeight = Math.max(lineHeight, runLineHeight);
|
|
3072
|
+
const words = run.text.split(/(\n| )/);
|
|
3073
|
+
for (const word of words) {
|
|
3074
|
+
if (word === "\n") {
|
|
3075
|
+
cursorX = startX;
|
|
3076
|
+
cursorY += lineHeight;
|
|
3077
|
+
lineHeight = runLineHeight;
|
|
3078
|
+
continue;
|
|
3079
|
+
}
|
|
3080
|
+
if (word === " ") {
|
|
3081
|
+
const spaceWidth = ctx.measureText(" ").width;
|
|
3082
|
+
if (cursorX + spaceWidth > startX + maxWidth && cursorX > startX) {
|
|
3083
|
+
cursorX = startX;
|
|
3084
|
+
cursorY += lineHeight;
|
|
3085
|
+
lineHeight = runLineHeight;
|
|
3086
|
+
} else {
|
|
3087
|
+
cursorX += spaceWidth;
|
|
3088
|
+
}
|
|
3089
|
+
continue;
|
|
3090
|
+
}
|
|
3091
|
+
if (!word) continue;
|
|
3092
|
+
const metrics = ctx.measureText(word);
|
|
3093
|
+
if (cursorX + metrics.width > startX + maxWidth && cursorX > startX) {
|
|
3094
|
+
cursorX = startX;
|
|
3095
|
+
cursorY += lineHeight;
|
|
3096
|
+
lineHeight = runLineHeight;
|
|
3097
|
+
}
|
|
3098
|
+
ctx.fillText(word, cursorX, cursorY);
|
|
3099
|
+
if (run.underline) {
|
|
3100
|
+
const underY = cursorY + run.fontSize + 1;
|
|
3101
|
+
ctx.fillRect(cursorX, underY, metrics.width, 1);
|
|
3102
|
+
}
|
|
3103
|
+
if (run.strikethrough) {
|
|
3104
|
+
const strikeY = cursorY + run.fontSize * 0.55;
|
|
3105
|
+
ctx.fillRect(cursorX, strikeY, metrics.width, 1);
|
|
3106
|
+
}
|
|
3107
|
+
cursorX += metrics.width;
|
|
3108
|
+
}
|
|
3109
|
+
}
|
|
2672
3110
|
}
|
|
2673
3111
|
|
|
2674
3112
|
// src/canvas/export-image.ts
|
|
@@ -2747,33 +3185,6 @@ function computeBounds(elements, padding) {
|
|
|
2747
3185
|
h: maxY - minY + padding * 2
|
|
2748
3186
|
};
|
|
2749
3187
|
}
|
|
2750
|
-
function renderNoteOnCanvas(ctx, note) {
|
|
2751
|
-
const { x, y } = note.position;
|
|
2752
|
-
const { w, h } = note.size;
|
|
2753
|
-
const r = 4;
|
|
2754
|
-
const pad = 8;
|
|
2755
|
-
ctx.save();
|
|
2756
|
-
ctx.fillStyle = note.backgroundColor;
|
|
2757
|
-
ctx.beginPath();
|
|
2758
|
-
ctx.moveTo(x + r, y);
|
|
2759
|
-
ctx.lineTo(x + w - r, y);
|
|
2760
|
-
ctx.arcTo(x + w, y, x + w, y + r, r);
|
|
2761
|
-
ctx.lineTo(x + w, y + h - r);
|
|
2762
|
-
ctx.arcTo(x + w, y + h, x + w - r, y + h, r);
|
|
2763
|
-
ctx.lineTo(x + r, y + h);
|
|
2764
|
-
ctx.arcTo(x, y + h, x, y + h - r, r);
|
|
2765
|
-
ctx.lineTo(x, y + r);
|
|
2766
|
-
ctx.arcTo(x, y, x + r, y, r);
|
|
2767
|
-
ctx.closePath();
|
|
2768
|
-
ctx.fill();
|
|
2769
|
-
if (note.text) {
|
|
2770
|
-
ctx.fillStyle = note.textColor;
|
|
2771
|
-
ctx.font = "14px system-ui, sans-serif";
|
|
2772
|
-
ctx.textBaseline = "top";
|
|
2773
|
-
wrapText(ctx, note.text, x + pad, y + pad, w - pad * 2, 18);
|
|
2774
|
-
}
|
|
2775
|
-
ctx.restore();
|
|
2776
|
-
}
|
|
2777
3188
|
function renderTextOnCanvas(ctx, text) {
|
|
2778
3189
|
if (!text.text) return;
|
|
2779
3190
|
ctx.save();
|
|
@@ -2798,25 +3209,6 @@ function renderTextOnCanvas(ctx, text) {
|
|
|
2798
3209
|
}
|
|
2799
3210
|
ctx.restore();
|
|
2800
3211
|
}
|
|
2801
|
-
function wrapText(ctx, text, x, y, maxWidth, lineHeight) {
|
|
2802
|
-
const words = text.split(" ");
|
|
2803
|
-
let line = "";
|
|
2804
|
-
let offsetY = 0;
|
|
2805
|
-
for (const word of words) {
|
|
2806
|
-
const testLine = line ? `${line} ${word}` : word;
|
|
2807
|
-
const metrics = ctx.measureText(testLine);
|
|
2808
|
-
if (metrics.width > maxWidth && line) {
|
|
2809
|
-
ctx.fillText(line, x, y + offsetY);
|
|
2810
|
-
line = word;
|
|
2811
|
-
offsetY += lineHeight;
|
|
2812
|
-
} else {
|
|
2813
|
-
line = testLine;
|
|
2814
|
-
}
|
|
2815
|
-
}
|
|
2816
|
-
if (line) {
|
|
2817
|
-
ctx.fillText(line, x, y + offsetY);
|
|
2818
|
-
}
|
|
2819
|
-
}
|
|
2820
3212
|
function renderGridForBounds(ctx, grid, bounds) {
|
|
2821
3213
|
const visibleBounds = {
|
|
2822
3214
|
minX: bounds.x,
|
|
@@ -3215,13 +3607,13 @@ var DomNodeManager = class {
|
|
|
3215
3607
|
padding: "8px",
|
|
3216
3608
|
borderRadius: "4px",
|
|
3217
3609
|
boxShadow: "0 2px 8px rgba(0,0,0,0.15)",
|
|
3218
|
-
fontSize:
|
|
3610
|
+
fontSize: `${element.fontSize ?? DEFAULT_NOTE_FONT_SIZE}px`,
|
|
3219
3611
|
overflow: "hidden",
|
|
3220
3612
|
cursor: "default",
|
|
3221
3613
|
userSelect: "none",
|
|
3222
3614
|
wordWrap: "break-word"
|
|
3223
3615
|
});
|
|
3224
|
-
node.
|
|
3616
|
+
node.innerHTML = element.text || "";
|
|
3225
3617
|
node.addEventListener("dblclick", (e) => {
|
|
3226
3618
|
e.stopPropagation();
|
|
3227
3619
|
const id = node.dataset["elementId"];
|
|
@@ -3229,11 +3621,13 @@ var DomNodeManager = class {
|
|
|
3229
3621
|
});
|
|
3230
3622
|
}
|
|
3231
3623
|
if (!this.isEditingElement(element.id)) {
|
|
3232
|
-
|
|
3233
|
-
|
|
3624
|
+
const text = element.text || "";
|
|
3625
|
+
if (node.innerHTML !== text) {
|
|
3626
|
+
node.innerHTML = text;
|
|
3234
3627
|
}
|
|
3235
3628
|
node.style.backgroundColor = element.backgroundColor;
|
|
3236
3629
|
node.style.color = element.textColor;
|
|
3630
|
+
node.style.fontSize = `${element.fontSize ?? DEFAULT_NOTE_FONT_SIZE}px`;
|
|
3237
3631
|
}
|
|
3238
3632
|
}
|
|
3239
3633
|
if (element.type === "html" && !node.dataset["initialized"]) {
|
|
@@ -3664,7 +4058,10 @@ var Viewport = class {
|
|
|
3664
4058
|
this.renderLoop.markAllLayersDirty();
|
|
3665
4059
|
this.requestRender();
|
|
3666
4060
|
});
|
|
3667
|
-
this.noteEditor = new NoteEditor(
|
|
4061
|
+
this.noteEditor = new NoteEditor({
|
|
4062
|
+
fontSizePresets: options.fontSizePresets,
|
|
4063
|
+
toolbar: options.toolbar
|
|
4064
|
+
});
|
|
3668
4065
|
this.noteEditor.setOnStop((id) => this.onTextEditStop(id));
|
|
3669
4066
|
this.history = new HistoryStack();
|
|
3670
4067
|
this.historyRecorder = new HistoryRecorder(this.store, this.history);
|
|
@@ -3720,6 +4117,7 @@ var Viewport = class {
|
|
|
3720
4117
|
});
|
|
3721
4118
|
this.unsubCamera = this.camera.onChange(() => {
|
|
3722
4119
|
this.applyCameraTransform();
|
|
4120
|
+
this.noteEditor.updateToolbarPosition();
|
|
3723
4121
|
this.requestRender();
|
|
3724
4122
|
});
|
|
3725
4123
|
this.unsubStore = [
|
|
@@ -5069,17 +5467,20 @@ var NoteTool = class {
|
|
|
5069
5467
|
backgroundColor;
|
|
5070
5468
|
textColor;
|
|
5071
5469
|
size;
|
|
5470
|
+
fontSize;
|
|
5072
5471
|
optionListeners = /* @__PURE__ */ new Set();
|
|
5073
5472
|
constructor(options = {}) {
|
|
5074
5473
|
this.backgroundColor = options.backgroundColor ?? "#ffeb3b";
|
|
5075
5474
|
this.textColor = options.textColor ?? "#000000";
|
|
5076
5475
|
this.size = options.size ?? { w: 200, h: 100 };
|
|
5476
|
+
this.fontSize = options.fontSize ?? DEFAULT_NOTE_FONT_SIZE;
|
|
5077
5477
|
}
|
|
5078
5478
|
getOptions() {
|
|
5079
5479
|
return {
|
|
5080
5480
|
backgroundColor: this.backgroundColor,
|
|
5081
5481
|
textColor: this.textColor,
|
|
5082
|
-
size: { ...this.size }
|
|
5482
|
+
size: { ...this.size },
|
|
5483
|
+
fontSize: this.fontSize
|
|
5083
5484
|
};
|
|
5084
5485
|
}
|
|
5085
5486
|
onOptionsChange(listener) {
|
|
@@ -5090,6 +5491,7 @@ var NoteTool = class {
|
|
|
5090
5491
|
if (options.backgroundColor !== void 0) this.backgroundColor = options.backgroundColor;
|
|
5091
5492
|
if (options.textColor !== void 0) this.textColor = options.textColor;
|
|
5092
5493
|
if (options.size !== void 0) this.size = options.size;
|
|
5494
|
+
if (options.fontSize !== void 0) this.fontSize = options.fontSize;
|
|
5093
5495
|
this.notifyOptionsChange();
|
|
5094
5496
|
}
|
|
5095
5497
|
notifyOptionsChange() {
|
|
@@ -5107,6 +5509,7 @@ var NoteTool = class {
|
|
|
5107
5509
|
size: { ...this.size },
|
|
5108
5510
|
backgroundColor: this.backgroundColor,
|
|
5109
5511
|
textColor: this.textColor,
|
|
5512
|
+
fontSize: this.fontSize,
|
|
5110
5513
|
layerId: ctx.activeLayerId ?? ""
|
|
5111
5514
|
});
|
|
5112
5515
|
ctx.store.add(note);
|
|
@@ -5774,7 +6177,7 @@ var UpdateLayerCommand = class {
|
|
|
5774
6177
|
};
|
|
5775
6178
|
|
|
5776
6179
|
// src/index.ts
|
|
5777
|
-
var VERSION = "0.
|
|
6180
|
+
var VERSION = "0.10.0";
|
|
5778
6181
|
export {
|
|
5779
6182
|
AddElementCommand,
|
|
5780
6183
|
ArrowTool,
|
|
@@ -5783,6 +6186,8 @@ export {
|
|
|
5783
6186
|
BatchCommand,
|
|
5784
6187
|
Camera,
|
|
5785
6188
|
CreateLayerCommand,
|
|
6189
|
+
DEFAULT_FONT_SIZE_PRESETS,
|
|
6190
|
+
DEFAULT_NOTE_FONT_SIZE,
|
|
5786
6191
|
ElementRenderer,
|
|
5787
6192
|
ElementStore,
|
|
5788
6193
|
EraserTool,
|
|
@@ -5796,6 +6201,7 @@ export {
|
|
|
5796
6201
|
MeasureTool,
|
|
5797
6202
|
NoteEditor,
|
|
5798
6203
|
NoteTool,
|
|
6204
|
+
NoteToolbar,
|
|
5799
6205
|
PencilTool,
|
|
5800
6206
|
Quadtree,
|
|
5801
6207
|
RemoveElementCommand,
|
|
@@ -5826,6 +6232,7 @@ export {
|
|
|
5826
6232
|
exportState,
|
|
5827
6233
|
findBindTarget,
|
|
5828
6234
|
findBoundArrows,
|
|
6235
|
+
getActiveFormats,
|
|
5829
6236
|
getArrowBounds,
|
|
5830
6237
|
getArrowControlPoint,
|
|
5831
6238
|
getArrowMidpoint,
|
|
@@ -5842,9 +6249,15 @@ export {
|
|
|
5842
6249
|
isBindable,
|
|
5843
6250
|
isNearBezier,
|
|
5844
6251
|
parseState,
|
|
6252
|
+
sanitizeNoteHtml,
|
|
6253
|
+
setFontSize,
|
|
5845
6254
|
smartSnap,
|
|
5846
6255
|
snapPoint,
|
|
5847
6256
|
snapToHexCenter,
|
|
6257
|
+
toggleBold,
|
|
6258
|
+
toggleItalic,
|
|
6259
|
+
toggleStrikethrough,
|
|
6260
|
+
toggleUnderline,
|
|
5848
6261
|
unbindArrow,
|
|
5849
6262
|
updateBoundArrow
|
|
5850
6263
|
};
|