@markup-canvas/core 1.3.3 → 1.3.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/lib/MarkupCanvas.d.ts +4 -0
- package/dist/lib/events/keyboard/setupKeyboardEvents.d.ts +3 -1
- package/dist/markup-canvas.cjs.js +81 -8
- package/dist/markup-canvas.esm.js +81 -8
- package/dist/markup-canvas.umd.js +79 -6
- package/dist/markup-canvas.umd.min.js +1 -1
- package/dist/types/window.d.ts +4 -1
- package/package.json +1 -1
- package/src/lib/MarkupCanvas.ts +62 -2
- package/src/lib/config/presets/editor-preset.ts +2 -2
- package/src/lib/events/keyboard/setupKeyboardEvents.ts +25 -1
- package/src/lib/rulers/createHorizontalRuler.ts +0 -1
- package/src/lib/rulers/createVerticalRuler.ts +0 -1
- package/src/lib/window/bindCanvasToWindow.ts +3 -0
- package/src/types/window.ts +4 -1
|
@@ -11,6 +11,7 @@ export declare class MarkupCanvas {
|
|
|
11
11
|
private rulers;
|
|
12
12
|
private dragSetup;
|
|
13
13
|
private keyboardCleanup;
|
|
14
|
+
private textEditModeEnabled;
|
|
14
15
|
config: Required<MarkupCanvasConfig>;
|
|
15
16
|
event: EventEmitter<MarkupCanvasEvents>;
|
|
16
17
|
private _isReady;
|
|
@@ -52,6 +53,9 @@ export declare class MarkupCanvas {
|
|
|
52
53
|
enableKeyboard(): boolean;
|
|
53
54
|
disableKeyboard(): boolean;
|
|
54
55
|
isKeyboardEnabled(): boolean;
|
|
56
|
+
enableTextEditMode(): boolean;
|
|
57
|
+
disableTextEditMode(): boolean;
|
|
58
|
+
isTextEditModeEnabled(): boolean;
|
|
55
59
|
toggleGrid(): boolean;
|
|
56
60
|
showGrid(): boolean;
|
|
57
61
|
hideGrid(): boolean;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
import type { MarkupCanvas } from "@/lib/MarkupCanvas.js";
|
|
2
2
|
import type { MarkupCanvasConfig } from "@/types/index.js";
|
|
3
|
-
export declare function setupKeyboardEvents(canvas: MarkupCanvas, config: Required<MarkupCanvasConfig
|
|
3
|
+
export declare function setupKeyboardEvents(canvas: MarkupCanvas, config: Required<MarkupCanvasConfig>, options?: {
|
|
4
|
+
textEditModeEnabled?: boolean;
|
|
5
|
+
}): () => void;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Markup Canvas
|
|
3
3
|
* High-performance markup canvas with zoom and pan capabilities
|
|
4
|
-
* @version 1.3.
|
|
4
|
+
* @version 1.3.4
|
|
5
5
|
*/
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
@@ -22,7 +22,7 @@ const EDITOR_PRESET = {
|
|
|
22
22
|
enableKeyboard: true,
|
|
23
23
|
bindKeyboardEventsTo: "document",
|
|
24
24
|
// Zoom behavior
|
|
25
|
-
zoomSpeed:
|
|
25
|
+
zoomSpeed: 4,
|
|
26
26
|
minZoom: 0.05,
|
|
27
27
|
maxZoom: 80,
|
|
28
28
|
enableTransition: false,
|
|
@@ -54,7 +54,7 @@ const EDITOR_PRESET = {
|
|
|
54
54
|
canvasBackgroundColorDark: "transparent",
|
|
55
55
|
// Ruler styling
|
|
56
56
|
rulerBackgroundColor: "oklch(100% 0 0 / 0.96)",
|
|
57
|
-
rulerBorderColor: "oklch(
|
|
57
|
+
rulerBorderColor: "oklch(0.322 0.0095 285.919)",
|
|
58
58
|
rulerTextColor: "oklch(70.5% 0.015 286.067)",
|
|
59
59
|
rulerTickColor: "oklch(92% 0.004 286.32)",
|
|
60
60
|
gridColor: "rgba(232, 86, 193, 0.5)",
|
|
@@ -948,7 +948,8 @@ function getAdaptiveZoomSpeed(canvas, baseSpeed) {
|
|
|
948
948
|
}
|
|
949
949
|
}
|
|
950
950
|
|
|
951
|
-
function setupKeyboardEvents(canvas, config) {
|
|
951
|
+
function setupKeyboardEvents(canvas, config, options) {
|
|
952
|
+
const textEditModeEnabled = options?.textEditModeEnabled ?? false;
|
|
952
953
|
function handleKeyDown(event) {
|
|
953
954
|
if (!(event instanceof KeyboardEvent))
|
|
954
955
|
return;
|
|
@@ -958,23 +959,38 @@ function setupKeyboardEvents(canvas, config) {
|
|
|
958
959
|
const newTransform = {};
|
|
959
960
|
switch (event.key) {
|
|
960
961
|
case "ArrowLeft":
|
|
962
|
+
if (textEditModeEnabled) {
|
|
963
|
+
return;
|
|
964
|
+
}
|
|
961
965
|
newTransform.translateX = canvas.transform.translateX + config.keyboardPanStep;
|
|
962
966
|
handled = true;
|
|
963
967
|
break;
|
|
964
968
|
case "ArrowRight":
|
|
969
|
+
if (textEditModeEnabled) {
|
|
970
|
+
return;
|
|
971
|
+
}
|
|
965
972
|
newTransform.translateX = canvas.transform.translateX - config.keyboardPanStep;
|
|
966
973
|
handled = true;
|
|
967
974
|
break;
|
|
968
975
|
case "ArrowUp":
|
|
976
|
+
if (textEditModeEnabled) {
|
|
977
|
+
return;
|
|
978
|
+
}
|
|
969
979
|
newTransform.translateY = canvas.transform.translateY + config.keyboardPanStep;
|
|
970
980
|
handled = true;
|
|
971
981
|
break;
|
|
972
982
|
case "ArrowDown":
|
|
983
|
+
if (textEditModeEnabled) {
|
|
984
|
+
return;
|
|
985
|
+
}
|
|
973
986
|
newTransform.translateY = canvas.transform.translateY - config.keyboardPanStep;
|
|
974
987
|
handled = true;
|
|
975
988
|
break;
|
|
976
989
|
case "=":
|
|
977
990
|
case "+":
|
|
991
|
+
if (textEditModeEnabled) {
|
|
992
|
+
return;
|
|
993
|
+
}
|
|
978
994
|
{
|
|
979
995
|
const adaptiveZoomStep = config.enableAdaptiveSpeed
|
|
980
996
|
? getAdaptiveZoomSpeed(canvas, config.keyboardZoomStep)
|
|
@@ -984,6 +1000,9 @@ function setupKeyboardEvents(canvas, config) {
|
|
|
984
1000
|
}
|
|
985
1001
|
break;
|
|
986
1002
|
case "-":
|
|
1003
|
+
if (textEditModeEnabled) {
|
|
1004
|
+
return;
|
|
1005
|
+
}
|
|
987
1006
|
{
|
|
988
1007
|
const adaptiveZoomStep = config.enableAdaptiveSpeed
|
|
989
1008
|
? getAdaptiveZoomSpeed(canvas, config.keyboardZoomStep)
|
|
@@ -1749,7 +1768,6 @@ function createHorizontalRuler(config) {
|
|
|
1749
1768
|
height: ${config.rulerSize}px;
|
|
1750
1769
|
background: var(--ruler-background-color);
|
|
1751
1770
|
border-bottom: 1px solid var(--ruler-border-color);
|
|
1752
|
-
border-right: 1px solid var(--ruler-border-color);
|
|
1753
1771
|
z-index: ${RULER_Z_INDEX.RULERS};
|
|
1754
1772
|
pointer-events: none;
|
|
1755
1773
|
font-family: ${config.rulerFontFamily};
|
|
@@ -1771,7 +1789,6 @@ function createVerticalRuler(config) {
|
|
|
1771
1789
|
width: ${config.rulerSize}px;
|
|
1772
1790
|
background: var(--ruler-background-color);
|
|
1773
1791
|
border-right: 1px solid var(--ruler-border-color);
|
|
1774
|
-
border-bottom: 1px solid var(--ruler-border-color);
|
|
1775
1792
|
z-index: ${RULER_Z_INDEX.RULERS};
|
|
1776
1793
|
pointer-events: none;
|
|
1777
1794
|
font-family: ${config.rulerFontFamily};
|
|
@@ -2173,6 +2190,9 @@ function bindCanvasToWindow(canvas, config) {
|
|
|
2173
2190
|
enable: canvas.enableKeyboard.bind(canvas),
|
|
2174
2191
|
disable: canvas.disableKeyboard.bind(canvas),
|
|
2175
2192
|
isEnabled: canvas.isKeyboardEnabled.bind(canvas),
|
|
2193
|
+
enableTextEditMode: canvas.enableTextEditMode.bind(canvas),
|
|
2194
|
+
disableTextEditMode: canvas.disableTextEditMode.bind(canvas),
|
|
2195
|
+
isTextEditModeEnabled: canvas.isTextEditModeEnabled.bind(canvas),
|
|
2176
2196
|
},
|
|
2177
2197
|
// Grid group
|
|
2178
2198
|
grid: {
|
|
@@ -2247,6 +2267,7 @@ class MarkupCanvas {
|
|
|
2247
2267
|
this.rulers = null;
|
|
2248
2268
|
this.dragSetup = null;
|
|
2249
2269
|
this.keyboardCleanup = null;
|
|
2270
|
+
this.textEditModeEnabled = false;
|
|
2250
2271
|
this.event = new EventEmitter();
|
|
2251
2272
|
this._isReady = false;
|
|
2252
2273
|
if (!container) {
|
|
@@ -2298,7 +2319,9 @@ class MarkupCanvas {
|
|
|
2298
2319
|
}
|
|
2299
2320
|
// Keyboard events
|
|
2300
2321
|
withFeatureEnabled(this.config, "enableKeyboard", () => {
|
|
2301
|
-
const keyboardCleanup = setupKeyboardEvents(this, this.config
|
|
2322
|
+
const keyboardCleanup = setupKeyboardEvents(this, this.config, {
|
|
2323
|
+
textEditModeEnabled: this.textEditModeEnabled,
|
|
2324
|
+
});
|
|
2302
2325
|
this.keyboardCleanup = keyboardCleanup;
|
|
2303
2326
|
this.cleanupCallbacks.push(keyboardCleanup);
|
|
2304
2327
|
});
|
|
@@ -2412,7 +2435,9 @@ class MarkupCanvas {
|
|
|
2412
2435
|
if (this.keyboardCleanup) {
|
|
2413
2436
|
return true; // Already enabled
|
|
2414
2437
|
}
|
|
2415
|
-
this.keyboardCleanup = setupKeyboardEvents(this, this.config
|
|
2438
|
+
this.keyboardCleanup = setupKeyboardEvents(this, this.config, {
|
|
2439
|
+
textEditModeEnabled: this.textEditModeEnabled,
|
|
2440
|
+
});
|
|
2416
2441
|
this.cleanupCallbacks.push(this.keyboardCleanup);
|
|
2417
2442
|
return true;
|
|
2418
2443
|
}
|
|
@@ -2427,6 +2452,54 @@ class MarkupCanvas {
|
|
|
2427
2452
|
isKeyboardEnabled() {
|
|
2428
2453
|
return this.keyboardCleanup !== null;
|
|
2429
2454
|
}
|
|
2455
|
+
// Text edit mode control methods
|
|
2456
|
+
enableTextEditMode() {
|
|
2457
|
+
if (this.textEditModeEnabled) {
|
|
2458
|
+
return true; // Already enabled
|
|
2459
|
+
}
|
|
2460
|
+
this.textEditModeEnabled = true;
|
|
2461
|
+
// If keyboard is currently enabled, re-setup with new option
|
|
2462
|
+
if (this.keyboardCleanup) {
|
|
2463
|
+
// Remove old cleanup from callbacks
|
|
2464
|
+
const index = this.cleanupCallbacks.indexOf(this.keyboardCleanup);
|
|
2465
|
+
if (index > -1) {
|
|
2466
|
+
this.cleanupCallbacks.splice(index, 1);
|
|
2467
|
+
}
|
|
2468
|
+
// Cleanup old handler
|
|
2469
|
+
this.keyboardCleanup();
|
|
2470
|
+
// Setup new handler with text edit mode enabled
|
|
2471
|
+
this.keyboardCleanup = setupKeyboardEvents(this, this.config, {
|
|
2472
|
+
textEditModeEnabled: true,
|
|
2473
|
+
});
|
|
2474
|
+
this.cleanupCallbacks.push(this.keyboardCleanup);
|
|
2475
|
+
}
|
|
2476
|
+
return true;
|
|
2477
|
+
}
|
|
2478
|
+
disableTextEditMode() {
|
|
2479
|
+
if (!this.textEditModeEnabled) {
|
|
2480
|
+
return true; // Already disabled
|
|
2481
|
+
}
|
|
2482
|
+
this.textEditModeEnabled = false;
|
|
2483
|
+
// If keyboard is currently enabled, re-setup with new option
|
|
2484
|
+
if (this.keyboardCleanup) {
|
|
2485
|
+
// Remove old cleanup from callbacks
|
|
2486
|
+
const index = this.cleanupCallbacks.indexOf(this.keyboardCleanup);
|
|
2487
|
+
if (index > -1) {
|
|
2488
|
+
this.cleanupCallbacks.splice(index, 1);
|
|
2489
|
+
}
|
|
2490
|
+
// Cleanup old handler
|
|
2491
|
+
this.keyboardCleanup();
|
|
2492
|
+
// Setup new handler with text edit mode disabled
|
|
2493
|
+
this.keyboardCleanup = setupKeyboardEvents(this, this.config, {
|
|
2494
|
+
textEditModeEnabled: false,
|
|
2495
|
+
});
|
|
2496
|
+
this.cleanupCallbacks.push(this.keyboardCleanup);
|
|
2497
|
+
}
|
|
2498
|
+
return true;
|
|
2499
|
+
}
|
|
2500
|
+
isTextEditModeEnabled() {
|
|
2501
|
+
return this.textEditModeEnabled;
|
|
2502
|
+
}
|
|
2430
2503
|
toggleGrid() {
|
|
2431
2504
|
const result = toggleGrid(this.rulers);
|
|
2432
2505
|
if (result) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Markup Canvas
|
|
3
3
|
* High-performance markup canvas with zoom and pan capabilities
|
|
4
|
-
* @version 1.3.
|
|
4
|
+
* @version 1.3.4
|
|
5
5
|
*/
|
|
6
6
|
const EDITOR_PRESET = {
|
|
7
7
|
// Canvas dimensions
|
|
@@ -18,7 +18,7 @@ const EDITOR_PRESET = {
|
|
|
18
18
|
enableKeyboard: true,
|
|
19
19
|
bindKeyboardEventsTo: "document",
|
|
20
20
|
// Zoom behavior
|
|
21
|
-
zoomSpeed:
|
|
21
|
+
zoomSpeed: 4,
|
|
22
22
|
minZoom: 0.05,
|
|
23
23
|
maxZoom: 80,
|
|
24
24
|
enableTransition: false,
|
|
@@ -50,7 +50,7 @@ const EDITOR_PRESET = {
|
|
|
50
50
|
canvasBackgroundColorDark: "transparent",
|
|
51
51
|
// Ruler styling
|
|
52
52
|
rulerBackgroundColor: "oklch(100% 0 0 / 0.96)",
|
|
53
|
-
rulerBorderColor: "oklch(
|
|
53
|
+
rulerBorderColor: "oklch(0.322 0.0095 285.919)",
|
|
54
54
|
rulerTextColor: "oklch(70.5% 0.015 286.067)",
|
|
55
55
|
rulerTickColor: "oklch(92% 0.004 286.32)",
|
|
56
56
|
gridColor: "rgba(232, 86, 193, 0.5)",
|
|
@@ -944,7 +944,8 @@ function getAdaptiveZoomSpeed(canvas, baseSpeed) {
|
|
|
944
944
|
}
|
|
945
945
|
}
|
|
946
946
|
|
|
947
|
-
function setupKeyboardEvents(canvas, config) {
|
|
947
|
+
function setupKeyboardEvents(canvas, config, options) {
|
|
948
|
+
const textEditModeEnabled = options?.textEditModeEnabled ?? false;
|
|
948
949
|
function handleKeyDown(event) {
|
|
949
950
|
if (!(event instanceof KeyboardEvent))
|
|
950
951
|
return;
|
|
@@ -954,23 +955,38 @@ function setupKeyboardEvents(canvas, config) {
|
|
|
954
955
|
const newTransform = {};
|
|
955
956
|
switch (event.key) {
|
|
956
957
|
case "ArrowLeft":
|
|
958
|
+
if (textEditModeEnabled) {
|
|
959
|
+
return;
|
|
960
|
+
}
|
|
957
961
|
newTransform.translateX = canvas.transform.translateX + config.keyboardPanStep;
|
|
958
962
|
handled = true;
|
|
959
963
|
break;
|
|
960
964
|
case "ArrowRight":
|
|
965
|
+
if (textEditModeEnabled) {
|
|
966
|
+
return;
|
|
967
|
+
}
|
|
961
968
|
newTransform.translateX = canvas.transform.translateX - config.keyboardPanStep;
|
|
962
969
|
handled = true;
|
|
963
970
|
break;
|
|
964
971
|
case "ArrowUp":
|
|
972
|
+
if (textEditModeEnabled) {
|
|
973
|
+
return;
|
|
974
|
+
}
|
|
965
975
|
newTransform.translateY = canvas.transform.translateY + config.keyboardPanStep;
|
|
966
976
|
handled = true;
|
|
967
977
|
break;
|
|
968
978
|
case "ArrowDown":
|
|
979
|
+
if (textEditModeEnabled) {
|
|
980
|
+
return;
|
|
981
|
+
}
|
|
969
982
|
newTransform.translateY = canvas.transform.translateY - config.keyboardPanStep;
|
|
970
983
|
handled = true;
|
|
971
984
|
break;
|
|
972
985
|
case "=":
|
|
973
986
|
case "+":
|
|
987
|
+
if (textEditModeEnabled) {
|
|
988
|
+
return;
|
|
989
|
+
}
|
|
974
990
|
{
|
|
975
991
|
const adaptiveZoomStep = config.enableAdaptiveSpeed
|
|
976
992
|
? getAdaptiveZoomSpeed(canvas, config.keyboardZoomStep)
|
|
@@ -980,6 +996,9 @@ function setupKeyboardEvents(canvas, config) {
|
|
|
980
996
|
}
|
|
981
997
|
break;
|
|
982
998
|
case "-":
|
|
999
|
+
if (textEditModeEnabled) {
|
|
1000
|
+
return;
|
|
1001
|
+
}
|
|
983
1002
|
{
|
|
984
1003
|
const adaptiveZoomStep = config.enableAdaptiveSpeed
|
|
985
1004
|
? getAdaptiveZoomSpeed(canvas, config.keyboardZoomStep)
|
|
@@ -1745,7 +1764,6 @@ function createHorizontalRuler(config) {
|
|
|
1745
1764
|
height: ${config.rulerSize}px;
|
|
1746
1765
|
background: var(--ruler-background-color);
|
|
1747
1766
|
border-bottom: 1px solid var(--ruler-border-color);
|
|
1748
|
-
border-right: 1px solid var(--ruler-border-color);
|
|
1749
1767
|
z-index: ${RULER_Z_INDEX.RULERS};
|
|
1750
1768
|
pointer-events: none;
|
|
1751
1769
|
font-family: ${config.rulerFontFamily};
|
|
@@ -1767,7 +1785,6 @@ function createVerticalRuler(config) {
|
|
|
1767
1785
|
width: ${config.rulerSize}px;
|
|
1768
1786
|
background: var(--ruler-background-color);
|
|
1769
1787
|
border-right: 1px solid var(--ruler-border-color);
|
|
1770
|
-
border-bottom: 1px solid var(--ruler-border-color);
|
|
1771
1788
|
z-index: ${RULER_Z_INDEX.RULERS};
|
|
1772
1789
|
pointer-events: none;
|
|
1773
1790
|
font-family: ${config.rulerFontFamily};
|
|
@@ -2169,6 +2186,9 @@ function bindCanvasToWindow(canvas, config) {
|
|
|
2169
2186
|
enable: canvas.enableKeyboard.bind(canvas),
|
|
2170
2187
|
disable: canvas.disableKeyboard.bind(canvas),
|
|
2171
2188
|
isEnabled: canvas.isKeyboardEnabled.bind(canvas),
|
|
2189
|
+
enableTextEditMode: canvas.enableTextEditMode.bind(canvas),
|
|
2190
|
+
disableTextEditMode: canvas.disableTextEditMode.bind(canvas),
|
|
2191
|
+
isTextEditModeEnabled: canvas.isTextEditModeEnabled.bind(canvas),
|
|
2172
2192
|
},
|
|
2173
2193
|
// Grid group
|
|
2174
2194
|
grid: {
|
|
@@ -2243,6 +2263,7 @@ class MarkupCanvas {
|
|
|
2243
2263
|
this.rulers = null;
|
|
2244
2264
|
this.dragSetup = null;
|
|
2245
2265
|
this.keyboardCleanup = null;
|
|
2266
|
+
this.textEditModeEnabled = false;
|
|
2246
2267
|
this.event = new EventEmitter();
|
|
2247
2268
|
this._isReady = false;
|
|
2248
2269
|
if (!container) {
|
|
@@ -2294,7 +2315,9 @@ class MarkupCanvas {
|
|
|
2294
2315
|
}
|
|
2295
2316
|
// Keyboard events
|
|
2296
2317
|
withFeatureEnabled(this.config, "enableKeyboard", () => {
|
|
2297
|
-
const keyboardCleanup = setupKeyboardEvents(this, this.config
|
|
2318
|
+
const keyboardCleanup = setupKeyboardEvents(this, this.config, {
|
|
2319
|
+
textEditModeEnabled: this.textEditModeEnabled,
|
|
2320
|
+
});
|
|
2298
2321
|
this.keyboardCleanup = keyboardCleanup;
|
|
2299
2322
|
this.cleanupCallbacks.push(keyboardCleanup);
|
|
2300
2323
|
});
|
|
@@ -2408,7 +2431,9 @@ class MarkupCanvas {
|
|
|
2408
2431
|
if (this.keyboardCleanup) {
|
|
2409
2432
|
return true; // Already enabled
|
|
2410
2433
|
}
|
|
2411
|
-
this.keyboardCleanup = setupKeyboardEvents(this, this.config
|
|
2434
|
+
this.keyboardCleanup = setupKeyboardEvents(this, this.config, {
|
|
2435
|
+
textEditModeEnabled: this.textEditModeEnabled,
|
|
2436
|
+
});
|
|
2412
2437
|
this.cleanupCallbacks.push(this.keyboardCleanup);
|
|
2413
2438
|
return true;
|
|
2414
2439
|
}
|
|
@@ -2423,6 +2448,54 @@ class MarkupCanvas {
|
|
|
2423
2448
|
isKeyboardEnabled() {
|
|
2424
2449
|
return this.keyboardCleanup !== null;
|
|
2425
2450
|
}
|
|
2451
|
+
// Text edit mode control methods
|
|
2452
|
+
enableTextEditMode() {
|
|
2453
|
+
if (this.textEditModeEnabled) {
|
|
2454
|
+
return true; // Already enabled
|
|
2455
|
+
}
|
|
2456
|
+
this.textEditModeEnabled = true;
|
|
2457
|
+
// If keyboard is currently enabled, re-setup with new option
|
|
2458
|
+
if (this.keyboardCleanup) {
|
|
2459
|
+
// Remove old cleanup from callbacks
|
|
2460
|
+
const index = this.cleanupCallbacks.indexOf(this.keyboardCleanup);
|
|
2461
|
+
if (index > -1) {
|
|
2462
|
+
this.cleanupCallbacks.splice(index, 1);
|
|
2463
|
+
}
|
|
2464
|
+
// Cleanup old handler
|
|
2465
|
+
this.keyboardCleanup();
|
|
2466
|
+
// Setup new handler with text edit mode enabled
|
|
2467
|
+
this.keyboardCleanup = setupKeyboardEvents(this, this.config, {
|
|
2468
|
+
textEditModeEnabled: true,
|
|
2469
|
+
});
|
|
2470
|
+
this.cleanupCallbacks.push(this.keyboardCleanup);
|
|
2471
|
+
}
|
|
2472
|
+
return true;
|
|
2473
|
+
}
|
|
2474
|
+
disableTextEditMode() {
|
|
2475
|
+
if (!this.textEditModeEnabled) {
|
|
2476
|
+
return true; // Already disabled
|
|
2477
|
+
}
|
|
2478
|
+
this.textEditModeEnabled = false;
|
|
2479
|
+
// If keyboard is currently enabled, re-setup with new option
|
|
2480
|
+
if (this.keyboardCleanup) {
|
|
2481
|
+
// Remove old cleanup from callbacks
|
|
2482
|
+
const index = this.cleanupCallbacks.indexOf(this.keyboardCleanup);
|
|
2483
|
+
if (index > -1) {
|
|
2484
|
+
this.cleanupCallbacks.splice(index, 1);
|
|
2485
|
+
}
|
|
2486
|
+
// Cleanup old handler
|
|
2487
|
+
this.keyboardCleanup();
|
|
2488
|
+
// Setup new handler with text edit mode disabled
|
|
2489
|
+
this.keyboardCleanup = setupKeyboardEvents(this, this.config, {
|
|
2490
|
+
textEditModeEnabled: false,
|
|
2491
|
+
});
|
|
2492
|
+
this.cleanupCallbacks.push(this.keyboardCleanup);
|
|
2493
|
+
}
|
|
2494
|
+
return true;
|
|
2495
|
+
}
|
|
2496
|
+
isTextEditModeEnabled() {
|
|
2497
|
+
return this.textEditModeEnabled;
|
|
2498
|
+
}
|
|
2426
2499
|
toggleGrid() {
|
|
2427
2500
|
const result = toggleGrid(this.rulers);
|
|
2428
2501
|
if (result) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Markup Canvas
|
|
3
3
|
* High-performance markup canvas with zoom and pan capabilities
|
|
4
|
-
* @version 1.3.
|
|
4
|
+
* @version 1.3.4
|
|
5
5
|
*/
|
|
6
6
|
(function (global, factory) {
|
|
7
7
|
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
|
|
@@ -889,7 +889,8 @@
|
|
|
889
889
|
}
|
|
890
890
|
}
|
|
891
891
|
|
|
892
|
-
function setupKeyboardEvents(canvas, config) {
|
|
892
|
+
function setupKeyboardEvents(canvas, config, options) {
|
|
893
|
+
const textEditModeEnabled = options?.textEditModeEnabled ?? false;
|
|
893
894
|
function handleKeyDown(event) {
|
|
894
895
|
if (!(event instanceof KeyboardEvent))
|
|
895
896
|
return;
|
|
@@ -899,23 +900,38 @@
|
|
|
899
900
|
const newTransform = {};
|
|
900
901
|
switch (event.key) {
|
|
901
902
|
case "ArrowLeft":
|
|
903
|
+
if (textEditModeEnabled) {
|
|
904
|
+
return;
|
|
905
|
+
}
|
|
902
906
|
newTransform.translateX = canvas.transform.translateX + config.keyboardPanStep;
|
|
903
907
|
handled = true;
|
|
904
908
|
break;
|
|
905
909
|
case "ArrowRight":
|
|
910
|
+
if (textEditModeEnabled) {
|
|
911
|
+
return;
|
|
912
|
+
}
|
|
906
913
|
newTransform.translateX = canvas.transform.translateX - config.keyboardPanStep;
|
|
907
914
|
handled = true;
|
|
908
915
|
break;
|
|
909
916
|
case "ArrowUp":
|
|
917
|
+
if (textEditModeEnabled) {
|
|
918
|
+
return;
|
|
919
|
+
}
|
|
910
920
|
newTransform.translateY = canvas.transform.translateY + config.keyboardPanStep;
|
|
911
921
|
handled = true;
|
|
912
922
|
break;
|
|
913
923
|
case "ArrowDown":
|
|
924
|
+
if (textEditModeEnabled) {
|
|
925
|
+
return;
|
|
926
|
+
}
|
|
914
927
|
newTransform.translateY = canvas.transform.translateY - config.keyboardPanStep;
|
|
915
928
|
handled = true;
|
|
916
929
|
break;
|
|
917
930
|
case "=":
|
|
918
931
|
case "+":
|
|
932
|
+
if (textEditModeEnabled) {
|
|
933
|
+
return;
|
|
934
|
+
}
|
|
919
935
|
{
|
|
920
936
|
const adaptiveZoomStep = config.enableAdaptiveSpeed
|
|
921
937
|
? getAdaptiveZoomSpeed(canvas, config.keyboardZoomStep)
|
|
@@ -925,6 +941,9 @@
|
|
|
925
941
|
}
|
|
926
942
|
break;
|
|
927
943
|
case "-":
|
|
944
|
+
if (textEditModeEnabled) {
|
|
945
|
+
return;
|
|
946
|
+
}
|
|
928
947
|
{
|
|
929
948
|
const adaptiveZoomStep = config.enableAdaptiveSpeed
|
|
930
949
|
? getAdaptiveZoomSpeed(canvas, config.keyboardZoomStep)
|
|
@@ -1690,7 +1709,6 @@
|
|
|
1690
1709
|
height: ${config.rulerSize}px;
|
|
1691
1710
|
background: var(--ruler-background-color);
|
|
1692
1711
|
border-bottom: 1px solid var(--ruler-border-color);
|
|
1693
|
-
border-right: 1px solid var(--ruler-border-color);
|
|
1694
1712
|
z-index: ${RULER_Z_INDEX.RULERS};
|
|
1695
1713
|
pointer-events: none;
|
|
1696
1714
|
font-family: ${config.rulerFontFamily};
|
|
@@ -1712,7 +1730,6 @@
|
|
|
1712
1730
|
width: ${config.rulerSize}px;
|
|
1713
1731
|
background: var(--ruler-background-color);
|
|
1714
1732
|
border-right: 1px solid var(--ruler-border-color);
|
|
1715
|
-
border-bottom: 1px solid var(--ruler-border-color);
|
|
1716
1733
|
z-index: ${RULER_Z_INDEX.RULERS};
|
|
1717
1734
|
pointer-events: none;
|
|
1718
1735
|
font-family: ${config.rulerFontFamily};
|
|
@@ -2114,6 +2131,9 @@
|
|
|
2114
2131
|
enable: canvas.enableKeyboard.bind(canvas),
|
|
2115
2132
|
disable: canvas.disableKeyboard.bind(canvas),
|
|
2116
2133
|
isEnabled: canvas.isKeyboardEnabled.bind(canvas),
|
|
2134
|
+
enableTextEditMode: canvas.enableTextEditMode.bind(canvas),
|
|
2135
|
+
disableTextEditMode: canvas.disableTextEditMode.bind(canvas),
|
|
2136
|
+
isTextEditModeEnabled: canvas.isTextEditModeEnabled.bind(canvas),
|
|
2117
2137
|
},
|
|
2118
2138
|
// Grid group
|
|
2119
2139
|
grid: {
|
|
@@ -2188,6 +2208,7 @@
|
|
|
2188
2208
|
this.rulers = null;
|
|
2189
2209
|
this.dragSetup = null;
|
|
2190
2210
|
this.keyboardCleanup = null;
|
|
2211
|
+
this.textEditModeEnabled = false;
|
|
2191
2212
|
this.event = new EventEmitter();
|
|
2192
2213
|
this._isReady = false;
|
|
2193
2214
|
if (!container) {
|
|
@@ -2239,7 +2260,9 @@
|
|
|
2239
2260
|
}
|
|
2240
2261
|
// Keyboard events
|
|
2241
2262
|
withFeatureEnabled(this.config, "enableKeyboard", () => {
|
|
2242
|
-
const keyboardCleanup = setupKeyboardEvents(this, this.config
|
|
2263
|
+
const keyboardCleanup = setupKeyboardEvents(this, this.config, {
|
|
2264
|
+
textEditModeEnabled: this.textEditModeEnabled,
|
|
2265
|
+
});
|
|
2243
2266
|
this.keyboardCleanup = keyboardCleanup;
|
|
2244
2267
|
this.cleanupCallbacks.push(keyboardCleanup);
|
|
2245
2268
|
});
|
|
@@ -2353,7 +2376,9 @@
|
|
|
2353
2376
|
if (this.keyboardCleanup) {
|
|
2354
2377
|
return true; // Already enabled
|
|
2355
2378
|
}
|
|
2356
|
-
this.keyboardCleanup = setupKeyboardEvents(this, this.config
|
|
2379
|
+
this.keyboardCleanup = setupKeyboardEvents(this, this.config, {
|
|
2380
|
+
textEditModeEnabled: this.textEditModeEnabled,
|
|
2381
|
+
});
|
|
2357
2382
|
this.cleanupCallbacks.push(this.keyboardCleanup);
|
|
2358
2383
|
return true;
|
|
2359
2384
|
}
|
|
@@ -2368,6 +2393,54 @@
|
|
|
2368
2393
|
isKeyboardEnabled() {
|
|
2369
2394
|
return this.keyboardCleanup !== null;
|
|
2370
2395
|
}
|
|
2396
|
+
// Text edit mode control methods
|
|
2397
|
+
enableTextEditMode() {
|
|
2398
|
+
if (this.textEditModeEnabled) {
|
|
2399
|
+
return true; // Already enabled
|
|
2400
|
+
}
|
|
2401
|
+
this.textEditModeEnabled = true;
|
|
2402
|
+
// If keyboard is currently enabled, re-setup with new option
|
|
2403
|
+
if (this.keyboardCleanup) {
|
|
2404
|
+
// Remove old cleanup from callbacks
|
|
2405
|
+
const index = this.cleanupCallbacks.indexOf(this.keyboardCleanup);
|
|
2406
|
+
if (index > -1) {
|
|
2407
|
+
this.cleanupCallbacks.splice(index, 1);
|
|
2408
|
+
}
|
|
2409
|
+
// Cleanup old handler
|
|
2410
|
+
this.keyboardCleanup();
|
|
2411
|
+
// Setup new handler with text edit mode enabled
|
|
2412
|
+
this.keyboardCleanup = setupKeyboardEvents(this, this.config, {
|
|
2413
|
+
textEditModeEnabled: true,
|
|
2414
|
+
});
|
|
2415
|
+
this.cleanupCallbacks.push(this.keyboardCleanup);
|
|
2416
|
+
}
|
|
2417
|
+
return true;
|
|
2418
|
+
}
|
|
2419
|
+
disableTextEditMode() {
|
|
2420
|
+
if (!this.textEditModeEnabled) {
|
|
2421
|
+
return true; // Already disabled
|
|
2422
|
+
}
|
|
2423
|
+
this.textEditModeEnabled = false;
|
|
2424
|
+
// If keyboard is currently enabled, re-setup with new option
|
|
2425
|
+
if (this.keyboardCleanup) {
|
|
2426
|
+
// Remove old cleanup from callbacks
|
|
2427
|
+
const index = this.cleanupCallbacks.indexOf(this.keyboardCleanup);
|
|
2428
|
+
if (index > -1) {
|
|
2429
|
+
this.cleanupCallbacks.splice(index, 1);
|
|
2430
|
+
}
|
|
2431
|
+
// Cleanup old handler
|
|
2432
|
+
this.keyboardCleanup();
|
|
2433
|
+
// Setup new handler with text edit mode disabled
|
|
2434
|
+
this.keyboardCleanup = setupKeyboardEvents(this, this.config, {
|
|
2435
|
+
textEditModeEnabled: false,
|
|
2436
|
+
});
|
|
2437
|
+
this.cleanupCallbacks.push(this.keyboardCleanup);
|
|
2438
|
+
}
|
|
2439
|
+
return true;
|
|
2440
|
+
}
|
|
2441
|
+
isTextEditModeEnabled() {
|
|
2442
|
+
return this.textEditModeEnabled;
|
|
2443
|
+
}
|
|
2371
2444
|
toggleGrid() {
|
|
2372
2445
|
const result = toggleGrid(this.rulers);
|
|
2373
2446
|
if (result) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).MarkupCanvas=t()}(this,function(){"use strict";function e(e,t,n){if(!n?.inverse)return{x:e,y:t};try{const r=n.inverse(),o=new DOMPoint(e,t).matrixTransform(r);return{x:o.x,y:o.y}}catch(n){return console.warn("Canvas to content conversion failed:",n),{x:e,y:t}}}function t(e,t){return Math.max(t.minZoom,Math.min(t.maxZoom,e))}function n(e,t,n){return new DOMMatrix([e,0,0,e,t,n])}const r="canvas-container",o="transform-layer",a="content-layer";function s(e,n,r,o,a){const s=a.enableRulers?-a.rulerSize:0,i=r||{scale:1,translateX:s,translateY:s},{scale:l,translateX:c,translateY:u}=i,d=t(l*o,a);if(Math.abs(d-l)<.001)return{scale:l,translateX:c,translateY:u};return{scale:d,translateX:e-(e-c)/l*d,translateY:n-(n-u)/l*d}}function i(e){return e.getBounds().visibleArea}function l(e,n){return n(n=>t(n,e))}const c=new Map;function u(e,t,n){return e[t]?n():null}function d(e){let t=null,n=null;const r=(...r)=>{n=r,null===t&&(t=requestAnimationFrame(()=>{n&&e(...n),t=null,n=null}))};return r.cleanup=()=>{null!==t&&(cancelAnimationFrame(t),t=null,n=null)},r}function h(e,t,n){return n(null!==e.container.querySelector(".canvas-ruler")?t:0)}function g(e,t,n,r,o){const a=null!==e.container.querySelector(".canvas-ruler");return o(a?t-r:t,a?n-r:n)}function m(e,t){if("dark"===e.themeMode){return e[`${t}Dark`]}return e[t]}const p={width:8e3,height:8e3,enableAcceleration:!0,initialZoom:1,initialPan:{x:0,y:0},name:"markupCanvas",enablePostMessageAPI:!1,enableZoom:!0,enablePan:!0,enableTouch:!0,enableKeyboard:!0,bindKeyboardEventsTo:"document",zoomSpeed:1.5,minZoom:.05,maxZoom:80,enableTransition:!0,transitionDuration:.2,enableAdaptiveSpeed:!0,enableLeftDrag:!0,enableMiddleDrag:!0,requireSpaceForMouseDrag:!1,keyboardPanStep:50,keyboardFastMultiplier:20,keyboardZoomStep:.2,enableClickToZoom:!0,clickZoomLevel:1,requireOptionForClickZoom:!1,enableRulers:!0,enableGrid:!1,showRulers:!0,showGrid:!1,rulerFontSize:9,rulerFontFamily:"Monaco, Menlo, monospace",rulerUnits:"px",rulerSize:20,canvasBackgroundColor:"rgba(250, 250, 250, 1)",canvasBackgroundColorDark:"rgba(40, 40, 40, 1)",rulerBackgroundColor:"rgba(255, 255, 255, 0.95)",rulerBorderColor:"rgba(240, 240, 240, 1)",rulerTextColor:"rgba(102, 102, 102, 1)",rulerTickColor:"rgba(204, 204, 204, 1)",gridColor:"rgba(232, 86, 193, 0.5)",rulerBackgroundColorDark:"rgba(30, 30, 30, 0.95)",rulerBorderColorDark:"rgba(68, 68, 68, 1)",rulerTextColorDark:"rgba(170, 170, 170, 1)",rulerTickColorDark:"rgba(104, 104, 104, 1)",gridColorDark:"rgba(232, 86, 193, 0.5)",themeMode:"light"};function f(t,r){try{const o=t.container,a=t.transform||{scale:1,translateX:0,translateY:0},s=o.getBoundingClientRect(),i=s.width||o.clientWidth||0,l=s.height||o.clientHeight||0,c=h({container:o},r.rulerSize,e=>Math.max(0,i-e)),u=h({container:o},r.rulerSize,e=>Math.max(0,l-e)),d=r.width||p.width,g=r.height||p.height,m=function(t,r,o,a,s){const i=e(0,0,n(s.scale,s.translateX,s.translateY)),l=e(t,r,n(s.scale,s.translateX,s.translateY));return{x:Math.max(0,Math.min(o,i.x)),y:Math.max(0,Math.min(a,i.y)),width:Math.max(0,Math.min(o-i.x,l.x-i.x)),height:Math.max(0,Math.min(a-i.y,l.y-i.y))}}(c,u,d,g,a);return{width:c,height:u,contentWidth:d,contentHeight:g,scale:a.scale,translateX:a.translateX,translateY:a.translateY,visibleArea:m,scaledContentWidth:d*a.scale,scaledContentHeight:g*a.scale,canPanLeft:a.translateX<0,canPanRight:a.translateX+d*a.scale>c,canPanUp:a.translateY<0,canPanDown:a.translateY+g*a.scale>u,canZoomIn:a.scale<3.5,canZoomOut:a.scale>.1}}catch(e){return console.error("Failed to calculate canvas bounds:",e),{width:0,height:0,contentWidth:0,contentHeight:0,scale:1,translateX:0,translateY:0,visibleArea:{x:0,y:0,width:0,height:0},scaledContentWidth:0,scaledContentHeight:0,canPanLeft:!1,canPanRight:!1,canPanUp:!1,canPanDown:!1,canZoomIn:!1,canZoomOut:!1}}}function b(e,t){try{if(t.enableTransition){window.__markupCanvasTransitionTimeout&&(clearTimeout(window.__markupCanvasTransitionTimeout),window.__markupCanvasTransitionTimeout=void 0);return function(e,t,n){const r=c.get(e);r&&clearTimeout(r);const o=window.setTimeout(()=>{n(),c.delete(e)},t);c.set(e,o)}("disableTransition",1e3*(t.transitionDuration??.2),()=>{e.style.transition="none",window.__markupCanvasTransitionTimeout=void 0}),!0}return!1}catch(e){return console.error("Failed to disable transitions:",e),!0}}function y(e,t,n){!function(e,t){try{return!!t.enableTransition&&(window.__markupCanvasTransitionTimeout&&(clearTimeout(window.__markupCanvasTransitionTimeout),window.__markupCanvasTransitionTimeout=void 0),e.style.transition=`transform ${t.transitionDuration}s linear`,!0)}catch(e){return console.error("Failed to enable transitions:",e),!1}}(e,t);try{return n()}finally{b(e,t)}}function v(e,t,n){const r=t.keyboardPanStep;return n({translateY:e.transform.translateY-r})}function w(e,t,n){const r=t.keyboardPanStep;return n({translateX:e.transform.translateX+r})}function k(e,t,n){const r=t.keyboardPanStep;return n({translateX:e.transform.translateX-r})}function x(e,t,n){const r=t.keyboardPanStep;return n({translateY:e.transform.translateY+r})}function T(e,t){if(!e?.style||!t)return!1;try{return e.style.transform=function(e){return`matrix3d(${e.m11}, ${e.m12}, ${e.m13}, ${e.m14}, ${e.m21}, ${e.m22}, ${e.m23}, ${e.m24}, ${e.m31}, ${e.m32}, ${e.m33}, ${e.m34}, ${e.m41}, ${e.m42}, ${e.m43}, ${e.m44})`}(t),!0}catch(e){return console.warn("Transform application failed:",e),!1}}function C(e,t){e.transform={...e.transform,...t};const r=n(e.transform.scale,e.transform.translateX,e.transform.translateY);return T(e.transformLayer,r)}function M(e={}){const t={...p,...e};return("number"!=typeof t.width||t.width<=0)&&(console.warn("Invalid width, using default"),t.width=p.width),("number"!=typeof t.height||t.height<=0)&&(console.warn("Invalid height, using default"),t.height=p.height),("number"!=typeof t.zoomSpeed||t.zoomSpeed<=0)&&(console.warn("Invalid zoomSpeed, using default"),t.zoomSpeed=p.zoomSpeed),("number"!=typeof t.minZoom||t.minZoom<=0)&&(console.warn("Invalid minZoom, using default"),t.minZoom=p.minZoom),("number"!=typeof t.maxZoom||t.maxZoom<=t.minZoom)&&(console.warn("Invalid maxZoom, using default"),t.maxZoom=p.maxZoom),("number"!=typeof t.keyboardPanStep||t.keyboardPanStep<=0)&&(console.warn("Invalid keyboardPanStep, using default"),t.keyboardPanStep=p.keyboardPanStep),("number"!=typeof t.keyboardFastMultiplier||t.keyboardFastMultiplier<=0)&&(console.warn("Invalid keyboardFastMultiplier, using default"),t.keyboardFastMultiplier=p.keyboardFastMultiplier),("number"!=typeof t.clickZoomLevel||t.clickZoomLevel<=0)&&(console.warn("Invalid clickZoomLevel, using default"),t.clickZoomLevel=p.clickZoomLevel),("number"!=typeof t.rulerFontSize||t.rulerFontSize<=0)&&(console.warn("Invalid rulerFontSize, using default"),t.rulerFontSize=p.rulerFontSize),("number"!=typeof t.rulerSize||t.rulerSize<=0)&&(console.warn("Invalid rulerSize, using default"),t.rulerSize=p.rulerSize),t}function S(e,t,n,r){const o=M({...t,themeMode:r}),a=m(o,"canvasBackgroundColor");e.style.backgroundColor=a,n&&n.updateTheme(o)}function D(e){try{const t=e.getBounds();return{x:t.width/2,y:t.height/2}}catch(e){return console.warn("Failed to calculate viewport center:",e),{x:0,y:0}}}function z(e,t){const n=Array.from(e.children);let r=e.querySelector(`.${o}`);r||(r=document.createElement("div"),r.className=o,e.appendChild(r)),function(e,t){e.style.position="absolute";const n=t.rulerSize;e.style.top=`${n}px`,e.style.left=`${n}px`,e.style.width=`${t.width}px`,e.style.height=`${t.height}px`,e.style.transformOrigin="0 0"}(r,t);let s=r.querySelector(`.${a}`);return s||(s=document.createElement("div"),s.className=a,r.appendChild(s),function(e,t,n){e.forEach(e=>{e===n||e.classList.contains(o)||t.appendChild(e)})}(n,s,r)),function(e){e.style.position="relative",e.style.width="100%",e.style.height="100%",e.style.pointerEvents="auto"}(s),{transformLayer:r,contentLayer:s}}function L(e,t){if("static"===getComputedStyle(e).position&&(e.style.position="relative"),e.style.overflow="hidden",e.style.cursor="grab",e.style.overscrollBehavior="none",t){const n=m(t,"canvasBackgroundColor");e.style.backgroundColor=n}e.hasAttribute("tabindex")||e.setAttribute("tabindex","0"),function(e){const t=e.getBoundingClientRect(),n=getComputedStyle(e);0===t.height&&"auto"===n.height&&console.error("MarkupCanvas: Container height is 0. Please set a height on your container element using CSS.","Examples: height: 100vh, height: 500px, or use flexbox/grid layout.",e),0===t.width&&"auto"===n.width&&console.error("MarkupCanvas: Container width is 0. Please set a width on your container element using CSS.","Examples: width: 100vw, width: 800px, or use flexbox/grid layout.",e)}(e),e.classList.contains(r)||e.classList.add(r)}function R(e,t){if(!e?.appendChild)return console.error("Invalid container element provided to createCanvas"),null;try{L(e,t);const{transformLayer:r,contentLayer:o}=z(e,t);u(t,"enableAcceleration",()=>{!function(e){try{return e.style.transform=e.style.transform||"translateZ(0)",e.style.backfaceVisibility="hidden",!0}catch(e){return console.error("Failed to enable hardware acceleration:",e),!1}}(r)});const a=t.enableRulers?-t.rulerSize:0,s={scale:t.initialZoom??1,translateX:(t.initialPan?.x??0)+a,translateY:(t.initialPan?.y??0)+a},i=n(s.scale,s.translateX,s.translateY);T(r,i);return{container:e,transformLayer:r,contentLayer:o,transform:s}}catch(e){return console.error("Failed to create canvas:",e),null}}class P{constructor(){this.listeners=new Map}setEmitInterceptor(e){this.emitInterceptor=e}on(e,t){this.listeners.has(e)||this.listeners.set(e,new Set),this.listeners.get(e).add(t)}off(e,t){const n=this.listeners.get(e);n&&n.delete(t)}emit(e,t){this.emitInterceptor?.(e,t);const n=this.listeners.get(e);n&&n.forEach(n=>{try{n(t)}catch(t){console.error(`Error in event handler for "${String(e)}":`,t)}})}removeAllListeners(){this.listeners.clear()}}function E(e,t){const n=t.transform;e.emit("transform",n),e.emit("zoom",n.scale),e.emit("pan",{x:n.translateX,y:n.translateY})}const Y=300,X=5;function $(e,t){if(!e?.getBounds)return t;try{const n=e.getBounds(),r=n.width*n.height;return t*(r/2073600)**1}catch(e){return console.warn("Failed to calculate adaptive zoom speed, using base speed:",e),t}}function I(e,t){function n(n){if(!(n instanceof KeyboardEvent))return;if("canvas"===t.bindKeyboardEventsTo&&document.activeElement!==e.container)return;let r=!1;const o={};switch(n.key){case"ArrowLeft":o.translateX=e.transform.translateX+t.keyboardPanStep,r=!0;break;case"ArrowRight":o.translateX=e.transform.translateX-t.keyboardPanStep,r=!0;break;case"ArrowUp":o.translateY=e.transform.translateY+t.keyboardPanStep,r=!0;break;case"ArrowDown":o.translateY=e.transform.translateY-t.keyboardPanStep,r=!0;break;case"=":case"+":{const n=t.enableAdaptiveSpeed?$(e,t.keyboardZoomStep):t.keyboardZoomStep;e.zoomIn(n),r=!0}break;case"-":{const n=t.enableAdaptiveSpeed?$(e,t.keyboardZoomStep):t.keyboardZoomStep;e.zoomOut(n),r=!0}break;case"0":n.ctrlKey?(e.resetView&&e.resetView(),r=!0):(n.metaKey||n.ctrlKey)&&(e.resetViewToCenter&&e.resetViewToCenter(),r=!0);break;case"g":case"G":n.shiftKey&&e.toggleGrid&&e.toggleGrid(),r=n.shiftKey;break;case"r":case"R":!n.shiftKey||n.metaKey||n.ctrlKey||n.altKey||!e.toggleRulers||(e.toggleRulers(),r=!0)}r&&(n.preventDefault(),Object.keys(o).length>0&&e.updateTransform(o))}const r="canvas"===t.bindKeyboardEventsTo?e.container:document;return r.addEventListener("keydown",n),()=>{r.removeEventListener("keydown",n)}}function B(e,t,n,r,o){n?t.requireSpaceForMouseDrag?e.container.style.cursor=r?"grab":"default":e.container.style.cursor=o?"grabbing":"grab":e.container.style.cursor="default"}function Z(e,t,n,r,o){o.setIsDragging(!1),o.setDragButton(-1),B(e,t,n,r,!1)}function F(e,t,n,r,o,a,s,i,l,c){a&&e.button===s&&Z(t,n,r,o,{setIsDragging:c.setIsDragging,setDragButton:c.setDragButton}),r&&0===e.button&&n.enableClickToZoom&&i>0&&function(e,t,n,r,o,a){const s=Date.now()-r,i=e.altKey,l=!n.requireOptionForClickZoom||i;if(s<Y&&!o&&!a&&l){e.preventDefault();const r=t.container.getBoundingClientRect(),o=e.clientX-r.left,a=e.clientY-r.top,{clickX:s,clickY:i}=g(t,o,a,n.rulerSize,(e,t)=>({clickX:e,clickY:t})),l=t.canvasToContent(s,i),c=r.width/2,u=r.height/2,d=n.clickZoomLevel,h={scale:d,translateX:c-l.x*d,translateY:u-l.y*d};y(t.transformLayer,t.config,()=>{t.updateTransform(h)})}}(e,t,n,i,l,a),0===e.button&&function(e){e.setMouseDownTime(0),e.setHasDragged(!1)}({setMouseDownTime:c.setMouseDownTime,setHasDragged:c.setHasDragged})}function O(e,t,n=!0){let r=!0,o=!1,a=0,s=0,i=-1,l=!1,c=0,u=0,h=0,g=!1;const m={setIsDragging:e=>{o=e},setDragButton:e=>{i=e},setIsSpacePressed:e=>{l=e},setMouseDownTime:e=>{c=e},setMouseDownX:e=>{u=e},setMouseDownY:e=>{h=e},setHasDragged:e=>{g=e},setLastMouseX:e=>{a=e},setLastMouseY:e=>{s=e}},p=n=>{!function(e,t,n,r,o,a){n.requireSpaceForMouseDrag&&" "===e.key&&(a.setIsSpacePressed(!0),B(t,n,r,!0,o))}(n,e,t,r,o,{setIsSpacePressed:m.setIsSpacePressed})},f=n=>{!function(e,t,n,r,o,a){n.requireSpaceForMouseDrag&&" "===e.key&&(a.setIsSpacePressed(!1),B(t,n,r,!1,o),o&&Z(t,n,r,!1,{setIsDragging:a.setIsDragging,setDragButton:a.setDragButton}))}(n,e,t,r,o,{setIsSpacePressed:m.setIsSpacePressed,setIsDragging:m.setIsDragging,setDragButton:m.setDragButton})},b=n=>{!function(e,t,n,r,o,a){const s=0===e.button,i=1===e.button;if(s&&(a.setMouseDownTime(Date.now()),a.setMouseDownX(e.clientX),a.setMouseDownY(e.clientY),a.setHasDragged(!1)),!r)return;(!n.requireSpaceForMouseDrag||o)&&(s&&n.enableLeftDrag||i&&n.enableMiddleDrag)&&(e.preventDefault(),a.setDragButton(e.button),a.setLastMouseX(e.clientX),a.setLastMouseY(e.clientY),B(t,n,r,o,!1))}(n,e,t,r,l,m)},y=n=>{!function(e,t,n,r,o,a,s,i,l,c,u,h){if(s>0){const t=Math.abs(e.clientX-i),s=Math.abs(e.clientY-l);if(t>X||s>X){h.setHasDragged(!0);const e=!n.requireSpaceForMouseDrag||a;!o&&r&&e&&h.setIsDragging(!0)}}if(!o||!r)return;e.preventDefault(),d((...e)=>{const n=e[0];if(!o||!r)return;const a=n.clientX-c,s=n.clientY-u,i={translateX:t.transform.translateX+a,translateY:t.transform.translateY+s};t.updateTransform(i),h.setLastMouseX(n.clientX),h.setLastMouseY(n.clientY)})(e)}(n,e,t,r,o,l,c,u,h,a,s,{setHasDragged:m.setHasDragged,setIsDragging:m.setIsDragging,setLastMouseX:m.setLastMouseX,setLastMouseY:m.setLastMouseY})},v=n=>{F(n,e,t,r,l,o,i,c,g,{setIsDragging:m.setIsDragging,setDragButton:m.setDragButton,setMouseDownTime:m.setMouseDownTime,setHasDragged:m.setHasDragged})},w=()=>{!function(e,t,n,r,o,a){o&&Z(e,t,n,r,a)}(e,t,r,l,o,{setIsDragging:m.setIsDragging,setDragButton:m.setDragButton})};e.container.addEventListener("mousedown",b),document.addEventListener("mousemove",y),document.addEventListener("mouseup",v),e.container.addEventListener("mouseleave",w),t.requireSpaceForMouseDrag&&(document.addEventListener("keydown",p),document.addEventListener("keyup",f)),B(e,t,r,l,o);const k=()=>{e.container.removeEventListener("mousedown",b),document.removeEventListener("mousemove",y),document.removeEventListener("mouseup",v),e.container.removeEventListener("mouseleave",w),t.requireSpaceForMouseDrag&&(document.removeEventListener("keydown",p),document.removeEventListener("keyup",f))};return n?{cleanup:k,enable:()=>(r=!0,B(e,t,r,l,o),!0),disable:()=>(r=!1,o&&Z(e,t,r,l,{setIsDragging:m.setIsDragging,setDragButton:m.setDragButton}),B(e,t,r,l,o),!0),isEnabled:()=>r}:k}function V(e,t,n,r){try{switch(t){case"zoomIn":e.zoomIn(n);break;case"zoomOut":e.zoomOut(n);break;case"setZoom":{const t=n;if("number"!=typeof t||t<=0)throw new Error(`Invalid zoom level: ${t}. Must be a positive number.`);e.setZoom(t);break}case"resetZoom":e.resetZoom();break;case"panLeft":e.panLeft(n);break;case"panRight":e.panRight(n);break;case"panUp":e.panUp(n);break;case"panDown":e.panDown(n);break;case"fitToScreen":e.fitToScreen();break;case"centerContent":e.centerContent();break;case"panToPoint":{const t=n;e.panToPoint(t.x,t.y);break}case"resetView":e.resetView();break;case"resetViewToCenter":e.resetViewToCenter();break;case"toggleRulers":e.toggleRulers();break;case"showRulers":e.showRulers();break;case"hideRulers":e.hideRulers();break;case"toggleGrid":e.toggleGrid();break;case"showGrid":e.showGrid();break;case"hideGrid":e.hideGrid();break;case"updateThemeMode":{const t=n;if("light"!==t&&"dark"!==t)throw new Error(`Invalid theme mode: ${t}`);e.updateThemeMode(t);break}case"toggleThemeMode":{const t="light"===e.getConfig().themeMode?"dark":"light";e.updateThemeMode(t);break}case"updateTransition":{const t=n;if("boolean"!=typeof t)throw new Error(`Invalid transition enabled value: ${t}. Must be a boolean.`);e.updateTransition(t);break}case"toggleTransitionMode":e.toggleTransitionMode();break;default:throw new Error(`Unknown action: ${t}`)}}catch(e){!function(e,t,n){window.postMessage({source:"markup-canvas-error",canvasName:e,action:t,error:n,timestamp:Date.now()},"*")}(r,t,e instanceof Error?e.message:String(e))}}function A(e,t){return{x:(e.clientX+t.clientX)/2,y:(e.clientY+t.clientY)/2}}function _(e,t){const n=e.clientX-t.clientX,r=e.clientY-t.clientY;return Math.sqrt(n*n+r*r)}function G(e,t,n,r){const o=s(n,r,e.transform,t,e.config);return e.updateTransform(o)}function K(e,t,n){e.preventDefault();const r=Array.from(e.touches);d((...e)=>{const r=e[0];if(1===r.length){if(1===n.touches.length){const e=r[0].clientX-n.touches[0].clientX,o=r[0].clientY-n.touches[0].clientY,a={translateX:t.transform.translateX+e,translateY:t.transform.translateY+o};t.updateTransform(a)}}else if(2===r.length){const e=_(r[0],r[1]),o=A(r[0],r[1]);if(n.lastDistance>0){const r=e/n.lastDistance,a=t.container.getBoundingClientRect();let s=o.x-a.left,i=o.y-a.top;const l=function(e,t,n,r){return h(e,t,e=>{const t={...n,x:n.x-e,y:n.y-e};return r(t)})}(t,t.config.rulerSize,{x:s,y:i},e=>e);s=l.x,i=l.y,G(t,r,s,i)}n.lastDistance=e,n.lastCenter=o}n.touches=r})(r)}function H(e){const t={touches:[],lastDistance:0,lastCenter:{}},n=e=>{!function(e,t){e.preventDefault(),t.touches=Array.from(e.touches),2===t.touches.length&&(t.lastDistance=_(t.touches[0],t.touches[1]),t.lastCenter=A(t.touches[0],t.touches[1]))}(e,t)},r=n=>{K(n,e,t)},o=e=>{!function(e,t){t.touches=Array.from(e.touches),t.touches.length<2&&(t.lastDistance=0)}(e,t)};return e.container.addEventListener("touchstart",n,{passive:!1}),e.container.addEventListener("touchmove",r,{passive:!1}),e.container.addEventListener("touchend",o,{passive:!1}),()=>{e.container.removeEventListener("touchstart",n),e.container.removeEventListener("touchmove",r),e.container.removeEventListener("touchend",o)}}function N(e){const t=e.ctrlKey||e.metaKey,n=[0===e.deltaMode,Math.abs(e.deltaY)<50,e.deltaY%1!=0,Math.abs(e.deltaX)>0&&Math.abs(e.deltaY)>0].filter(Boolean).length>=2;return{isTrackpad:n,isMouseWheel:!n,isTrackpadScroll:n&&!t,isTrackpadPinch:n&&t,isZoomGesture:t}}function q(e,t){const n=(e=>d((...t)=>{const n=t[0];if(!n||!e?.updateTransform)return!1;try{const t=e.transform,r=1,o=n.deltaX*r,a=n.deltaY*r,s={scale:t.scale,translateX:t.translateX-o,translateY:t.translateY-a};return b(e.transformLayer,e.config),e.updateTransform(s)}catch(e){return console.error("Error handling trackpad pan:",e),!1}}))(e),r=r=>N(r).isTrackpadScroll?n(r):function(e,t,n){if(!e||"number"!=typeof e.deltaY)return console.warn("Invalid wheel event provided"),!1;if(!t?.updateTransform)return console.warn("Invalid canvas provided to handleWheelEvent"),!1;try{e.preventDefault();const r=t.container.getBoundingClientRect(),o=e.clientX-r.left,a=e.clientY-r.top,{mouseX:s,mouseY:i}=g(t,o,a,n.rulerSize,(e,t)=>({mouseX:e,mouseY:t})),l=n.zoomSpeed,c=N(e);if(!c.isZoomGesture)return!1;let u=n.enableAdaptiveSpeed?$(t,l):l;if(c.isTrackpadPinch){const e=.05*n.zoomSpeed;u=n.enableAdaptiveSpeed?$(t,e):e}return G(t,(e.deltaY<0?1:-1)>0?1+u:1/(1+u),s,i)}catch(e){return console.error("Error handling wheel event:",e),!1}}(r,e,t);return e.container.addEventListener("wheel",r,{passive:!1}),()=>{e.container.removeEventListener("wheel",r)}}const U=100,W=1e3,j=1001,J=4,Q=4,ee=100,te=100,ne=20,re=200;function oe(e,t){const n=function(e){const t=document.createElement("div");return t.className="canvas-ruler horizontal-ruler",t.style.cssText=`\n\tposition: absolute;\n\ttop: 0;\n\tleft: ${e.rulerSize}px;\n\tright: 0;\n\theight: ${e.rulerSize}px;\n\tbackground: var(--ruler-background-color);\n\tborder-bottom: 1px solid var(--ruler-border-color);\n\tborder-right: 1px solid var(--ruler-border-color);\n\tz-index: ${W};\n\tpointer-events: none;\n\tfont-family: ${e.rulerFontFamily};\n\tfont-size: ${e.rulerFontSize}px;\n\tcolor: var(--ruler-text-color);\n\toverflow: hidden;\n `,t}(t),r=function(e){const t=document.createElement("div");return t.className="canvas-ruler vertical-ruler",t.style.cssText=`\n\tposition: absolute;\n\ttop: ${e.rulerSize}px;\n\tleft: 0;\n\tbottom: 0;\n\twidth: ${e.rulerSize}px;\n\tbackground: var(--ruler-background-color);\n\tborder-right: 1px solid var(--ruler-border-color);\n\tborder-bottom: 1px solid var(--ruler-border-color);\n\tz-index: ${W};\n\tpointer-events: none;\n\tfont-family: ${e.rulerFontFamily};\n\tfont-size: ${e.rulerFontSize}px;\n\tcolor: var(--ruler-text-color);\n\toverflow: hidden;\n `,t}(t),o=function(e){const t=document.createElement("div");return t.className="canvas-ruler corner-box",t.style.cssText=`\n\t\tposition: absolute;\n\t\ttop: 0;\n\t\tleft: 0;\n\t\twidth: ${e.rulerSize}px;\n\t\theight: ${e.rulerSize}px;\n\t\tbackground: var(--ruler-background-color);\n\t\tborder-right: 1px solid var(--ruler-border-color);\n\t\tborder-bottom: 1px solid var(--ruler-border-color);\n\t\tz-index: ${j};\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t\tjustify-content: center;\n\t\tfont-family: ${e.rulerFontFamily};\n\t\tfont-size: ${e.rulerFontSize-2}px;\n\t\tcolor: var(--ruler-text-color);\n\t\tpointer-events: none;\n\t`,t.textContent=e.rulerUnits,t}(t),a=t.enableGrid?function(e){const t=document.createElement("div");return t.className="canvas-ruler grid-overlay",t.style.cssText=`\n\t\tposition: absolute;\n\t\ttop: ${e.rulerSize}px;\n\t\tleft: ${e.rulerSize}px;\n\t\tright: 0;\n\t\tbottom: 0;\n\t\tpointer-events: none;\n\t\tz-index: ${U};\n\t\tbackground-image: \n\t\t\tlinear-gradient(var(--grid-color) 1px, transparent 1px),\n\t\t\tlinear-gradient(90deg, var(--grid-color) 1px, transparent 1px);\n\t\tbackground-size: 100px 100px;\n\t\topacity: 0.5;\n\t`,t}(t):void 0;return e.appendChild(n),e.appendChild(r),e.appendChild(o),a&&e.appendChild(a),{horizontalRuler:n,verticalRuler:r,cornerBox:o,gridOverlay:a}}function ae(e,t){const n=e/Math.max(5,Math.min(20,t/50)),r=10**Math.floor(Math.log10(n)),o=n/r;let a;return a=o<=1?1:o<=2?2:o<=5?5:10,a*r}function se(e,t,n,r,o){const a=document.createElement("div");a.className="tick",a.style.cssText=`\n\t\tposition: absolute;\n\t\tleft: ${n}px;\n\t\tbottom: 0;\n\t\twidth: 1px;\n\t\theight: ${J}px;\n\t\tbackground: var(--ruler-tick-color);\n\t`,e.appendChild(a);if(t%ee===0){const r=document.createElement("div");r.style.cssText=`\n\t\t\tposition: absolute;\n\t\t\tleft: ${n}px;\n\t\t\tbottom: ${J+2}px;\n\t\t\tfont-size: ${o.rulerFontSize}px;\n\t\t\tline-height: 1;\n\t\t\tcolor: var(--ruler-text-color);\n\t\t\twhite-space: nowrap;\n\t\t\tpointer-events: none;\n\t\t`,r.textContent=Math.round(t).toString(),e.appendChild(r)}}function ie(e,t,n,r,o){const a=document.createElement("div");a.className="tick",a.style.cssText=`\n\t\tposition: absolute;\n\t\ttop: ${n}px;\n\t\tright: 0;\n\t\twidth: ${Q}px;\n\t\theight: 1px;\n\t\tbackground: var(--ruler-tick-color);\n\t`,e.appendChild(a);if(t%ee===0){const r=document.createElement("div");r.style.cssText=`\n\t\t\tposition: absolute;\n\t\t\ttop: ${n-6}px;\n\t\t\tright: ${Q+6}px;\n\t\t\tfont-size: ${o.rulerFontSize}px;\n\t\t\tline-height: 1;\n\t\t\tcolor: var(--ruler-text-color);\n\t\t\twhite-space: nowrap;\n\t\t\tpointer-events: none;\n\t\t\ttransform: rotate(-90deg);\n\t\t\ttransform-origin: right center;\n\t\t`,r.textContent=Math.round(t).toString(),e.appendChild(r)}}function le(e,t,n,r,o){const a=e.getBounds(),s=a.scale||1,i=a.translateX||0,l=a.translateY||0,c=a.width-o.rulerSize,u=a.height-o.rulerSize,d=-i/s,h=-l/s,g=h+u/s;!function(e,t,n,r,o,a){const s=r,i=ae(n-t,s),l=document.createDocumentFragment(),c=Math.floor(t/i)*i,u=Math.ceil(n/i)*i;for(let e=c;e<=u;e+=i){const n=(e-t)*o;n>=-50&&n<=s+50&&se(l,e,n,0,a)}e.innerHTML="",e.appendChild(l)}(t,d,d+c/s,c,s,o),function(e,t,n,r,o,a){const s=r,i=ae(n-t,s),l=document.createDocumentFragment(),c=Math.floor(t/i)*i,u=Math.ceil(n/i)*i;for(let e=c;e<=u;e+=i){const n=(e-t)*o;n>=-50&&n<=s+50&&ie(l,e,n,0,a)}e.innerHTML="",e.appendChild(l)}(n,h,g,u,s,o),r&&function(e,t,n,r){let o=te*t;for(;o<ne;)o*=2;for(;o>re;)o/=2;e.style.backgroundSize=`${o}px ${o}px`,e.style.backgroundPosition=`${n%o}px ${r%o}px`}(r,s,i,l)}function ce(e,t){const n=m(t,"rulerBackgroundColor"),r=m(t,"rulerBorderColor"),o=m(t,"rulerTextColor"),a=m(t,"rulerTickColor"),s=m(t,"gridColor");e.horizontalRuler&&(e.horizontalRuler.style.setProperty("--ruler-background-color",n),e.horizontalRuler.style.setProperty("--ruler-border-color",r),e.horizontalRuler.style.setProperty("--ruler-text-color",o),e.horizontalRuler.style.setProperty("--ruler-tick-color",a)),e.verticalRuler&&(e.verticalRuler.style.setProperty("--ruler-background-color",n),e.verticalRuler.style.setProperty("--ruler-border-color",r),e.verticalRuler.style.setProperty("--ruler-text-color",o),e.verticalRuler.style.setProperty("--ruler-tick-color",a)),e.cornerBox&&(e.cornerBox.style.setProperty("--ruler-background-color",n),e.cornerBox.style.setProperty("--ruler-border-color",r),e.cornerBox.style.setProperty("--ruler-text-color",o)),e.gridOverlay&&e.gridOverlay.style.setProperty("--grid-color",s)}function ue(e,t){if(!e?.container)return console.error("Invalid canvas provided to createRulers"),null;let n,r=null,o=!1;const a=()=>{!o&&n.horizontalRuler&&n.verticalRuler&&le(e,n.horizontalRuler,n.verticalRuler,n.gridOverlay,t)};try{return n=oe(e.container,t),r=function(e,t){const n=d(t),r=e.updateTransform;e.updateTransform=function(e){const t=r.call(this,e);return n(),t};const o=d(t);return window.addEventListener("resize",o),()=>{window.removeEventListener("resize",o),e.updateTransform=r,n.cleanup(),o.cleanup()}}(e,a),ce(n,t),a(),t.showRulers||(n.horizontalRuler.style.display="none",n.verticalRuler.style.display="none",n.cornerBox.style.display="none"),!t.showGrid&&n.gridOverlay&&(n.gridOverlay.style.display="none"),{horizontalRuler:n.horizontalRuler,verticalRuler:n.verticalRuler,cornerBox:n.cornerBox,gridOverlay:n.gridOverlay,update:a,updateTheme:e=>{o||ce(n,e)},show:()=>{n.horizontalRuler&&(n.horizontalRuler.style.display="block"),n.verticalRuler&&(n.verticalRuler.style.display="block"),n.cornerBox&&(n.cornerBox.style.display="flex")},hide:()=>{n.horizontalRuler&&(n.horizontalRuler.style.display="none"),n.verticalRuler&&(n.verticalRuler.style.display="none"),n.cornerBox&&(n.cornerBox.style.display="none"),n.gridOverlay&&(n.gridOverlay.style.display="none")},toggleGrid:()=>{if(n.gridOverlay){const e="none"!==n.gridOverlay.style.display;n.gridOverlay.style.display=e?"none":"block"}},destroy:()=>{o=!0,r&&r(),n.horizontalRuler?.parentNode&&n.horizontalRuler.parentNode.removeChild(n.horizontalRuler),n.verticalRuler?.parentNode&&n.verticalRuler.parentNode.removeChild(n.verticalRuler),n.cornerBox?.parentNode&&n.cornerBox.parentNode.removeChild(n.cornerBox),n.gridOverlay?.parentNode&&n.gridOverlay.parentNode.removeChild(n.gridOverlay)}}}catch(e){return console.error("Failed to create rulers:",e),null}}return class{constructor(e,t={}){if(this.cleanupCallbacks=[],this.rulers=null,this.dragSetup=null,this.keyboardCleanup=null,this.event=new P,this._isReady=!1,!e)throw new Error("Container element is required");this.config=M(t);const n=R(e,this.config);if(!n)throw new Error("Failed to create canvas");if(this.canvas=n,u(this.config,"enableRulers",()=>{this.rulers=ue(this,this.config),this.cleanupCallbacks.push(()=>{this.rulers&&this.rulers.destroy()})}),t.themeMode&&S(this.canvas.container,this.config,this.rulers,t.themeMode),this.event.setEmitInterceptor((e,t)=>{!function(e,t,n){if("undefined"==typeof window)return;let r=t;"ready"===e&&(r={ready:!0});const o=n.name||"markupCanvas";window.postMessage({source:"markup-canvas",action:e,data:r,timestamp:Date.now(),canvasName:o},"*"),window.parent&&window.parent.postMessage({source:"markup-canvas",action:e,data:r,timestamp:Date.now(),canvasName:o},"*")}(e,t,this.config)}),function(e,t){if("undefined"==typeof window)return;const n=t.name||"markupCanvas",r=window,o={config:{get current(){return e.config},get:e.getConfig.bind(e),update:e.updateConfig.bind(e)},transform:{update:e.updateTransform.bind(e),reset:e.reset.bind(e)},zoom:{get current(){return e.transform.scale||1},set:e.setZoom.bind(e),toPoint:e.zoomToPoint.bind(e),in:e.zoomIn.bind(e),out:e.zoomOut.bind(e),reset:e.resetZoom.bind(e),resetToCenter:e.resetViewToCenter.bind(e),fitToScreen:e.fitToScreen.bind(e)},pan:{left:e.panLeft.bind(e),right:e.panRight.bind(e),up:e.panUp.bind(e),down:e.panDown.bind(e),toPoint:e.panToPoint.bind(e),toCenter:e.centerContent.bind(e)},mouseDrag:{enable:e.enableMouseDrag.bind(e),disable:e.disableMouseDrag.bind(e),isEnabled:e.isMouseDragEnabled.bind(e)},keyboard:{enable:e.enableKeyboard.bind(e),disable:e.disableKeyboard.bind(e),isEnabled:e.isKeyboardEnabled.bind(e)},grid:{toggle:e.toggleGrid.bind(e),show:e.showGrid.bind(e),hide:e.hideGrid.bind(e),isVisible:e.isGridVisible.bind(e)},rulers:{toggle:e.toggleRulers.bind(e),show:e.showRulers.bind(e),hide:e.hideRulers.bind(e),isVisible:e.areRulersVisible.bind(e)},canvas:{canvasToContent:e.canvasToContent.bind(e),getVisibleArea:e.getVisibleArea.bind(e),isPointVisible:e.isPointVisible.bind(e),getBounds:e.getBounds.bind(e)},theme:{get current(){return e.config.themeMode},update:e.updateThemeMode.bind(e),toggle:e.toggleThemeMode.bind(e)},transition:{get current(){return e.config.enableTransition},set:e.updateTransition.bind(e),toggle:e.toggleTransitionMode.bind(e)},event:e.event,lifecycle:{cleanup:e.cleanup.bind(e),destroy:e.destroy.bind(e)},state:{get isReady(){return e.isReady},get isTransforming(){return e.isTransforming},get visibleBounds(){return e.visibleBounds},get transform(){return e.transform}}};r[n]=o,r.__markupCanvasInstances||(r.__markupCanvasInstances=new Map),r.__markupCanvasInstances.set(n,o)}(this,this.config),this.config.enablePostMessageAPI){const e=function(e){const t=t=>{const n=t.data;if(!["markup-canvas","application"].includes(n.source))return;const r=e.config.name||"markupCanvas";if(n.canvasName!==r)return;const o=n.action,a=n.data;V(e,o,a,r)};return"undefined"!=typeof window&&window.addEventListener("message",t),()=>{"undefined"!=typeof window&&window.removeEventListener("message",t)}}(this);this.cleanupCallbacks.push(e)}this.setupEventHandlers(),this._isReady=!0,this.event.emit("ready",this)}setupEventHandlers(){try{u(this.config,"enableZoom",()=>{const e=q(this,this.config);this.cleanupCallbacks.push(e)}),(this.config.enablePan||this.config.enableClickToZoom)&&(this.dragSetup=O(this,this.config,!0),this.cleanupCallbacks.push(this.dragSetup.cleanup)),u(this.config,"enableKeyboard",()=>{const e=I(this,this.config);this.keyboardCleanup=e,this.cleanupCallbacks.push(e)}),u(this.config,"enableTouch",()=>{const e=H(this);this.cleanupCallbacks.push(e)})}catch(e){throw console.error("Failed to set up event handlers:",e),this.cleanup(),e}}get container(){return this.canvas.container}get transformLayer(){return this.canvas.transformLayer}get contentLayer(){return this.canvas.contentLayer}get transform(){return this.canvas.transform}get isReady(){return this._isReady}get isTransforming(){return this.dragSetup?.isEnabled()||!1}get visibleBounds(){return i(this)}getBounds(){return f(this.canvas,this.config)}updateTransform(e){const t=C(this.canvas,e);return t&&E(this.event,this.canvas),t}reset(){const e=C(this.canvas,{scale:1,translateX:0,translateY:0});return e&&E(this.event,this.canvas),e}setZoom(e){return function(e,t,n,r,o){return y(t,n,()=>l(n,t=>{const n=t(o),a=D(e);return r(a.x,a.y,n)}))}(this,this.transformLayer,this.config,this.zoomToPoint.bind(this),e)}canvasToContent(t,r){return e(t,r,n(this.canvas.transform.scale,this.canvas.transform.translateX,this.canvas.transform.translateY))}zoomToPoint(e,t,n){const r=function(e,t,n,r,o,a){return y(t,n,()=>{const t=s(r,o,e.transform,a/e.transform.scale,n);return C(e,t)})}(this.canvas,this.transformLayer,this.config,e,t,n);return r&&E(this.event,this.canvas),r}resetView(){return e=this.canvas,t=this.transformLayer,n=this.config,y(t,n,()=>h(e,n.rulerSize,t=>C(e,{scale:1,translateX:-1*t,translateY:-1*t})));var e,t,n}resetViewToCenter(){return function(e,t,n,r){return y(t,n,()=>l(n,t=>{const n=t(1),o=D(e);return r(o.x,o.y,n)}))}(this,this.transformLayer,this.config,this.zoomToPoint.bind(this))}panLeft(e){return w(this.canvas,this.config,this.updateTransform.bind(this))||!!e&&w(this.canvas,{...this.config,keyboardPanStep:e},this.updateTransform.bind(this))}panRight(e){return k(this.canvas,this.config,this.updateTransform.bind(this))||!!e&&k(this.canvas,{...this.config,keyboardPanStep:e},this.updateTransform.bind(this))}panUp(e){return x(this.canvas,this.config,this.updateTransform.bind(this))||!!e&&x(this.canvas,{...this.config,keyboardPanStep:e},this.updateTransform.bind(this))}panDown(e){return v(this.canvas,this.config,this.updateTransform.bind(this))||!!e&&v(this.canvas,{...this.config,keyboardPanStep:e},this.updateTransform.bind(this))}zoomIn(e=.5){return function(e,t,n,r,o=.5){return y(t,n,()=>l(n,t=>{const n=t(e.transform.scale*(1+o)),a=D(e);return r(a.x,a.y,n)}))}(this,this.transformLayer,this.config,this.zoomToPoint.bind(this),e)}zoomOut(e=.5){return function(e,t,n,r,o=.5){return y(t,n,()=>l(n,t=>{const n=t(e.transform.scale*(1-o)),a=D(e);return r(a.x,a.y,n)}))}(this,this.transformLayer,this.config,this.zoomToPoint.bind(this),e)}resetZoom(){return this.resetViewToCenter()}enableMouseDrag(){return this.dragSetup?.enable()??!1}disableMouseDrag(){return this.dragSetup?.disable()??!1}isMouseDragEnabled(){return this.dragSetup?.isEnabled()??!1}enableKeyboard(){return this.keyboardCleanup||(this.keyboardCleanup=I(this,this.config),this.cleanupCallbacks.push(this.keyboardCleanup)),!0}disableKeyboard(){return!!this.keyboardCleanup&&(this.keyboardCleanup(),this.keyboardCleanup=null,!0)}isKeyboardEnabled(){return null!==this.keyboardCleanup}toggleGrid(){const e=(t=this.rulers,!!t?.toggleGrid&&(t.toggleGrid(),!0));var t;return e&&this.event.emit("gridVisibility",this.isGridVisible()),e}showGrid(){const e=(t=this.rulers,!!t?.gridOverlay&&(t.gridOverlay.style.display="block",!0));var t;return e&&this.event.emit("gridVisibility",!0),e}hideGrid(){const e=(t=this.rulers,!!t?.gridOverlay&&(t.gridOverlay.style.display="none",!0));var t;return e&&this.event.emit("gridVisibility",!1),e}isGridVisible(){return e=this.rulers,!!e?.gridOverlay&&"none"!==e.gridOverlay.style.display;var e}toggleRulers(){const e=function(e,t){if(e)return t()?e.hide():e.show(),!0;return!1}(this.rulers,()=>this.areRulersVisible());return e&&this.event.emit("rulersVisibility",this.areRulersVisible()),e}showRulers(){const e=!!(t=this.rulers)&&(t.show(),!0);var t;return e&&this.event.emit("rulersVisibility",!0),e}hideRulers(){const e=!!(t=this.rulers)&&(t.hide(),!0);var t;return e&&this.event.emit("rulersVisibility",!1),e}areRulersVisible(){return e=this.rulers,!!e?.horizontalRuler&&"none"!==e.horizontalRuler.style.display;var e}centerContent(){return e=this.canvas,t=this.config,n=this.updateTransform.bind(this),y(this.transformLayer,t,()=>{const r=f(e,t),o=(r.width-r.contentWidth*e.transform.scale)/2,a=(r.height-r.contentHeight*e.transform.scale)/2;return n({translateX:o,translateY:a})});var e,t,n}fitToScreen(){return e=this.canvas,t=this.transformLayer,n=this.config,y(t,n,()=>{const t=f(e,n),r=t.width/n.width,o=t.height/n.height,a=l(n,e=>e(.9*Math.min(r,o))),s=n.width*a,i=n.height*a,c=(t.width-s)/2,u=(t.height-i)/2;return C(e,{scale:a,translateX:c,translateY:u})});var e,t,n}getVisibleArea(){return i(this)}isPointVisible(e,t){return function(e,t,n){const r=i(e);return t>=r.x&&t<=r.x+r.width&&n>=r.y&&n<=r.y+r.height}(this,e,t)}panToPoint(e,t){return function(e,t,n,r,o,a){return y(a,t,()=>{const a=f(e,t),s=a.width/2,i=a.height/2,l=s-n*e.transform.scale,c=i-r*e.transform.scale;return o({translateX:l,translateY:c})})}(this.canvas,this.config,e,t,this.updateTransform.bind(this),this.transformLayer)}getConfig(){return{...this.config}}updateConfig(e){this.config=M({...this.config,...e})}updateThemeMode(e){this.config=M({...this.config,themeMode:e}),S(this.canvas.container,this.config,this.rulers,e)}toggleThemeMode(){const e="light"===this.config.themeMode?"dark":"light";return this.updateThemeMode(e),e}updateTransition(e){this.config=M({...this.config,enableTransition:e})}toggleTransitionMode(){const e=function(e){return!e}(this.config.enableTransition);return this.updateTransition(e),e}cleanup(){!function(e){if("undefined"==typeof window)return;const t=e.name||"markupCanvas",n=window;delete n[t],n.__markupCanvasInstances&&n.__markupCanvasInstances.delete(t)}(this.config),this.cleanupCallbacks.forEach(e=>{try{e()}catch(e){console.warn("Error during cleanup:",e)}}),this.cleanupCallbacks=[],this.removeAllListeners()}on(e,t){this.event.on(e,t)}off(e,t){this.event.off(e,t)}emit(e,t){this.event.emit(e,t)}removeAllListeners(){this.event.removeAllListeners()}destroy(){this.cleanup(),window.__markupCanvasTransitionTimeout&&clearTimeout(window.__markupCanvasTransitionTimeout)}}});
|
|
1
|
+
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).MarkupCanvas=t()}(this,function(){"use strict";function e(e,t,n){if(!n?.inverse)return{x:e,y:t};try{const r=n.inverse(),o=new DOMPoint(e,t).matrixTransform(r);return{x:o.x,y:o.y}}catch(n){return console.warn("Canvas to content conversion failed:",n),{x:e,y:t}}}function t(e,t){return Math.max(t.minZoom,Math.min(t.maxZoom,e))}function n(e,t,n){return new DOMMatrix([e,0,0,e,t,n])}const r="canvas-container",o="transform-layer",a="content-layer";function i(e,n,r,o,a){const i=a.enableRulers?-a.rulerSize:0,s=r||{scale:1,translateX:i,translateY:i},{scale:l,translateX:c,translateY:u}=s,d=t(l*o,a);if(Math.abs(d-l)<.001)return{scale:l,translateX:c,translateY:u};return{scale:d,translateX:e-(e-c)/l*d,translateY:n-(n-u)/l*d}}function s(e){return e.getBounds().visibleArea}function l(e,n){return n(n=>t(n,e))}const c=new Map;function u(e,t,n){return e[t]?n():null}function d(e){let t=null,n=null;const r=(...r)=>{n=r,null===t&&(t=requestAnimationFrame(()=>{n&&e(...n),t=null,n=null}))};return r.cleanup=()=>{null!==t&&(cancelAnimationFrame(t),t=null,n=null)},r}function h(e,t,n){return n(null!==e.container.querySelector(".canvas-ruler")?t:0)}function g(e,t,n,r,o){const a=null!==e.container.querySelector(".canvas-ruler");return o(a?t-r:t,a?n-r:n)}function m(e,t){if("dark"===e.themeMode){return e[`${t}Dark`]}return e[t]}const p={width:8e3,height:8e3,enableAcceleration:!0,initialZoom:1,initialPan:{x:0,y:0},name:"markupCanvas",enablePostMessageAPI:!1,enableZoom:!0,enablePan:!0,enableTouch:!0,enableKeyboard:!0,bindKeyboardEventsTo:"document",zoomSpeed:1.5,minZoom:.05,maxZoom:80,enableTransition:!0,transitionDuration:.2,enableAdaptiveSpeed:!0,enableLeftDrag:!0,enableMiddleDrag:!0,requireSpaceForMouseDrag:!1,keyboardPanStep:50,keyboardFastMultiplier:20,keyboardZoomStep:.2,enableClickToZoom:!0,clickZoomLevel:1,requireOptionForClickZoom:!1,enableRulers:!0,enableGrid:!1,showRulers:!0,showGrid:!1,rulerFontSize:9,rulerFontFamily:"Monaco, Menlo, monospace",rulerUnits:"px",rulerSize:20,canvasBackgroundColor:"rgba(250, 250, 250, 1)",canvasBackgroundColorDark:"rgba(40, 40, 40, 1)",rulerBackgroundColor:"rgba(255, 255, 255, 0.95)",rulerBorderColor:"rgba(240, 240, 240, 1)",rulerTextColor:"rgba(102, 102, 102, 1)",rulerTickColor:"rgba(204, 204, 204, 1)",gridColor:"rgba(232, 86, 193, 0.5)",rulerBackgroundColorDark:"rgba(30, 30, 30, 0.95)",rulerBorderColorDark:"rgba(68, 68, 68, 1)",rulerTextColorDark:"rgba(170, 170, 170, 1)",rulerTickColorDark:"rgba(104, 104, 104, 1)",gridColorDark:"rgba(232, 86, 193, 0.5)",themeMode:"light"};function f(t,r){try{const o=t.container,a=t.transform||{scale:1,translateX:0,translateY:0},i=o.getBoundingClientRect(),s=i.width||o.clientWidth||0,l=i.height||o.clientHeight||0,c=h({container:o},r.rulerSize,e=>Math.max(0,s-e)),u=h({container:o},r.rulerSize,e=>Math.max(0,l-e)),d=r.width||p.width,g=r.height||p.height,m=function(t,r,o,a,i){const s=e(0,0,n(i.scale,i.translateX,i.translateY)),l=e(t,r,n(i.scale,i.translateX,i.translateY));return{x:Math.max(0,Math.min(o,s.x)),y:Math.max(0,Math.min(a,s.y)),width:Math.max(0,Math.min(o-s.x,l.x-s.x)),height:Math.max(0,Math.min(a-s.y,l.y-s.y))}}(c,u,d,g,a);return{width:c,height:u,contentWidth:d,contentHeight:g,scale:a.scale,translateX:a.translateX,translateY:a.translateY,visibleArea:m,scaledContentWidth:d*a.scale,scaledContentHeight:g*a.scale,canPanLeft:a.translateX<0,canPanRight:a.translateX+d*a.scale>c,canPanUp:a.translateY<0,canPanDown:a.translateY+g*a.scale>u,canZoomIn:a.scale<3.5,canZoomOut:a.scale>.1}}catch(e){return console.error("Failed to calculate canvas bounds:",e),{width:0,height:0,contentWidth:0,contentHeight:0,scale:1,translateX:0,translateY:0,visibleArea:{x:0,y:0,width:0,height:0},scaledContentWidth:0,scaledContentHeight:0,canPanLeft:!1,canPanRight:!1,canPanUp:!1,canPanDown:!1,canZoomIn:!1,canZoomOut:!1}}}function b(e,t){try{if(t.enableTransition){window.__markupCanvasTransitionTimeout&&(clearTimeout(window.__markupCanvasTransitionTimeout),window.__markupCanvasTransitionTimeout=void 0);return function(e,t,n){const r=c.get(e);r&&clearTimeout(r);const o=window.setTimeout(()=>{n(),c.delete(e)},t);c.set(e,o)}("disableTransition",1e3*(t.transitionDuration??.2),()=>{e.style.transition="none",window.__markupCanvasTransitionTimeout=void 0}),!0}return!1}catch(e){return console.error("Failed to disable transitions:",e),!0}}function y(e,t,n){!function(e,t){try{return!!t.enableTransition&&(window.__markupCanvasTransitionTimeout&&(clearTimeout(window.__markupCanvasTransitionTimeout),window.__markupCanvasTransitionTimeout=void 0),e.style.transition=`transform ${t.transitionDuration}s linear`,!0)}catch(e){return console.error("Failed to enable transitions:",e),!1}}(e,t);try{return n()}finally{b(e,t)}}function v(e,t,n){const r=t.keyboardPanStep;return n({translateY:e.transform.translateY-r})}function k(e,t,n){const r=t.keyboardPanStep;return n({translateX:e.transform.translateX+r})}function w(e,t,n){const r=t.keyboardPanStep;return n({translateX:e.transform.translateX-r})}function x(e,t,n){const r=t.keyboardPanStep;return n({translateY:e.transform.translateY+r})}function T(e,t){if(!e?.style||!t)return!1;try{return e.style.transform=function(e){return`matrix3d(${e.m11}, ${e.m12}, ${e.m13}, ${e.m14}, ${e.m21}, ${e.m22}, ${e.m23}, ${e.m24}, ${e.m31}, ${e.m32}, ${e.m33}, ${e.m34}, ${e.m41}, ${e.m42}, ${e.m43}, ${e.m44})`}(t),!0}catch(e){return console.warn("Transform application failed:",e),!1}}function C(e,t){e.transform={...e.transform,...t};const r=n(e.transform.scale,e.transform.translateX,e.transform.translateY);return T(e.transformLayer,r)}function M(e={}){const t={...p,...e};return("number"!=typeof t.width||t.width<=0)&&(console.warn("Invalid width, using default"),t.width=p.width),("number"!=typeof t.height||t.height<=0)&&(console.warn("Invalid height, using default"),t.height=p.height),("number"!=typeof t.zoomSpeed||t.zoomSpeed<=0)&&(console.warn("Invalid zoomSpeed, using default"),t.zoomSpeed=p.zoomSpeed),("number"!=typeof t.minZoom||t.minZoom<=0)&&(console.warn("Invalid minZoom, using default"),t.minZoom=p.minZoom),("number"!=typeof t.maxZoom||t.maxZoom<=t.minZoom)&&(console.warn("Invalid maxZoom, using default"),t.maxZoom=p.maxZoom),("number"!=typeof t.keyboardPanStep||t.keyboardPanStep<=0)&&(console.warn("Invalid keyboardPanStep, using default"),t.keyboardPanStep=p.keyboardPanStep),("number"!=typeof t.keyboardFastMultiplier||t.keyboardFastMultiplier<=0)&&(console.warn("Invalid keyboardFastMultiplier, using default"),t.keyboardFastMultiplier=p.keyboardFastMultiplier),("number"!=typeof t.clickZoomLevel||t.clickZoomLevel<=0)&&(console.warn("Invalid clickZoomLevel, using default"),t.clickZoomLevel=p.clickZoomLevel),("number"!=typeof t.rulerFontSize||t.rulerFontSize<=0)&&(console.warn("Invalid rulerFontSize, using default"),t.rulerFontSize=p.rulerFontSize),("number"!=typeof t.rulerSize||t.rulerSize<=0)&&(console.warn("Invalid rulerSize, using default"),t.rulerSize=p.rulerSize),t}function S(e,t,n,r){const o=M({...t,themeMode:r}),a=m(o,"canvasBackgroundColor");e.style.backgroundColor=a,n&&n.updateTheme(o)}function D(e){try{const t=e.getBounds();return{x:t.width/2,y:t.height/2}}catch(e){return console.warn("Failed to calculate viewport center:",e),{x:0,y:0}}}function E(e,t){const n=Array.from(e.children);let r=e.querySelector(`.${o}`);r||(r=document.createElement("div"),r.className=o,e.appendChild(r)),function(e,t){e.style.position="absolute";const n=t.rulerSize;e.style.top=`${n}px`,e.style.left=`${n}px`,e.style.width=`${t.width}px`,e.style.height=`${t.height}px`,e.style.transformOrigin="0 0"}(r,t);let i=r.querySelector(`.${a}`);return i||(i=document.createElement("div"),i.className=a,r.appendChild(i),function(e,t,n){e.forEach(e=>{e===n||e.classList.contains(o)||t.appendChild(e)})}(n,i,r)),function(e){e.style.position="relative",e.style.width="100%",e.style.height="100%",e.style.pointerEvents="auto"}(i),{transformLayer:r,contentLayer:i}}function z(e,t){if("static"===getComputedStyle(e).position&&(e.style.position="relative"),e.style.overflow="hidden",e.style.cursor="grab",e.style.overscrollBehavior="none",t){const n=m(t,"canvasBackgroundColor");e.style.backgroundColor=n}e.hasAttribute("tabindex")||e.setAttribute("tabindex","0"),function(e){const t=e.getBoundingClientRect(),n=getComputedStyle(e);0===t.height&&"auto"===n.height&&console.error("MarkupCanvas: Container height is 0. Please set a height on your container element using CSS.","Examples: height: 100vh, height: 500px, or use flexbox/grid layout.",e),0===t.width&&"auto"===n.width&&console.error("MarkupCanvas: Container width is 0. Please set a width on your container element using CSS.","Examples: width: 100vw, width: 800px, or use flexbox/grid layout.",e)}(e),e.classList.contains(r)||e.classList.add(r)}function L(e,t){if(!e?.appendChild)return console.error("Invalid container element provided to createCanvas"),null;try{z(e,t);const{transformLayer:r,contentLayer:o}=E(e,t);u(t,"enableAcceleration",()=>{!function(e){try{return e.style.transform=e.style.transform||"translateZ(0)",e.style.backfaceVisibility="hidden",!0}catch(e){return console.error("Failed to enable hardware acceleration:",e),!1}}(r)});const a=t.enableRulers?-t.rulerSize:0,i={scale:t.initialZoom??1,translateX:(t.initialPan?.x??0)+a,translateY:(t.initialPan?.y??0)+a},s=n(i.scale,i.translateX,i.translateY);T(r,s);return{container:e,transformLayer:r,contentLayer:o,transform:i}}catch(e){return console.error("Failed to create canvas:",e),null}}class R{constructor(){this.listeners=new Map}setEmitInterceptor(e){this.emitInterceptor=e}on(e,t){this.listeners.has(e)||this.listeners.set(e,new Set),this.listeners.get(e).add(t)}off(e,t){const n=this.listeners.get(e);n&&n.delete(t)}emit(e,t){this.emitInterceptor?.(e,t);const n=this.listeners.get(e);n&&n.forEach(n=>{try{n(t)}catch(t){console.error(`Error in event handler for "${String(e)}":`,t)}})}removeAllListeners(){this.listeners.clear()}}function P(e,t){const n=t.transform;e.emit("transform",n),e.emit("zoom",n.scale),e.emit("pan",{x:n.translateX,y:n.translateY})}const Y=300,X=5;function $(e,t){if(!e?.getBounds)return t;try{const n=e.getBounds(),r=n.width*n.height;return t*(r/2073600)**1}catch(e){return console.warn("Failed to calculate adaptive zoom speed, using base speed:",e),t}}function I(e,t,n){const r=n?.textEditModeEnabled??!1;function o(n){if(!(n instanceof KeyboardEvent))return;if("canvas"===t.bindKeyboardEventsTo&&document.activeElement!==e.container)return;let o=!1;const a={};switch(n.key){case"ArrowLeft":if(r)return;a.translateX=e.transform.translateX+t.keyboardPanStep,o=!0;break;case"ArrowRight":if(r)return;a.translateX=e.transform.translateX-t.keyboardPanStep,o=!0;break;case"ArrowUp":if(r)return;a.translateY=e.transform.translateY+t.keyboardPanStep,o=!0;break;case"ArrowDown":if(r)return;a.translateY=e.transform.translateY-t.keyboardPanStep,o=!0;break;case"=":case"+":if(r)return;{const n=t.enableAdaptiveSpeed?$(e,t.keyboardZoomStep):t.keyboardZoomStep;e.zoomIn(n),o=!0}break;case"-":if(r)return;{const n=t.enableAdaptiveSpeed?$(e,t.keyboardZoomStep):t.keyboardZoomStep;e.zoomOut(n),o=!0}break;case"0":n.ctrlKey?(e.resetView&&e.resetView(),o=!0):(n.metaKey||n.ctrlKey)&&(e.resetViewToCenter&&e.resetViewToCenter(),o=!0);break;case"g":case"G":n.shiftKey&&e.toggleGrid&&e.toggleGrid(),o=n.shiftKey;break;case"r":case"R":!n.shiftKey||n.metaKey||n.ctrlKey||n.altKey||!e.toggleRulers||(e.toggleRulers(),o=!0)}o&&(n.preventDefault(),Object.keys(a).length>0&&e.updateTransform(a))}const a="canvas"===t.bindKeyboardEventsTo?e.container:document;return a.addEventListener("keydown",o),()=>{a.removeEventListener("keydown",o)}}function B(e,t,n,r,o){n?t.requireSpaceForMouseDrag?e.container.style.cursor=r?"grab":"default":e.container.style.cursor=o?"grabbing":"grab":e.container.style.cursor="default"}function Z(e,t,n,r,o){o.setIsDragging(!1),o.setDragButton(-1),B(e,t,n,r,!1)}function F(e,t,n,r,o,a,i,s,l,c){a&&e.button===i&&Z(t,n,r,o,{setIsDragging:c.setIsDragging,setDragButton:c.setDragButton}),r&&0===e.button&&n.enableClickToZoom&&s>0&&function(e,t,n,r,o,a){const i=Date.now()-r,s=e.altKey,l=!n.requireOptionForClickZoom||s;if(i<Y&&!o&&!a&&l){e.preventDefault();const r=t.container.getBoundingClientRect(),o=e.clientX-r.left,a=e.clientY-r.top,{clickX:i,clickY:s}=g(t,o,a,n.rulerSize,(e,t)=>({clickX:e,clickY:t})),l=t.canvasToContent(i,s),c=r.width/2,u=r.height/2,d=n.clickZoomLevel,h={scale:d,translateX:c-l.x*d,translateY:u-l.y*d};y(t.transformLayer,t.config,()=>{t.updateTransform(h)})}}(e,t,n,s,l,a),0===e.button&&function(e){e.setMouseDownTime(0),e.setHasDragged(!1)}({setMouseDownTime:c.setMouseDownTime,setHasDragged:c.setHasDragged})}function O(e,t,n=!0){let r=!0,o=!1,a=0,i=0,s=-1,l=!1,c=0,u=0,h=0,g=!1;const m={setIsDragging:e=>{o=e},setDragButton:e=>{s=e},setIsSpacePressed:e=>{l=e},setMouseDownTime:e=>{c=e},setMouseDownX:e=>{u=e},setMouseDownY:e=>{h=e},setHasDragged:e=>{g=e},setLastMouseX:e=>{a=e},setLastMouseY:e=>{i=e}},p=n=>{!function(e,t,n,r,o,a){n.requireSpaceForMouseDrag&&" "===e.key&&(a.setIsSpacePressed(!0),B(t,n,r,!0,o))}(n,e,t,r,o,{setIsSpacePressed:m.setIsSpacePressed})},f=n=>{!function(e,t,n,r,o,a){n.requireSpaceForMouseDrag&&" "===e.key&&(a.setIsSpacePressed(!1),B(t,n,r,!1,o),o&&Z(t,n,r,!1,{setIsDragging:a.setIsDragging,setDragButton:a.setDragButton}))}(n,e,t,r,o,{setIsSpacePressed:m.setIsSpacePressed,setIsDragging:m.setIsDragging,setDragButton:m.setDragButton})},b=n=>{!function(e,t,n,r,o,a){const i=0===e.button,s=1===e.button;if(i&&(a.setMouseDownTime(Date.now()),a.setMouseDownX(e.clientX),a.setMouseDownY(e.clientY),a.setHasDragged(!1)),!r)return;(!n.requireSpaceForMouseDrag||o)&&(i&&n.enableLeftDrag||s&&n.enableMiddleDrag)&&(e.preventDefault(),a.setDragButton(e.button),a.setLastMouseX(e.clientX),a.setLastMouseY(e.clientY),B(t,n,r,o,!1))}(n,e,t,r,l,m)},y=n=>{!function(e,t,n,r,o,a,i,s,l,c,u,h){if(i>0){const t=Math.abs(e.clientX-s),i=Math.abs(e.clientY-l);if(t>X||i>X){h.setHasDragged(!0);const e=!n.requireSpaceForMouseDrag||a;!o&&r&&e&&h.setIsDragging(!0)}}if(!o||!r)return;e.preventDefault(),d((...e)=>{const n=e[0];if(!o||!r)return;const a=n.clientX-c,i=n.clientY-u,s={translateX:t.transform.translateX+a,translateY:t.transform.translateY+i};t.updateTransform(s),h.setLastMouseX(n.clientX),h.setLastMouseY(n.clientY)})(e)}(n,e,t,r,o,l,c,u,h,a,i,{setHasDragged:m.setHasDragged,setIsDragging:m.setIsDragging,setLastMouseX:m.setLastMouseX,setLastMouseY:m.setLastMouseY})},v=n=>{F(n,e,t,r,l,o,s,c,g,{setIsDragging:m.setIsDragging,setDragButton:m.setDragButton,setMouseDownTime:m.setMouseDownTime,setHasDragged:m.setHasDragged})},k=()=>{!function(e,t,n,r,o,a){o&&Z(e,t,n,r,a)}(e,t,r,l,o,{setIsDragging:m.setIsDragging,setDragButton:m.setDragButton})};e.container.addEventListener("mousedown",b),document.addEventListener("mousemove",y),document.addEventListener("mouseup",v),e.container.addEventListener("mouseleave",k),t.requireSpaceForMouseDrag&&(document.addEventListener("keydown",p),document.addEventListener("keyup",f)),B(e,t,r,l,o);const w=()=>{e.container.removeEventListener("mousedown",b),document.removeEventListener("mousemove",y),document.removeEventListener("mouseup",v),e.container.removeEventListener("mouseleave",k),t.requireSpaceForMouseDrag&&(document.removeEventListener("keydown",p),document.removeEventListener("keyup",f))};return n?{cleanup:w,enable:()=>(r=!0,B(e,t,r,l,o),!0),disable:()=>(r=!1,o&&Z(e,t,r,l,{setIsDragging:m.setIsDragging,setDragButton:m.setDragButton}),B(e,t,r,l,o),!0),isEnabled:()=>r}:w}function V(e,t,n,r){try{switch(t){case"zoomIn":e.zoomIn(n);break;case"zoomOut":e.zoomOut(n);break;case"setZoom":{const t=n;if("number"!=typeof t||t<=0)throw new Error(`Invalid zoom level: ${t}. Must be a positive number.`);e.setZoom(t);break}case"resetZoom":e.resetZoom();break;case"panLeft":e.panLeft(n);break;case"panRight":e.panRight(n);break;case"panUp":e.panUp(n);break;case"panDown":e.panDown(n);break;case"fitToScreen":e.fitToScreen();break;case"centerContent":e.centerContent();break;case"panToPoint":{const t=n;e.panToPoint(t.x,t.y);break}case"resetView":e.resetView();break;case"resetViewToCenter":e.resetViewToCenter();break;case"toggleRulers":e.toggleRulers();break;case"showRulers":e.showRulers();break;case"hideRulers":e.hideRulers();break;case"toggleGrid":e.toggleGrid();break;case"showGrid":e.showGrid();break;case"hideGrid":e.hideGrid();break;case"updateThemeMode":{const t=n;if("light"!==t&&"dark"!==t)throw new Error(`Invalid theme mode: ${t}`);e.updateThemeMode(t);break}case"toggleThemeMode":{const t="light"===e.getConfig().themeMode?"dark":"light";e.updateThemeMode(t);break}case"updateTransition":{const t=n;if("boolean"!=typeof t)throw new Error(`Invalid transition enabled value: ${t}. Must be a boolean.`);e.updateTransition(t);break}case"toggleTransitionMode":e.toggleTransitionMode();break;default:throw new Error(`Unknown action: ${t}`)}}catch(e){!function(e,t,n){window.postMessage({source:"markup-canvas-error",canvasName:e,action:t,error:n,timestamp:Date.now()},"*")}(r,t,e instanceof Error?e.message:String(e))}}function A(e,t){return{x:(e.clientX+t.clientX)/2,y:(e.clientY+t.clientY)/2}}function _(e,t){const n=e.clientX-t.clientX,r=e.clientY-t.clientY;return Math.sqrt(n*n+r*r)}function G(e,t,n,r){const o=i(n,r,e.transform,t,e.config);return e.updateTransform(o)}function K(e,t,n){e.preventDefault();const r=Array.from(e.touches);d((...e)=>{const r=e[0];if(1===r.length){if(1===n.touches.length){const e=r[0].clientX-n.touches[0].clientX,o=r[0].clientY-n.touches[0].clientY,a={translateX:t.transform.translateX+e,translateY:t.transform.translateY+o};t.updateTransform(a)}}else if(2===r.length){const e=_(r[0],r[1]),o=A(r[0],r[1]);if(n.lastDistance>0){const r=e/n.lastDistance,a=t.container.getBoundingClientRect();let i=o.x-a.left,s=o.y-a.top;const l=function(e,t,n,r){return h(e,t,e=>{const t={...n,x:n.x-e,y:n.y-e};return r(t)})}(t,t.config.rulerSize,{x:i,y:s},e=>e);i=l.x,s=l.y,G(t,r,i,s)}n.lastDistance=e,n.lastCenter=o}n.touches=r})(r)}function H(e){const t={touches:[],lastDistance:0,lastCenter:{}},n=e=>{!function(e,t){e.preventDefault(),t.touches=Array.from(e.touches),2===t.touches.length&&(t.lastDistance=_(t.touches[0],t.touches[1]),t.lastCenter=A(t.touches[0],t.touches[1]))}(e,t)},r=n=>{K(n,e,t)},o=e=>{!function(e,t){t.touches=Array.from(e.touches),t.touches.length<2&&(t.lastDistance=0)}(e,t)};return e.container.addEventListener("touchstart",n,{passive:!1}),e.container.addEventListener("touchmove",r,{passive:!1}),e.container.addEventListener("touchend",o,{passive:!1}),()=>{e.container.removeEventListener("touchstart",n),e.container.removeEventListener("touchmove",r),e.container.removeEventListener("touchend",o)}}function N(e){const t=e.ctrlKey||e.metaKey,n=[0===e.deltaMode,Math.abs(e.deltaY)<50,e.deltaY%1!=0,Math.abs(e.deltaX)>0&&Math.abs(e.deltaY)>0].filter(Boolean).length>=2;return{isTrackpad:n,isMouseWheel:!n,isTrackpadScroll:n&&!t,isTrackpadPinch:n&&t,isZoomGesture:t}}function q(e,t){const n=(e=>d((...t)=>{const n=t[0];if(!n||!e?.updateTransform)return!1;try{const t=e.transform,r=1,o=n.deltaX*r,a=n.deltaY*r,i={scale:t.scale,translateX:t.translateX-o,translateY:t.translateY-a};return b(e.transformLayer,e.config),e.updateTransform(i)}catch(e){return console.error("Error handling trackpad pan:",e),!1}}))(e),r=r=>N(r).isTrackpadScroll?n(r):function(e,t,n){if(!e||"number"!=typeof e.deltaY)return console.warn("Invalid wheel event provided"),!1;if(!t?.updateTransform)return console.warn("Invalid canvas provided to handleWheelEvent"),!1;try{e.preventDefault();const r=t.container.getBoundingClientRect(),o=e.clientX-r.left,a=e.clientY-r.top,{mouseX:i,mouseY:s}=g(t,o,a,n.rulerSize,(e,t)=>({mouseX:e,mouseY:t})),l=n.zoomSpeed,c=N(e);if(!c.isZoomGesture)return!1;let u=n.enableAdaptiveSpeed?$(t,l):l;if(c.isTrackpadPinch){const e=.05*n.zoomSpeed;u=n.enableAdaptiveSpeed?$(t,e):e}return G(t,(e.deltaY<0?1:-1)>0?1+u:1/(1+u),i,s)}catch(e){return console.error("Error handling wheel event:",e),!1}}(r,e,t);return e.container.addEventListener("wheel",r,{passive:!1}),()=>{e.container.removeEventListener("wheel",r)}}const U=100,W=1e3,j=1001,J=4,Q=4,ee=100,te=100,ne=20,re=200;function oe(e,t){const n=function(e){const t=document.createElement("div");return t.className="canvas-ruler horizontal-ruler",t.style.cssText=`\n\tposition: absolute;\n\ttop: 0;\n\tleft: ${e.rulerSize}px;\n\tright: 0;\n\theight: ${e.rulerSize}px;\n\tbackground: var(--ruler-background-color);\n\tborder-bottom: 1px solid var(--ruler-border-color);\n\tz-index: ${W};\n\tpointer-events: none;\n\tfont-family: ${e.rulerFontFamily};\n\tfont-size: ${e.rulerFontSize}px;\n\tcolor: var(--ruler-text-color);\n\toverflow: hidden;\n `,t}(t),r=function(e){const t=document.createElement("div");return t.className="canvas-ruler vertical-ruler",t.style.cssText=`\n\tposition: absolute;\n\ttop: ${e.rulerSize}px;\n\tleft: 0;\n\tbottom: 0;\n\twidth: ${e.rulerSize}px;\n\tbackground: var(--ruler-background-color);\n\tborder-right: 1px solid var(--ruler-border-color);\n\tz-index: ${W};\n\tpointer-events: none;\n\tfont-family: ${e.rulerFontFamily};\n\tfont-size: ${e.rulerFontSize}px;\n\tcolor: var(--ruler-text-color);\n\toverflow: hidden;\n `,t}(t),o=function(e){const t=document.createElement("div");return t.className="canvas-ruler corner-box",t.style.cssText=`\n\t\tposition: absolute;\n\t\ttop: 0;\n\t\tleft: 0;\n\t\twidth: ${e.rulerSize}px;\n\t\theight: ${e.rulerSize}px;\n\t\tbackground: var(--ruler-background-color);\n\t\tborder-right: 1px solid var(--ruler-border-color);\n\t\tborder-bottom: 1px solid var(--ruler-border-color);\n\t\tz-index: ${j};\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t\tjustify-content: center;\n\t\tfont-family: ${e.rulerFontFamily};\n\t\tfont-size: ${e.rulerFontSize-2}px;\n\t\tcolor: var(--ruler-text-color);\n\t\tpointer-events: none;\n\t`,t.textContent=e.rulerUnits,t}(t),a=t.enableGrid?function(e){const t=document.createElement("div");return t.className="canvas-ruler grid-overlay",t.style.cssText=`\n\t\tposition: absolute;\n\t\ttop: ${e.rulerSize}px;\n\t\tleft: ${e.rulerSize}px;\n\t\tright: 0;\n\t\tbottom: 0;\n\t\tpointer-events: none;\n\t\tz-index: ${U};\n\t\tbackground-image: \n\t\t\tlinear-gradient(var(--grid-color) 1px, transparent 1px),\n\t\t\tlinear-gradient(90deg, var(--grid-color) 1px, transparent 1px);\n\t\tbackground-size: 100px 100px;\n\t\topacity: 0.5;\n\t`,t}(t):void 0;return e.appendChild(n),e.appendChild(r),e.appendChild(o),a&&e.appendChild(a),{horizontalRuler:n,verticalRuler:r,cornerBox:o,gridOverlay:a}}function ae(e,t){const n=e/Math.max(5,Math.min(20,t/50)),r=10**Math.floor(Math.log10(n)),o=n/r;let a;return a=o<=1?1:o<=2?2:o<=5?5:10,a*r}function ie(e,t,n,r,o){const a=document.createElement("div");a.className="tick",a.style.cssText=`\n\t\tposition: absolute;\n\t\tleft: ${n}px;\n\t\tbottom: 0;\n\t\twidth: 1px;\n\t\theight: ${J}px;\n\t\tbackground: var(--ruler-tick-color);\n\t`,e.appendChild(a);if(t%ee===0){const r=document.createElement("div");r.style.cssText=`\n\t\t\tposition: absolute;\n\t\t\tleft: ${n}px;\n\t\t\tbottom: ${J+2}px;\n\t\t\tfont-size: ${o.rulerFontSize}px;\n\t\t\tline-height: 1;\n\t\t\tcolor: var(--ruler-text-color);\n\t\t\twhite-space: nowrap;\n\t\t\tpointer-events: none;\n\t\t`,r.textContent=Math.round(t).toString(),e.appendChild(r)}}function se(e,t,n,r,o){const a=document.createElement("div");a.className="tick",a.style.cssText=`\n\t\tposition: absolute;\n\t\ttop: ${n}px;\n\t\tright: 0;\n\t\twidth: ${Q}px;\n\t\theight: 1px;\n\t\tbackground: var(--ruler-tick-color);\n\t`,e.appendChild(a);if(t%ee===0){const r=document.createElement("div");r.style.cssText=`\n\t\t\tposition: absolute;\n\t\t\ttop: ${n-6}px;\n\t\t\tright: ${Q+6}px;\n\t\t\tfont-size: ${o.rulerFontSize}px;\n\t\t\tline-height: 1;\n\t\t\tcolor: var(--ruler-text-color);\n\t\t\twhite-space: nowrap;\n\t\t\tpointer-events: none;\n\t\t\ttransform: rotate(-90deg);\n\t\t\ttransform-origin: right center;\n\t\t`,r.textContent=Math.round(t).toString(),e.appendChild(r)}}function le(e,t,n,r,o){const a=e.getBounds(),i=a.scale||1,s=a.translateX||0,l=a.translateY||0,c=a.width-o.rulerSize,u=a.height-o.rulerSize,d=-s/i,h=-l/i,g=h+u/i;!function(e,t,n,r,o,a){const i=r,s=ae(n-t,i),l=document.createDocumentFragment(),c=Math.floor(t/s)*s,u=Math.ceil(n/s)*s;for(let e=c;e<=u;e+=s){const n=(e-t)*o;n>=-50&&n<=i+50&&ie(l,e,n,0,a)}e.innerHTML="",e.appendChild(l)}(t,d,d+c/i,c,i,o),function(e,t,n,r,o,a){const i=r,s=ae(n-t,i),l=document.createDocumentFragment(),c=Math.floor(t/s)*s,u=Math.ceil(n/s)*s;for(let e=c;e<=u;e+=s){const n=(e-t)*o;n>=-50&&n<=i+50&&se(l,e,n,0,a)}e.innerHTML="",e.appendChild(l)}(n,h,g,u,i,o),r&&function(e,t,n,r){let o=te*t;for(;o<ne;)o*=2;for(;o>re;)o/=2;e.style.backgroundSize=`${o}px ${o}px`,e.style.backgroundPosition=`${n%o}px ${r%o}px`}(r,i,s,l)}function ce(e,t){const n=m(t,"rulerBackgroundColor"),r=m(t,"rulerBorderColor"),o=m(t,"rulerTextColor"),a=m(t,"rulerTickColor"),i=m(t,"gridColor");e.horizontalRuler&&(e.horizontalRuler.style.setProperty("--ruler-background-color",n),e.horizontalRuler.style.setProperty("--ruler-border-color",r),e.horizontalRuler.style.setProperty("--ruler-text-color",o),e.horizontalRuler.style.setProperty("--ruler-tick-color",a)),e.verticalRuler&&(e.verticalRuler.style.setProperty("--ruler-background-color",n),e.verticalRuler.style.setProperty("--ruler-border-color",r),e.verticalRuler.style.setProperty("--ruler-text-color",o),e.verticalRuler.style.setProperty("--ruler-tick-color",a)),e.cornerBox&&(e.cornerBox.style.setProperty("--ruler-background-color",n),e.cornerBox.style.setProperty("--ruler-border-color",r),e.cornerBox.style.setProperty("--ruler-text-color",o)),e.gridOverlay&&e.gridOverlay.style.setProperty("--grid-color",i)}function ue(e,t){if(!e?.container)return console.error("Invalid canvas provided to createRulers"),null;let n,r=null,o=!1;const a=()=>{!o&&n.horizontalRuler&&n.verticalRuler&&le(e,n.horizontalRuler,n.verticalRuler,n.gridOverlay,t)};try{return n=oe(e.container,t),r=function(e,t){const n=d(t),r=e.updateTransform;e.updateTransform=function(e){const t=r.call(this,e);return n(),t};const o=d(t);return window.addEventListener("resize",o),()=>{window.removeEventListener("resize",o),e.updateTransform=r,n.cleanup(),o.cleanup()}}(e,a),ce(n,t),a(),t.showRulers||(n.horizontalRuler.style.display="none",n.verticalRuler.style.display="none",n.cornerBox.style.display="none"),!t.showGrid&&n.gridOverlay&&(n.gridOverlay.style.display="none"),{horizontalRuler:n.horizontalRuler,verticalRuler:n.verticalRuler,cornerBox:n.cornerBox,gridOverlay:n.gridOverlay,update:a,updateTheme:e=>{o||ce(n,e)},show:()=>{n.horizontalRuler&&(n.horizontalRuler.style.display="block"),n.verticalRuler&&(n.verticalRuler.style.display="block"),n.cornerBox&&(n.cornerBox.style.display="flex")},hide:()=>{n.horizontalRuler&&(n.horizontalRuler.style.display="none"),n.verticalRuler&&(n.verticalRuler.style.display="none"),n.cornerBox&&(n.cornerBox.style.display="none"),n.gridOverlay&&(n.gridOverlay.style.display="none")},toggleGrid:()=>{if(n.gridOverlay){const e="none"!==n.gridOverlay.style.display;n.gridOverlay.style.display=e?"none":"block"}},destroy:()=>{o=!0,r&&r(),n.horizontalRuler?.parentNode&&n.horizontalRuler.parentNode.removeChild(n.horizontalRuler),n.verticalRuler?.parentNode&&n.verticalRuler.parentNode.removeChild(n.verticalRuler),n.cornerBox?.parentNode&&n.cornerBox.parentNode.removeChild(n.cornerBox),n.gridOverlay?.parentNode&&n.gridOverlay.parentNode.removeChild(n.gridOverlay)}}}catch(e){return console.error("Failed to create rulers:",e),null}}return class{constructor(e,t={}){if(this.cleanupCallbacks=[],this.rulers=null,this.dragSetup=null,this.keyboardCleanup=null,this.textEditModeEnabled=!1,this.event=new R,this._isReady=!1,!e)throw new Error("Container element is required");this.config=M(t);const n=L(e,this.config);if(!n)throw new Error("Failed to create canvas");if(this.canvas=n,u(this.config,"enableRulers",()=>{this.rulers=ue(this,this.config),this.cleanupCallbacks.push(()=>{this.rulers&&this.rulers.destroy()})}),t.themeMode&&S(this.canvas.container,this.config,this.rulers,t.themeMode),this.event.setEmitInterceptor((e,t)=>{!function(e,t,n){if("undefined"==typeof window)return;let r=t;"ready"===e&&(r={ready:!0});const o=n.name||"markupCanvas";window.postMessage({source:"markup-canvas",action:e,data:r,timestamp:Date.now(),canvasName:o},"*"),window.parent&&window.parent.postMessage({source:"markup-canvas",action:e,data:r,timestamp:Date.now(),canvasName:o},"*")}(e,t,this.config)}),function(e,t){if("undefined"==typeof window)return;const n=t.name||"markupCanvas",r=window,o={config:{get current(){return e.config},get:e.getConfig.bind(e),update:e.updateConfig.bind(e)},transform:{update:e.updateTransform.bind(e),reset:e.reset.bind(e)},zoom:{get current(){return e.transform.scale||1},set:e.setZoom.bind(e),toPoint:e.zoomToPoint.bind(e),in:e.zoomIn.bind(e),out:e.zoomOut.bind(e),reset:e.resetZoom.bind(e),resetToCenter:e.resetViewToCenter.bind(e),fitToScreen:e.fitToScreen.bind(e)},pan:{left:e.panLeft.bind(e),right:e.panRight.bind(e),up:e.panUp.bind(e),down:e.panDown.bind(e),toPoint:e.panToPoint.bind(e),toCenter:e.centerContent.bind(e)},mouseDrag:{enable:e.enableMouseDrag.bind(e),disable:e.disableMouseDrag.bind(e),isEnabled:e.isMouseDragEnabled.bind(e)},keyboard:{enable:e.enableKeyboard.bind(e),disable:e.disableKeyboard.bind(e),isEnabled:e.isKeyboardEnabled.bind(e),enableTextEditMode:e.enableTextEditMode.bind(e),disableTextEditMode:e.disableTextEditMode.bind(e),isTextEditModeEnabled:e.isTextEditModeEnabled.bind(e)},grid:{toggle:e.toggleGrid.bind(e),show:e.showGrid.bind(e),hide:e.hideGrid.bind(e),isVisible:e.isGridVisible.bind(e)},rulers:{toggle:e.toggleRulers.bind(e),show:e.showRulers.bind(e),hide:e.hideRulers.bind(e),isVisible:e.areRulersVisible.bind(e)},canvas:{canvasToContent:e.canvasToContent.bind(e),getVisibleArea:e.getVisibleArea.bind(e),isPointVisible:e.isPointVisible.bind(e),getBounds:e.getBounds.bind(e)},theme:{get current(){return e.config.themeMode},update:e.updateThemeMode.bind(e),toggle:e.toggleThemeMode.bind(e)},transition:{get current(){return e.config.enableTransition},set:e.updateTransition.bind(e),toggle:e.toggleTransitionMode.bind(e)},event:e.event,lifecycle:{cleanup:e.cleanup.bind(e),destroy:e.destroy.bind(e)},state:{get isReady(){return e.isReady},get isTransforming(){return e.isTransforming},get visibleBounds(){return e.visibleBounds},get transform(){return e.transform}}};r[n]=o,r.__markupCanvasInstances||(r.__markupCanvasInstances=new Map),r.__markupCanvasInstances.set(n,o)}(this,this.config),this.config.enablePostMessageAPI){const e=function(e){const t=t=>{const n=t.data;if(!["markup-canvas","application"].includes(n.source))return;const r=e.config.name||"markupCanvas";if(n.canvasName!==r)return;const o=n.action,a=n.data;V(e,o,a,r)};return"undefined"!=typeof window&&window.addEventListener("message",t),()=>{"undefined"!=typeof window&&window.removeEventListener("message",t)}}(this);this.cleanupCallbacks.push(e)}this.setupEventHandlers(),this._isReady=!0,this.event.emit("ready",this)}setupEventHandlers(){try{u(this.config,"enableZoom",()=>{const e=q(this,this.config);this.cleanupCallbacks.push(e)}),(this.config.enablePan||this.config.enableClickToZoom)&&(this.dragSetup=O(this,this.config,!0),this.cleanupCallbacks.push(this.dragSetup.cleanup)),u(this.config,"enableKeyboard",()=>{const e=I(this,this.config,{textEditModeEnabled:this.textEditModeEnabled});this.keyboardCleanup=e,this.cleanupCallbacks.push(e)}),u(this.config,"enableTouch",()=>{const e=H(this);this.cleanupCallbacks.push(e)})}catch(e){throw console.error("Failed to set up event handlers:",e),this.cleanup(),e}}get container(){return this.canvas.container}get transformLayer(){return this.canvas.transformLayer}get contentLayer(){return this.canvas.contentLayer}get transform(){return this.canvas.transform}get isReady(){return this._isReady}get isTransforming(){return this.dragSetup?.isEnabled()||!1}get visibleBounds(){return s(this)}getBounds(){return f(this.canvas,this.config)}updateTransform(e){const t=C(this.canvas,e);return t&&P(this.event,this.canvas),t}reset(){const e=C(this.canvas,{scale:1,translateX:0,translateY:0});return e&&P(this.event,this.canvas),e}setZoom(e){return function(e,t,n,r,o){return y(t,n,()=>l(n,t=>{const n=t(o),a=D(e);return r(a.x,a.y,n)}))}(this,this.transformLayer,this.config,this.zoomToPoint.bind(this),e)}canvasToContent(t,r){return e(t,r,n(this.canvas.transform.scale,this.canvas.transform.translateX,this.canvas.transform.translateY))}zoomToPoint(e,t,n){const r=function(e,t,n,r,o,a){return y(t,n,()=>{const t=i(r,o,e.transform,a/e.transform.scale,n);return C(e,t)})}(this.canvas,this.transformLayer,this.config,e,t,n);return r&&P(this.event,this.canvas),r}resetView(){return e=this.canvas,t=this.transformLayer,n=this.config,y(t,n,()=>h(e,n.rulerSize,t=>C(e,{scale:1,translateX:-1*t,translateY:-1*t})));var e,t,n}resetViewToCenter(){return function(e,t,n,r){return y(t,n,()=>l(n,t=>{const n=t(1),o=D(e);return r(o.x,o.y,n)}))}(this,this.transformLayer,this.config,this.zoomToPoint.bind(this))}panLeft(e){return k(this.canvas,this.config,this.updateTransform.bind(this))||!!e&&k(this.canvas,{...this.config,keyboardPanStep:e},this.updateTransform.bind(this))}panRight(e){return w(this.canvas,this.config,this.updateTransform.bind(this))||!!e&&w(this.canvas,{...this.config,keyboardPanStep:e},this.updateTransform.bind(this))}panUp(e){return x(this.canvas,this.config,this.updateTransform.bind(this))||!!e&&x(this.canvas,{...this.config,keyboardPanStep:e},this.updateTransform.bind(this))}panDown(e){return v(this.canvas,this.config,this.updateTransform.bind(this))||!!e&&v(this.canvas,{...this.config,keyboardPanStep:e},this.updateTransform.bind(this))}zoomIn(e=.5){return function(e,t,n,r,o=.5){return y(t,n,()=>l(n,t=>{const n=t(e.transform.scale*(1+o)),a=D(e);return r(a.x,a.y,n)}))}(this,this.transformLayer,this.config,this.zoomToPoint.bind(this),e)}zoomOut(e=.5){return function(e,t,n,r,o=.5){return y(t,n,()=>l(n,t=>{const n=t(e.transform.scale*(1-o)),a=D(e);return r(a.x,a.y,n)}))}(this,this.transformLayer,this.config,this.zoomToPoint.bind(this),e)}resetZoom(){return this.resetViewToCenter()}enableMouseDrag(){return this.dragSetup?.enable()??!1}disableMouseDrag(){return this.dragSetup?.disable()??!1}isMouseDragEnabled(){return this.dragSetup?.isEnabled()??!1}enableKeyboard(){return this.keyboardCleanup||(this.keyboardCleanup=I(this,this.config,{textEditModeEnabled:this.textEditModeEnabled}),this.cleanupCallbacks.push(this.keyboardCleanup)),!0}disableKeyboard(){return!!this.keyboardCleanup&&(this.keyboardCleanup(),this.keyboardCleanup=null,!0)}isKeyboardEnabled(){return null!==this.keyboardCleanup}enableTextEditMode(){if(this.textEditModeEnabled)return!0;if(this.textEditModeEnabled=!0,this.keyboardCleanup){const e=this.cleanupCallbacks.indexOf(this.keyboardCleanup);e>-1&&this.cleanupCallbacks.splice(e,1),this.keyboardCleanup(),this.keyboardCleanup=I(this,this.config,{textEditModeEnabled:!0}),this.cleanupCallbacks.push(this.keyboardCleanup)}return!0}disableTextEditMode(){if(!this.textEditModeEnabled)return!0;if(this.textEditModeEnabled=!1,this.keyboardCleanup){const e=this.cleanupCallbacks.indexOf(this.keyboardCleanup);e>-1&&this.cleanupCallbacks.splice(e,1),this.keyboardCleanup(),this.keyboardCleanup=I(this,this.config,{textEditModeEnabled:!1}),this.cleanupCallbacks.push(this.keyboardCleanup)}return!0}isTextEditModeEnabled(){return this.textEditModeEnabled}toggleGrid(){const e=(t=this.rulers,!!t?.toggleGrid&&(t.toggleGrid(),!0));var t;return e&&this.event.emit("gridVisibility",this.isGridVisible()),e}showGrid(){const e=(t=this.rulers,!!t?.gridOverlay&&(t.gridOverlay.style.display="block",!0));var t;return e&&this.event.emit("gridVisibility",!0),e}hideGrid(){const e=(t=this.rulers,!!t?.gridOverlay&&(t.gridOverlay.style.display="none",!0));var t;return e&&this.event.emit("gridVisibility",!1),e}isGridVisible(){return e=this.rulers,!!e?.gridOverlay&&"none"!==e.gridOverlay.style.display;var e}toggleRulers(){const e=function(e,t){if(e)return t()?e.hide():e.show(),!0;return!1}(this.rulers,()=>this.areRulersVisible());return e&&this.event.emit("rulersVisibility",this.areRulersVisible()),e}showRulers(){const e=!!(t=this.rulers)&&(t.show(),!0);var t;return e&&this.event.emit("rulersVisibility",!0),e}hideRulers(){const e=!!(t=this.rulers)&&(t.hide(),!0);var t;return e&&this.event.emit("rulersVisibility",!1),e}areRulersVisible(){return e=this.rulers,!!e?.horizontalRuler&&"none"!==e.horizontalRuler.style.display;var e}centerContent(){return e=this.canvas,t=this.config,n=this.updateTransform.bind(this),y(this.transformLayer,t,()=>{const r=f(e,t),o=(r.width-r.contentWidth*e.transform.scale)/2,a=(r.height-r.contentHeight*e.transform.scale)/2;return n({translateX:o,translateY:a})});var e,t,n}fitToScreen(){return e=this.canvas,t=this.transformLayer,n=this.config,y(t,n,()=>{const t=f(e,n),r=t.width/n.width,o=t.height/n.height,a=l(n,e=>e(.9*Math.min(r,o))),i=n.width*a,s=n.height*a,c=(t.width-i)/2,u=(t.height-s)/2;return C(e,{scale:a,translateX:c,translateY:u})});var e,t,n}getVisibleArea(){return s(this)}isPointVisible(e,t){return function(e,t,n){const r=s(e);return t>=r.x&&t<=r.x+r.width&&n>=r.y&&n<=r.y+r.height}(this,e,t)}panToPoint(e,t){return function(e,t,n,r,o,a){return y(a,t,()=>{const a=f(e,t),i=a.width/2,s=a.height/2,l=i-n*e.transform.scale,c=s-r*e.transform.scale;return o({translateX:l,translateY:c})})}(this.canvas,this.config,e,t,this.updateTransform.bind(this),this.transformLayer)}getConfig(){return{...this.config}}updateConfig(e){this.config=M({...this.config,...e})}updateThemeMode(e){this.config=M({...this.config,themeMode:e}),S(this.canvas.container,this.config,this.rulers,e)}toggleThemeMode(){const e="light"===this.config.themeMode?"dark":"light";return this.updateThemeMode(e),e}updateTransition(e){this.config=M({...this.config,enableTransition:e})}toggleTransitionMode(){const e=function(e){return!e}(this.config.enableTransition);return this.updateTransition(e),e}cleanup(){!function(e){if("undefined"==typeof window)return;const t=e.name||"markupCanvas",n=window;delete n[t],n.__markupCanvasInstances&&n.__markupCanvasInstances.delete(t)}(this.config),this.cleanupCallbacks.forEach(e=>{try{e()}catch(e){console.warn("Error during cleanup:",e)}}),this.cleanupCallbacks=[],this.removeAllListeners()}on(e,t){this.event.on(e,t)}off(e,t){this.event.off(e,t)}emit(e,t){this.event.emit(e,t)}removeAllListeners(){this.event.removeAllListeners()}destroy(){this.cleanup(),window.__markupCanvasTransitionTimeout&&clearTimeout(window.__markupCanvasTransitionTimeout)}}});
|
package/dist/types/window.d.ts
CHANGED
|
@@ -38,7 +38,10 @@ export interface WindowAPI {
|
|
|
38
38
|
keyboard: {
|
|
39
39
|
readonly enable: () => boolean;
|
|
40
40
|
readonly disable: () => boolean;
|
|
41
|
-
isEnabled: () => boolean;
|
|
41
|
+
readonly isEnabled: () => boolean;
|
|
42
|
+
readonly enableTextEditMode: () => boolean;
|
|
43
|
+
readonly disableTextEditMode: () => boolean;
|
|
44
|
+
readonly isTextEditModeEnabled: () => boolean;
|
|
42
45
|
};
|
|
43
46
|
grid: {
|
|
44
47
|
readonly toggle: () => void;
|
package/package.json
CHANGED
package/src/lib/MarkupCanvas.ts
CHANGED
|
@@ -31,6 +31,7 @@ export class MarkupCanvas {
|
|
|
31
31
|
private rulers: ReturnType<typeof createRulers> | null = null;
|
|
32
32
|
private dragSetup: MouseDragControls | null = null;
|
|
33
33
|
private keyboardCleanup: (() => void) | null = null;
|
|
34
|
+
private textEditModeEnabled = false;
|
|
34
35
|
public config: Required<MarkupCanvasConfig>;
|
|
35
36
|
public event = new EventEmitter<MarkupCanvasEvents>();
|
|
36
37
|
private _isReady = false;
|
|
@@ -99,7 +100,9 @@ export class MarkupCanvas {
|
|
|
99
100
|
|
|
100
101
|
// Keyboard events
|
|
101
102
|
withFeatureEnabled(this.config, "enableKeyboard", () => {
|
|
102
|
-
const keyboardCleanup = setupKeyboardEvents(this, this.config
|
|
103
|
+
const keyboardCleanup = setupKeyboardEvents(this, this.config, {
|
|
104
|
+
textEditModeEnabled: this.textEditModeEnabled,
|
|
105
|
+
});
|
|
103
106
|
this.keyboardCleanup = keyboardCleanup;
|
|
104
107
|
this.cleanupCallbacks.push(keyboardCleanup);
|
|
105
108
|
});
|
|
@@ -247,7 +250,9 @@ export class MarkupCanvas {
|
|
|
247
250
|
if (this.keyboardCleanup) {
|
|
248
251
|
return true; // Already enabled
|
|
249
252
|
}
|
|
250
|
-
this.keyboardCleanup = setupKeyboardEvents(this, this.config
|
|
253
|
+
this.keyboardCleanup = setupKeyboardEvents(this, this.config, {
|
|
254
|
+
textEditModeEnabled: this.textEditModeEnabled,
|
|
255
|
+
});
|
|
251
256
|
this.cleanupCallbacks.push(this.keyboardCleanup);
|
|
252
257
|
return true;
|
|
253
258
|
}
|
|
@@ -265,6 +270,61 @@ export class MarkupCanvas {
|
|
|
265
270
|
return this.keyboardCleanup !== null;
|
|
266
271
|
}
|
|
267
272
|
|
|
273
|
+
// Text edit mode control methods
|
|
274
|
+
enableTextEditMode(): boolean {
|
|
275
|
+
if (this.textEditModeEnabled) {
|
|
276
|
+
return true; // Already enabled
|
|
277
|
+
}
|
|
278
|
+
this.textEditModeEnabled = true;
|
|
279
|
+
|
|
280
|
+
// If keyboard is currently enabled, re-setup with new option
|
|
281
|
+
if (this.keyboardCleanup) {
|
|
282
|
+
// Remove old cleanup from callbacks
|
|
283
|
+
const index = this.cleanupCallbacks.indexOf(this.keyboardCleanup);
|
|
284
|
+
if (index > -1) {
|
|
285
|
+
this.cleanupCallbacks.splice(index, 1);
|
|
286
|
+
}
|
|
287
|
+
// Cleanup old handler
|
|
288
|
+
this.keyboardCleanup();
|
|
289
|
+
// Setup new handler with text edit mode enabled
|
|
290
|
+
this.keyboardCleanup = setupKeyboardEvents(this, this.config, {
|
|
291
|
+
textEditModeEnabled: true,
|
|
292
|
+
});
|
|
293
|
+
this.cleanupCallbacks.push(this.keyboardCleanup);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
return true;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
disableTextEditMode(): boolean {
|
|
300
|
+
if (!this.textEditModeEnabled) {
|
|
301
|
+
return true; // Already disabled
|
|
302
|
+
}
|
|
303
|
+
this.textEditModeEnabled = false;
|
|
304
|
+
|
|
305
|
+
// If keyboard is currently enabled, re-setup with new option
|
|
306
|
+
if (this.keyboardCleanup) {
|
|
307
|
+
// Remove old cleanup from callbacks
|
|
308
|
+
const index = this.cleanupCallbacks.indexOf(this.keyboardCleanup);
|
|
309
|
+
if (index > -1) {
|
|
310
|
+
this.cleanupCallbacks.splice(index, 1);
|
|
311
|
+
}
|
|
312
|
+
// Cleanup old handler
|
|
313
|
+
this.keyboardCleanup();
|
|
314
|
+
// Setup new handler with text edit mode disabled
|
|
315
|
+
this.keyboardCleanup = setupKeyboardEvents(this, this.config, {
|
|
316
|
+
textEditModeEnabled: false,
|
|
317
|
+
});
|
|
318
|
+
this.cleanupCallbacks.push(this.keyboardCleanup);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
return true;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
isTextEditModeEnabled(): boolean {
|
|
325
|
+
return this.textEditModeEnabled;
|
|
326
|
+
}
|
|
327
|
+
|
|
268
328
|
toggleGrid(): boolean {
|
|
269
329
|
const result = toggleGrid(this.rulers);
|
|
270
330
|
if (result) {
|
|
@@ -18,7 +18,7 @@ export const EDITOR_PRESET: MarkupCanvasConfig = {
|
|
|
18
18
|
bindKeyboardEventsTo: "document",
|
|
19
19
|
|
|
20
20
|
// Zoom behavior
|
|
21
|
-
zoomSpeed:
|
|
21
|
+
zoomSpeed: 4,
|
|
22
22
|
minZoom: 0.05,
|
|
23
23
|
maxZoom: 80,
|
|
24
24
|
enableTransition: false,
|
|
@@ -57,7 +57,7 @@ export const EDITOR_PRESET: MarkupCanvasConfig = {
|
|
|
57
57
|
|
|
58
58
|
// Ruler styling
|
|
59
59
|
rulerBackgroundColor: "oklch(100% 0 0 / 0.96)",
|
|
60
|
-
rulerBorderColor: "oklch(
|
|
60
|
+
rulerBorderColor: "oklch(0.322 0.0095 285.919)",
|
|
61
61
|
rulerTextColor: "oklch(70.5% 0.015 286.067)",
|
|
62
62
|
rulerTickColor: "oklch(92% 0.004 286.32)",
|
|
63
63
|
gridColor: "rgba(232, 86, 193, 0.5)",
|
|
@@ -2,7 +2,13 @@ import { getAdaptiveZoomSpeed } from "@/lib/events/utils/getAdaptiveZoomSpeed.js
|
|
|
2
2
|
import type { MarkupCanvas } from "@/lib/MarkupCanvas.js";
|
|
3
3
|
import type { MarkupCanvasConfig, Transform } from "@/types/index.js";
|
|
4
4
|
|
|
5
|
-
export function setupKeyboardEvents(
|
|
5
|
+
export function setupKeyboardEvents(
|
|
6
|
+
canvas: MarkupCanvas,
|
|
7
|
+
config: Required<MarkupCanvasConfig>,
|
|
8
|
+
options?: { textEditModeEnabled?: boolean }
|
|
9
|
+
): () => void {
|
|
10
|
+
const textEditModeEnabled = options?.textEditModeEnabled ?? false;
|
|
11
|
+
|
|
6
12
|
function handleKeyDown(event: Event): void {
|
|
7
13
|
if (!(event instanceof KeyboardEvent)) return;
|
|
8
14
|
|
|
@@ -13,23 +19,38 @@ export function setupKeyboardEvents(canvas: MarkupCanvas, config: Required<Marku
|
|
|
13
19
|
|
|
14
20
|
switch (event.key) {
|
|
15
21
|
case "ArrowLeft":
|
|
22
|
+
if (textEditModeEnabled) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
16
25
|
newTransform.translateX = canvas.transform.translateX + config.keyboardPanStep;
|
|
17
26
|
handled = true;
|
|
18
27
|
break;
|
|
19
28
|
case "ArrowRight":
|
|
29
|
+
if (textEditModeEnabled) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
20
32
|
newTransform.translateX = canvas.transform.translateX - config.keyboardPanStep;
|
|
21
33
|
handled = true;
|
|
22
34
|
break;
|
|
23
35
|
case "ArrowUp":
|
|
36
|
+
if (textEditModeEnabled) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
24
39
|
newTransform.translateY = canvas.transform.translateY + config.keyboardPanStep;
|
|
25
40
|
handled = true;
|
|
26
41
|
break;
|
|
27
42
|
case "ArrowDown":
|
|
43
|
+
if (textEditModeEnabled) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
28
46
|
newTransform.translateY = canvas.transform.translateY - config.keyboardPanStep;
|
|
29
47
|
handled = true;
|
|
30
48
|
break;
|
|
31
49
|
case "=":
|
|
32
50
|
case "+":
|
|
51
|
+
if (textEditModeEnabled) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
33
54
|
{
|
|
34
55
|
const adaptiveZoomStep = config.enableAdaptiveSpeed
|
|
35
56
|
? getAdaptiveZoomSpeed(canvas, config.keyboardZoomStep)
|
|
@@ -39,6 +60,9 @@ export function setupKeyboardEvents(canvas: MarkupCanvas, config: Required<Marku
|
|
|
39
60
|
}
|
|
40
61
|
break;
|
|
41
62
|
case "-":
|
|
63
|
+
if (textEditModeEnabled) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
42
66
|
{
|
|
43
67
|
const adaptiveZoomStep = config.enableAdaptiveSpeed
|
|
44
68
|
? getAdaptiveZoomSpeed(canvas, config.keyboardZoomStep)
|
|
@@ -13,7 +13,6 @@ export function createHorizontalRuler(config: Required<MarkupCanvasConfig>): HTM
|
|
|
13
13
|
height: ${config.rulerSize}px;
|
|
14
14
|
background: var(--ruler-background-color);
|
|
15
15
|
border-bottom: 1px solid var(--ruler-border-color);
|
|
16
|
-
border-right: 1px solid var(--ruler-border-color);
|
|
17
16
|
z-index: ${RULER_Z_INDEX.RULERS};
|
|
18
17
|
pointer-events: none;
|
|
19
18
|
font-family: ${config.rulerFontFamily};
|
|
@@ -13,7 +13,6 @@ export function createVerticalRuler(config: Required<MarkupCanvasConfig>): HTMLE
|
|
|
13
13
|
width: ${config.rulerSize}px;
|
|
14
14
|
background: var(--ruler-background-color);
|
|
15
15
|
border-right: 1px solid var(--ruler-border-color);
|
|
16
|
-
border-bottom: 1px solid var(--ruler-border-color);
|
|
17
16
|
z-index: ${RULER_Z_INDEX.RULERS};
|
|
18
17
|
pointer-events: none;
|
|
19
18
|
font-family: ${config.rulerFontFamily};
|
|
@@ -59,6 +59,9 @@ export function bindCanvasToWindow(canvas: MarkupCanvas, config: Required<Markup
|
|
|
59
59
|
enable: canvas.enableKeyboard.bind(canvas),
|
|
60
60
|
disable: canvas.disableKeyboard.bind(canvas),
|
|
61
61
|
isEnabled: canvas.isKeyboardEnabled.bind(canvas),
|
|
62
|
+
enableTextEditMode: canvas.enableTextEditMode.bind(canvas),
|
|
63
|
+
disableTextEditMode: canvas.disableTextEditMode.bind(canvas),
|
|
64
|
+
isTextEditModeEnabled: canvas.isTextEditModeEnabled.bind(canvas),
|
|
62
65
|
},
|
|
63
66
|
|
|
64
67
|
// Grid group
|
package/src/types/window.ts
CHANGED
|
@@ -39,7 +39,10 @@ export interface WindowAPI {
|
|
|
39
39
|
keyboard: {
|
|
40
40
|
readonly enable: () => boolean;
|
|
41
41
|
readonly disable: () => boolean;
|
|
42
|
-
isEnabled: () => boolean;
|
|
42
|
+
readonly isEnabled: () => boolean;
|
|
43
|
+
readonly enableTextEditMode: () => boolean;
|
|
44
|
+
readonly disableTextEditMode: () => boolean;
|
|
45
|
+
readonly isTextEditModeEnabled: () => boolean;
|
|
43
46
|
};
|
|
44
47
|
grid: {
|
|
45
48
|
readonly toggle: () => void;
|