@markup-canvas/core 1.3.2 → 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.
@@ -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: 1.5,
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(96.7% 0.001 286.375)",
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(canvas: MarkupCanvas, config: Required<MarkupCanvasConfig>): () => void {
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)
@@ -0,0 +1,113 @@
1
+ import type { MarkupCanvas } from "@/lib/MarkupCanvas.js";
2
+ import type { PostMessageAction } from "@/types/events";
3
+ import { sendPostMessageError } from "./sendPostMessageError";
4
+
5
+ export function processPostMessage(
6
+ canvas: MarkupCanvas,
7
+ action: PostMessageAction,
8
+ payload: string | number | boolean | object,
9
+ canvasName: string
10
+ ): void {
11
+ try {
12
+ // View methods
13
+ switch (action) {
14
+ case "zoomIn":
15
+ canvas.zoomIn(payload as number | undefined);
16
+ break;
17
+ case "zoomOut":
18
+ canvas.zoomOut(payload as number | undefined);
19
+ break;
20
+ case "setZoom": {
21
+ const zoomLevel = payload as number;
22
+ if (typeof zoomLevel !== "number" || zoomLevel <= 0) {
23
+ throw new Error(`Invalid zoom level: ${zoomLevel}. Must be a positive number.`);
24
+ }
25
+ canvas.setZoom(zoomLevel);
26
+ break;
27
+ }
28
+ case "resetZoom":
29
+ canvas.resetZoom();
30
+ break;
31
+ case "panLeft":
32
+ canvas.panLeft(payload as number | undefined);
33
+ break;
34
+ case "panRight":
35
+ canvas.panRight(payload as number | undefined);
36
+ break;
37
+ case "panUp":
38
+ canvas.panUp(payload as number | undefined);
39
+ break;
40
+ case "panDown":
41
+ canvas.panDown(payload as number | undefined);
42
+ break;
43
+ case "fitToScreen":
44
+ canvas.fitToScreen();
45
+ break;
46
+ case "centerContent":
47
+ canvas.centerContent();
48
+ break;
49
+ case "panToPoint": {
50
+ const point = payload as { x: number; y: number };
51
+ canvas.panToPoint(point.x, point.y);
52
+ break;
53
+ }
54
+ case "resetView":
55
+ canvas.resetView();
56
+ break;
57
+ case "resetViewToCenter":
58
+ canvas.resetViewToCenter();
59
+ break;
60
+ // Ruler/Grid methods
61
+ case "toggleRulers":
62
+ canvas.toggleRulers();
63
+ break;
64
+ case "showRulers":
65
+ canvas.showRulers();
66
+ break;
67
+ case "hideRulers":
68
+ canvas.hideRulers();
69
+ break;
70
+ case "toggleGrid":
71
+ canvas.toggleGrid();
72
+ break;
73
+ case "showGrid":
74
+ canvas.showGrid();
75
+ break;
76
+ case "hideGrid":
77
+ canvas.hideGrid();
78
+ break;
79
+ // Config methods
80
+ case "updateThemeMode": {
81
+ const mode = payload as "light" | "dark";
82
+ if (mode !== "light" && mode !== "dark") {
83
+ throw new Error(`Invalid theme mode: ${mode}`);
84
+ }
85
+ canvas.updateThemeMode(mode);
86
+ break;
87
+ }
88
+ case "toggleThemeMode": {
89
+ const currentConfig = canvas.getConfig();
90
+ const newMode = currentConfig.themeMode === "light" ? "dark" : "light";
91
+ canvas.updateThemeMode(newMode);
92
+ break;
93
+ }
94
+ // Transition methods
95
+ case "updateTransition": {
96
+ const enabled = payload as boolean;
97
+ if (typeof enabled !== "boolean") {
98
+ throw new Error(`Invalid transition enabled value: ${enabled}. Must be a boolean.`);
99
+ }
100
+ canvas.updateTransition(enabled);
101
+ break;
102
+ }
103
+ case "toggleTransitionMode":
104
+ canvas.toggleTransitionMode();
105
+ break;
106
+ default:
107
+ throw new Error(`Unknown action: ${action}`);
108
+ }
109
+ } catch (error) {
110
+ const errorMessage = error instanceof Error ? error.message : String(error);
111
+ sendPostMessageError(canvasName, action, errorMessage);
112
+ }
113
+ }
@@ -1,6 +1,6 @@
1
1
  import type { MarkupCanvas } from "@/lib/MarkupCanvas.js";
2
- import type { PostMessageAction, PostMessageRequest } from "@/types/events";
3
- import { sendPostMessageError } from "./sendError";
2
+ import type { PostMessageRequest } from "@/types/events";
3
+ import { processPostMessage } from "./processPostMessages";
4
4
 
5
5
  export function setupPostMessageEvents(canvas: MarkupCanvas): () => void {
6
6
  const handleMessage = (event: MessageEvent): void => {
@@ -10,94 +10,16 @@ export function setupPostMessageEvents(canvas: MarkupCanvas): () => void {
10
10
  return;
11
11
  }
12
12
 
13
- console.log("data", event.data);
14
-
15
13
  const canvasName = canvas.config.name || "markupCanvas";
16
14
 
17
15
  if (data.canvasName !== canvasName) {
18
- console.log("canvasName", data.canvasName, "!==", canvasName);
19
16
  return;
20
17
  }
21
18
 
22
- const action = data.action as PostMessageAction;
19
+ const action = data.action;
23
20
  const payload = data.data as string | number | boolean | object;
24
21
 
25
- try {
26
- // View methods
27
- if (action === "zoomIn") {
28
- console.log("zoomIn", payload);
29
- canvas.zoomIn(payload as number | undefined);
30
- } else if (action === "zoomOut") {
31
- canvas.zoomOut(payload as number | undefined);
32
- } else if (action === "setZoom") {
33
- const zoomLevel = payload as number;
34
- if (typeof zoomLevel !== "number" || zoomLevel <= 0) {
35
- throw new Error(`Invalid zoom level: ${zoomLevel}. Must be a positive number.`);
36
- }
37
- canvas.setZoom(zoomLevel);
38
- } else if (action === "resetZoom") {
39
- canvas.resetZoom();
40
- } else if (action === "panLeft") {
41
- canvas.panLeft(payload as number | undefined);
42
- } else if (action === "panRight") {
43
- canvas.panRight(payload as number | undefined);
44
- } else if (action === "panUp") {
45
- canvas.panUp(payload as number | undefined);
46
- } else if (action === "panDown") {
47
- canvas.panDown(payload as number | undefined);
48
- } else if (action === "fitToScreen") {
49
- canvas.fitToScreen();
50
- } else if (action === "centerContent") {
51
- canvas.centerContent();
52
- } else if (action === "panToPoint") {
53
- canvas.panToPoint((payload as { x: number; y: number }).x, (payload as { x: number; y: number }).y);
54
- } else if (action === "resetView") {
55
- canvas.resetView();
56
- } else if (action === "resetViewToCenter") {
57
- canvas.resetViewToCenter();
58
- }
59
- // Ruler/Grid methods
60
- else if (action === "toggleRulers") {
61
- canvas.toggleRulers();
62
- } else if (action === "showRulers") {
63
- canvas.showRulers();
64
- } else if (action === "hideRulers") {
65
- canvas.hideRulers();
66
- } else if (action === "toggleGrid") {
67
- canvas.toggleGrid();
68
- } else if (action === "showGrid") {
69
- canvas.showGrid();
70
- } else if (action === "hideGrid") {
71
- canvas.hideGrid();
72
- }
73
- // Config methods
74
- else if (action === "updateThemeMode") {
75
- const mode = payload as "light" | "dark";
76
- if (mode !== "light" && mode !== "dark") {
77
- throw new Error(`Invalid theme mode: ${mode}`);
78
- }
79
- canvas.updateThemeMode(mode);
80
- } else if (action === "toggleThemeMode") {
81
- const currentConfig = canvas.getConfig();
82
- const newMode = currentConfig.themeMode === "light" ? "dark" : "light";
83
- canvas.updateThemeMode(newMode);
84
- }
85
- // Transition methods
86
- else if (action === "updateTransition") {
87
- const enabled = payload as boolean;
88
- if (typeof enabled !== "boolean") {
89
- throw new Error(`Invalid transition enabled value: ${enabled}. Must be a boolean.`);
90
- }
91
- canvas.updateTransition(enabled);
92
- } else if (action === "toggleTransitionMode") {
93
- canvas.toggleTransitionMode();
94
- } else {
95
- throw new Error(`Unknown action: ${action}`);
96
- }
97
- } catch (error) {
98
- const errorMessage = error instanceof Error ? error.message : String(error);
99
- sendPostMessageError(canvasName, action, errorMessage);
100
- }
22
+ processPostMessage(canvas, action, payload, canvasName);
101
23
  };
102
24
 
103
25
  if (typeof window !== "undefined") {
@@ -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
@@ -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;