@markup-canvas/core 1.0.6 → 1.0.8

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.
Files changed (34) hide show
  1. package/README.md +42 -2
  2. package/dist/lib/MarkupCanvas.d.ts +1 -0
  3. package/dist/lib/canvas/setupCanvasContainer.d.ts +2 -1
  4. package/dist/lib/helpers/index.d.ts +1 -0
  5. package/dist/lib/helpers/withTheme.d.ts +4 -0
  6. package/dist/lib/rulers/constants.d.ts +3 -6
  7. package/dist/lib/rulers/ticks/createHorizontalTick.d.ts +1 -1
  8. package/dist/lib/rulers/ticks/createVerticalTick.d.ts +1 -1
  9. package/dist/lib/rulers/updateRulerTheme.d.ts +8 -0
  10. package/dist/markup-canvas.cjs.js +149 -54
  11. package/dist/markup-canvas.esm.js +149 -54
  12. package/dist/markup-canvas.umd.js +130 -47
  13. package/dist/markup-canvas.umd.min.js +1 -1
  14. package/dist/types/config.d.ts +11 -2
  15. package/dist/types/rulers.d.ts +2 -0
  16. package/package.json +4 -4
  17. package/src/lib/MarkupCanvas.ts +19 -1
  18. package/src/lib/canvas/createCanvas.ts +1 -1
  19. package/src/lib/canvas/setupCanvasContainer.ts +9 -1
  20. package/src/lib/config/constants.ts +24 -9
  21. package/src/lib/config/presets/editor-preset.ts +23 -7
  22. package/src/lib/helpers/index.ts +1 -0
  23. package/src/lib/helpers/withTheme.ts +17 -0
  24. package/src/lib/rulers/constants.ts +3 -6
  25. package/src/lib/rulers/createCornerBox.ts +5 -4
  26. package/src/lib/rulers/createGridOverlay.ts +3 -2
  27. package/src/lib/rulers/createHorizontalRuler.ts +5 -4
  28. package/src/lib/rulers/createRulers.ts +19 -0
  29. package/src/lib/rulers/createVerticalRuler.ts +5 -4
  30. package/src/lib/rulers/ticks/createHorizontalTick.ts +8 -8
  31. package/src/lib/rulers/ticks/createVerticalTick.ts +8 -8
  32. package/src/lib/rulers/updateRulerTheme.ts +46 -0
  33. package/src/types/config.ts +18 -3
  34. package/src/types/rulers.ts +2 -0
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Markup Canvas
3
3
  * High-performance markup canvas with zoom and pan capabilities
4
- * @version 1.0.6
4
+ * @version 1.0.8
5
5
  */
6
6
  (function (global, factory) {
7
7
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
@@ -239,6 +239,14 @@
239
239
  return operation(adjustedX, adjustedY);
240
240
  }
241
241
 
242
+ function getThemeValue(config, key) {
243
+ if (config.themeMode === "dark") {
244
+ const darkKey = `${key}Dark`;
245
+ return config[darkKey];
246
+ }
247
+ return config[key];
248
+ }
249
+
242
250
  const DEFAULT_CONFIG = {
243
251
  // Canvas dimensions
244
252
  width: 8000,
@@ -271,18 +279,30 @@
271
279
  requireOptionForClickZoom: false,
272
280
  // Visual elements
273
281
  enableRulers: true,
274
- enableGrid: true,
275
- gridColor: "rgba(0, 123, 255, 0.1)",
276
- // Ruler styling
277
- rulerBackgroundColor: "rgba(255, 255, 255, 0.95)",
278
- rulerBorderColor: "#ddd",
279
- rulerTextColor: "#666",
280
- rulerMajorTickColor: "#999",
281
- rulerMinorTickColor: "#ccc",
282
+ enableGrid: false,
283
+ showRulers: true,
284
+ showGrid: false,
282
285
  rulerFontSize: 9,
283
286
  rulerFontFamily: "Monaco, Menlo, monospace",
284
287
  rulerUnits: "px",
285
288
  rulerSize: 20,
289
+ // Canvas styling
290
+ canvasBackgroundColor: "rgba(250, 250, 250, 1)",
291
+ canvasBackgroundColorDark: "rgba(40, 40, 40, 1)",
292
+ // Ruler styling (light theme)
293
+ rulerBackgroundColor: "rgba(255, 255, 255, 0.95)",
294
+ rulerBorderColor: "rgba(240, 240, 240, 1)",
295
+ rulerTextColor: "rgba(102, 102, 102, 1)",
296
+ rulerTickColor: "rgba(204, 204, 204, 1)",
297
+ gridColor: "rgba(232, 86, 193, 0.5)",
298
+ // Ruler styling (dark theme)
299
+ rulerBackgroundColorDark: "rgba(30, 30, 30, 0.95)",
300
+ rulerBorderColorDark: "rgba(68, 68, 68, 1)",
301
+ rulerTextColorDark: "rgba(170, 170, 170, 1)",
302
+ rulerTickColorDark: "rgba(104, 104, 104, 1)",
303
+ gridColorDark: "rgba(232, 86, 193, 0.5)",
304
+ // Theme
305
+ themeMode: "light",
286
306
  // Callbacks
287
307
  onTransformUpdate: () => { },
288
308
  };
@@ -514,7 +534,7 @@
514
534
  }
515
535
  }
516
536
 
517
- function setupCanvasContainer(container) {
537
+ function setupCanvasContainer(container, config) {
518
538
  const currentPosition = getComputedStyle(container).position;
519
539
  if (currentPosition === "static") {
520
540
  container.style.position = "relative";
@@ -522,6 +542,11 @@
522
542
  container.style.overflow = "hidden";
523
543
  container.style.cursor = "grab";
524
544
  container.style.overscrollBehavior = "none";
545
+ // Apply canvas background color
546
+ if (config) {
547
+ const backgroundColor = getThemeValue(config, "canvasBackgroundColor");
548
+ container.style.backgroundColor = backgroundColor;
549
+ }
525
550
  if (!container.hasAttribute("tabindex")) {
526
551
  container.setAttribute("tabindex", "0");
527
552
  }
@@ -538,7 +563,7 @@
538
563
  return null;
539
564
  }
540
565
  try {
541
- setupCanvasContainer(container);
566
+ setupCanvasContainer(container, config);
542
567
  const { transformLayer, contentLayer } = createCanvasLayers(container, config);
543
568
  // Enable hardware acceleration if requested
544
569
  if (config.enableAcceleration) {
@@ -1284,12 +1309,9 @@
1284
1309
  CORNER: 1001,
1285
1310
  };
1286
1311
  const TICK_SETTINGS = {
1287
- MAJOR_HEIGHT: 6,
1288
- MINOR_HEIGHT: 4,
1289
- MAJOR_WIDTH: 8,
1290
- MINOR_WIDTH: 4,
1291
- MAJOR_MULTIPLIER: 5,
1292
- LABEL_INTERVAL: 100,
1312
+ TICK_HEIGHT: 4,
1313
+ TICK_WIDTH: 4,
1314
+ TICK_LABEL_INTERVAL: 100,
1293
1315
  };
1294
1316
  const GRID_SETTINGS = {
1295
1317
  BASE_SIZE: 100,
@@ -1306,16 +1328,16 @@
1306
1328
  left: 0;
1307
1329
  width: ${config.rulerSize}px;
1308
1330
  height: ${config.rulerSize}px;
1309
- background: ${config.rulerBackgroundColor};
1310
- border-right: 1px solid ${config.rulerBorderColor};
1311
- border-bottom: 1px solid ${config.rulerBorderColor};
1331
+ background: var(--ruler-background-color);
1332
+ border-right: 1px solid var(--ruler-border-color);
1333
+ border-bottom: 1px solid var(--ruler-border-color);
1312
1334
  z-index: ${RULER_Z_INDEX.CORNER};
1313
1335
  display: flex;
1314
1336
  align-items: center;
1315
1337
  justify-content: center;
1316
1338
  font-family: ${config.rulerFontFamily};
1317
1339
  font-size: ${config.rulerFontSize - 2}px;
1318
- color: ${config.rulerTextColor};
1340
+ color: var(--ruler-text-color);
1319
1341
  pointer-events: none;
1320
1342
  `;
1321
1343
  corner.textContent = config.rulerUnits;
@@ -1334,8 +1356,8 @@
1334
1356
  pointer-events: none;
1335
1357
  z-index: ${RULER_Z_INDEX.GRID};
1336
1358
  background-image:
1337
- linear-gradient(${config.gridColor} 1px, transparent 1px),
1338
- linear-gradient(90deg, ${config.gridColor} 1px, transparent 1px);
1359
+ linear-gradient(var(--grid-color) 1px, transparent 1px),
1360
+ linear-gradient(90deg, var(--grid-color) 1px, transparent 1px);
1339
1361
  background-size: 100px 100px;
1340
1362
  opacity: 0.5;
1341
1363
  `;
@@ -1351,14 +1373,14 @@
1351
1373
  left: ${config.rulerSize}px;
1352
1374
  right: 0;
1353
1375
  height: ${config.rulerSize}px;
1354
- background: ${config.rulerBackgroundColor};
1355
- border-bottom: 1px solid ${config.rulerBorderColor};
1356
- border-right: 1px solid ${config.rulerBorderColor};
1376
+ background: var(--ruler-background-color);
1377
+ border-bottom: 1px solid var(--ruler-border-color);
1378
+ border-right: 1px solid var(--ruler-border-color);
1357
1379
  z-index: ${RULER_Z_INDEX.RULERS};
1358
1380
  pointer-events: none;
1359
1381
  font-family: ${config.rulerFontFamily};
1360
1382
  font-size: ${config.rulerFontSize}px;
1361
- color: ${config.rulerTextColor};
1383
+ color: var(--ruler-text-color);
1362
1384
  overflow: hidden;
1363
1385
  `;
1364
1386
  return ruler;
@@ -1373,14 +1395,14 @@
1373
1395
  left: 0;
1374
1396
  bottom: 0;
1375
1397
  width: ${config.rulerSize}px;
1376
- background: ${config.rulerBackgroundColor};
1377
- border-right: 1px solid ${config.rulerBorderColor};
1378
- border-bottom: 1px solid ${config.rulerBorderColor};
1398
+ background: var(--ruler-background-color);
1399
+ border-right: 1px solid var(--ruler-border-color);
1400
+ border-bottom: 1px solid var(--ruler-border-color);
1379
1401
  z-index: ${RULER_Z_INDEX.RULERS};
1380
1402
  pointer-events: none;
1381
1403
  font-family: ${config.rulerFontFamily};
1382
1404
  font-size: ${config.rulerFontSize}px;
1383
- color: ${config.rulerTextColor};
1405
+ color: var(--ruler-text-color);
1384
1406
  overflow: hidden;
1385
1407
  `;
1386
1408
  return ruler;
@@ -1450,29 +1472,28 @@
1450
1472
  return niceSpacing * magnitude;
1451
1473
  }
1452
1474
 
1453
- function createHorizontalTick(container, position, pixelPos, tickSpacing, config) {
1475
+ function createHorizontalTick(container, position, pixelPos, _tickSpacing, config) {
1454
1476
  const tick = document.createElement("div");
1455
- const isMajor = position % (tickSpacing * TICK_SETTINGS.MAJOR_MULTIPLIER) === 0;
1456
- const tickHeight = isMajor ? TICK_SETTINGS.MAJOR_HEIGHT : TICK_SETTINGS.MINOR_HEIGHT;
1477
+ tick.className = "tick";
1457
1478
  tick.style.cssText = `
1458
1479
  position: absolute;
1459
1480
  left: ${pixelPos}px;
1460
1481
  bottom: 0;
1461
1482
  width: 1px;
1462
- height: ${tickHeight}px;
1463
- background: ${isMajor ? config.rulerMajorTickColor : config.rulerMinorTickColor};
1483
+ height: ${TICK_SETTINGS.TICK_HEIGHT}px;
1484
+ background: var(--ruler-tick-color);
1464
1485
  `;
1465
1486
  container.appendChild(tick);
1466
- const shouldShowLabel = isMajor || position % TICK_SETTINGS.LABEL_INTERVAL === 0;
1487
+ const shouldShowLabel = position % TICK_SETTINGS.TICK_LABEL_INTERVAL === 0;
1467
1488
  if (shouldShowLabel) {
1468
1489
  const label = document.createElement("div");
1469
1490
  label.style.cssText = `
1470
1491
  position: absolute;
1471
1492
  left: ${pixelPos}px;
1472
- bottom: ${tickHeight}px;
1493
+ bottom: ${TICK_SETTINGS.TICK_HEIGHT + 2}px;
1473
1494
  font-size: ${config.rulerFontSize}px;
1474
1495
  line-height: 1;
1475
- color: ${config.rulerTextColor};
1496
+ color: var(--ruler-text-color);
1476
1497
  white-space: nowrap;
1477
1498
  pointer-events: none;
1478
1499
  `;
@@ -1498,29 +1519,28 @@
1498
1519
  ruler.appendChild(fragment);
1499
1520
  }
1500
1521
 
1501
- function createVerticalTick(container, position, pixelPos, tickSpacing, config) {
1522
+ function createVerticalTick(container, position, pixelPos, _tickSpacing, config) {
1502
1523
  const tick = document.createElement("div");
1503
- const isMajor = position % (tickSpacing * TICK_SETTINGS.MAJOR_MULTIPLIER) === 0;
1504
- const tickWidth = isMajor ? TICK_SETTINGS.MAJOR_WIDTH : TICK_SETTINGS.MINOR_WIDTH;
1524
+ tick.className = "tick";
1505
1525
  tick.style.cssText = `
1506
1526
  position: absolute;
1507
1527
  top: ${pixelPos}px;
1508
1528
  right: 0;
1509
- width: ${tickWidth}px;
1529
+ width: ${TICK_SETTINGS.TICK_WIDTH}px;
1510
1530
  height: 1px;
1511
- background: ${isMajor ? config.rulerMajorTickColor : config.rulerMinorTickColor};
1531
+ background: var(--ruler-tick-color);
1512
1532
  `;
1513
1533
  container.appendChild(tick);
1514
- const shouldShowLabel = isMajor || position % TICK_SETTINGS.LABEL_INTERVAL === 0;
1534
+ const shouldShowLabel = position % TICK_SETTINGS.TICK_LABEL_INTERVAL === 0;
1515
1535
  if (shouldShowLabel) {
1516
1536
  const label = document.createElement("div");
1517
1537
  label.style.cssText = `
1518
1538
  position: absolute;
1519
1539
  top: ${pixelPos - 6}px;
1520
- right: ${tickWidth + 6}px;
1540
+ right: ${TICK_SETTINGS.TICK_WIDTH + 6}px;
1521
1541
  font-size: ${config.rulerFontSize}px;
1522
1542
  line-height: 1;
1523
- color: ${config.rulerTextColor};
1543
+ color: var(--ruler-text-color);
1524
1544
  white-space: nowrap;
1525
1545
  pointer-events: none;
1526
1546
  transform: rotate(-90deg);
@@ -1566,6 +1586,39 @@
1566
1586
  }
1567
1587
  }
1568
1588
 
1589
+ function updateRulerTheme(elements, config) {
1590
+ // Get theme-aware colors
1591
+ const backgroundColor = getThemeValue(config, "rulerBackgroundColor");
1592
+ const borderColor = getThemeValue(config, "rulerBorderColor");
1593
+ const textColor = getThemeValue(config, "rulerTextColor");
1594
+ const tickColor = getThemeValue(config, "rulerTickColor");
1595
+ const gridColor = getThemeValue(config, "gridColor");
1596
+ // Update horizontal ruler with CSS variables
1597
+ if (elements.horizontalRuler) {
1598
+ elements.horizontalRuler.style.setProperty("--ruler-background-color", backgroundColor);
1599
+ elements.horizontalRuler.style.setProperty("--ruler-border-color", borderColor);
1600
+ elements.horizontalRuler.style.setProperty("--ruler-text-color", textColor);
1601
+ elements.horizontalRuler.style.setProperty("--ruler-tick-color", tickColor);
1602
+ }
1603
+ // Update vertical ruler with CSS variables
1604
+ if (elements.verticalRuler) {
1605
+ elements.verticalRuler.style.setProperty("--ruler-background-color", backgroundColor);
1606
+ elements.verticalRuler.style.setProperty("--ruler-border-color", borderColor);
1607
+ elements.verticalRuler.style.setProperty("--ruler-text-color", textColor);
1608
+ elements.verticalRuler.style.setProperty("--ruler-tick-color", tickColor);
1609
+ }
1610
+ // Update corner box with CSS variables
1611
+ if (elements.cornerBox) {
1612
+ elements.cornerBox.style.setProperty("--ruler-background-color", backgroundColor);
1613
+ elements.cornerBox.style.setProperty("--ruler-border-color", borderColor);
1614
+ elements.cornerBox.style.setProperty("--ruler-text-color", textColor);
1615
+ }
1616
+ // Update grid overlay with CSS variables
1617
+ if (elements.gridOverlay) {
1618
+ elements.gridOverlay.style.setProperty("--grid-color", gridColor);
1619
+ }
1620
+ }
1621
+
1569
1622
  function createRulers(canvas, config) {
1570
1623
  if (!canvas?.container) {
1571
1624
  console.error("Invalid canvas provided to createRulers");
@@ -1582,13 +1635,28 @@
1582
1635
  try {
1583
1636
  elements = createRulerElements(canvas.container, config);
1584
1637
  cleanupEvents = setupRulerEvents(canvas, safeUpdate);
1638
+ updateRulerTheme(elements, config);
1585
1639
  safeUpdate();
1640
+ if (!config.showRulers) {
1641
+ elements.horizontalRuler.style.display = "none";
1642
+ elements.verticalRuler.style.display = "none";
1643
+ elements.cornerBox.style.display = "none";
1644
+ }
1645
+ if (!config.showGrid && elements.gridOverlay) {
1646
+ elements.gridOverlay.style.display = "none";
1647
+ }
1586
1648
  return {
1587
1649
  horizontalRuler: elements.horizontalRuler,
1588
1650
  verticalRuler: elements.verticalRuler,
1589
1651
  cornerBox: elements.cornerBox,
1590
1652
  gridOverlay: elements.gridOverlay,
1591
1653
  update: safeUpdate,
1654
+ updateTheme: (newConfig) => {
1655
+ if (isDestroyed)
1656
+ return;
1657
+ // Update all ruler theme colors
1658
+ updateRulerTheme(elements, newConfig);
1659
+ },
1592
1660
  show: () => {
1593
1661
  if (elements.horizontalRuler)
1594
1662
  elements.horizontalRuler.style.display = "block";
@@ -1956,6 +2024,21 @@
1956
2024
  updateConfig(newConfig) {
1957
2025
  this.config = createMarkupCanvasConfig({ ...this.config, ...newConfig });
1958
2026
  }
2027
+ // Theme management
2028
+ updateThemeMode(mode) {
2029
+ const newConfig = {
2030
+ ...this.config,
2031
+ themeMode: mode,
2032
+ };
2033
+ this.config = createMarkupCanvasConfig(newConfig);
2034
+ // Update canvas background color
2035
+ const backgroundColor = getThemeValue(this.config, "canvasBackgroundColor");
2036
+ this.baseCanvas.container.style.backgroundColor = backgroundColor;
2037
+ // Update rulers if they exist
2038
+ if (this.rulers) {
2039
+ this.rulers.updateTheme(this.config);
2040
+ }
2041
+ }
1959
2042
  // Cleanup method
1960
2043
  cleanup() {
1961
2044
  this.cleanupFunctions.forEach((cleanup) => {
@@ -1 +1 @@
1
- !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).MarkupCanvas=e()}(this,function(){"use strict";const t="canvas-container",e="transform-layer",n="content-layer";function r(t,r){const o=Array.from(t.children);let a=t.querySelector(`.${e}`);a||(a=document.createElement("div"),a.className=e,t.appendChild(a)),function(t,e){t.style.position="absolute";const n=e.rulerSize;t.style.top=`${n}px`,t.style.left=`${n}px`,t.style.width=`${e.width}px`,t.style.height=`${e.height}px`,t.style.transformOrigin="0 0"}(a,r);let s=a.querySelector(`.${n}`);return s||(s=document.createElement("div"),s.className=n,a.appendChild(s),function(t,n,r){t.forEach(t=>{t===r||t.classList.contains(e)||n.appendChild(t)})}(o,s,a)),function(t){t.style.position="relative",t.style.width="100%",t.style.height="100%",t.style.pointerEvents="auto"}(s),{transformLayer:a,contentLayer:s}}function o(t,e,n){if(!n?.inverse)return{x:t,y:e};try{const r=n.inverse(),o=new DOMPoint(t,e).matrixTransform(r);return{x:o.x,y:o.y}}catch(n){return console.warn("Canvas to content conversion failed:",n),{x:t,y:e}}}function a(t,e){return Math.max(e.minZoom,Math.min(e.maxZoom,t))}function s(t,e,n){return new DOMMatrix([t,0,0,t,e,n])}function i(t,e,n,r,o){const s=o.enableRulers?-o.rulerSize:0,i=n||{scale:1,translateX:s,translateY:s},{scale:l,translateX:c,translateY:u}=i,d=a(l*r,o);if(Math.abs(d-l)<.001)return{scale:l,translateX:c,translateY:u};return{scale:d,translateX:t-(t-c)/l*d,translateY:e-(e-u)/l*d}}function l(t,e){return e(e=>a(e,t))}const c=new Map;function u(t,e,n){return t[e]?n():null}function d(t){let e=null,n=null;const r=(...r)=>{n=r,null===e&&(e=requestAnimationFrame(()=>{n&&t(...n),e=null,n=null}))};return r.cleanup=()=>{null!==e&&(cancelAnimationFrame(e),e=null,n=null)},r}function h(t,e,n){return n(null!==t.container.querySelector(".canvas-ruler")?e:0)}function m(t,e,n,r,o){const a=null!==t.container.querySelector(".canvas-ruler");return o(a?e-r:e,a?n-r:n)}const f={width:8e3,height:8e3,enableAcceleration:!0,enableZoom:!0,enablePan:!0,enableTouch:!0,enableKeyboard:!0,limitKeyboardEventsToCanvas:!1,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:!0,gridColor:"rgba(0, 123, 255, 0.1)",rulerBackgroundColor:"rgba(255, 255, 255, 0.95)",rulerBorderColor:"#ddd",rulerTextColor:"#666",rulerMajorTickColor:"#999",rulerMinorTickColor:"#ccc",rulerFontSize:9,rulerFontFamily:"Monaco, Menlo, monospace",rulerUnits:"px",rulerSize:20,onTransformUpdate:()=>{}};function g(t){try{const e=t.container,n=t.config,r=t.transform||{scale:1,translateX:0,translateY:0},a=e.getBoundingClientRect(),i=a.width||e.clientWidth||0,l=a.height||e.clientHeight||0,c=h({container:e},n.rulerSize,t=>Math.max(0,i-t)),u=h({container:e},n.rulerSize,t=>Math.max(0,l-t)),d=n.width||f.width,m=n.height||f.height,g=function(t,e,n,r,a){const i=o(0,0,s(a.scale,a.translateX,a.translateY)),l=o(t,e,s(a.scale,a.translateX,a.translateY));return{x:Math.max(0,Math.min(n,i.x)),y:Math.max(0,Math.min(r,i.y)),width:Math.max(0,Math.min(n-i.x,l.x-i.x)),height:Math.max(0,Math.min(r-i.y,l.y-i.y))}}(c,u,d,m,r);return{width:c,height:u,contentWidth:d,contentHeight:m,scale:r.scale,translateX:r.translateX,translateY:r.translateY,visibleArea:g,scaledContentWidth:d*r.scale,scaledContentHeight:m*r.scale,canPanLeft:r.translateX<0,canPanRight:r.translateX+d*r.scale>c,canPanUp:r.translateY<0,canPanDown:r.translateY+m*r.scale>u,canZoomIn:r.scale<3.5,canZoomOut:r.scale>.1}}catch(t){return console.error("Failed to calculate canvas bounds:",t),{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 p(t,e){if(!t?.style||!e)return!1;try{return t.style.transform=function(t){return`matrix3d(${t.m11}, ${t.m12}, ${t.m13}, ${t.m14}, ${t.m21}, ${t.m22}, ${t.m23}, ${t.m24}, ${t.m31}, ${t.m32}, ${t.m33}, ${t.m34}, ${t.m41}, ${t.m42}, ${t.m43}, ${t.m44})`}(e),!0}catch(t){return console.warn("Transform application failed:",t),!1}}function v(t,e){try{if(e.enableTransition){window.__markupCanvasTransitionTimeout&&(clearTimeout(window.__markupCanvasTransitionTimeout),window.__markupCanvasTransitionTimeout=void 0);return function(t,e,n){const r=c.get(t);r&&clearTimeout(r);const o=window.setTimeout(()=>{n(),c.delete(t)},e);c.set(t,o)}("disableTransition",1e3*(e.transitionDuration??.2),()=>{t.style.transition="none",window.__markupCanvasTransitionTimeout=void 0}),!0}return!1}catch(t){return console.error("Failed to disable transitions:",t),!0}}function y(t,e,n){!function(t,e){try{return!!e.enableTransition&&(window.__markupCanvasTransitionTimeout&&(clearTimeout(window.__markupCanvasTransitionTimeout),window.__markupCanvasTransitionTimeout=void 0),t.style.transition=`transform ${e.transitionDuration}s linear`,!0)}catch(t){return console.error("Failed to enable transitions:",t),!1}}(t,e);try{return n()}finally{v(t,e)}}function b(e){"static"===getComputedStyle(e).position&&(e.style.position="relative"),e.style.overflow="hidden",e.style.cursor="grab",e.style.overscrollBehavior="none",e.hasAttribute("tabindex")||e.setAttribute("tabindex","0"),function(t){const e=t.getBoundingClientRect(),n=getComputedStyle(t);0===e.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.",t),0===e.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.",t)}(e),e.classList.contains(t)||e.classList.add(t)}function w(t,e){if(!t?.appendChild)return console.error("Invalid container element provided to createCanvas"),null;try{b(t);const{transformLayer:n,contentLayer:a}=r(t,e);e.enableAcceleration&&function(t){try{return t.style.transform=t.style.transform||"translateZ(0)",t.style.backfaceVisibility="hidden",!0}catch(t){return console.error("Failed to enable hardware acceleration:",t),!1}}(n);const c=e.enableRulers?-e.rulerSize:0,d={scale:1,translateX:c,translateY:c};p(n,s(d.scale,d.translateX,d.translateY));return{container:t,transformLayer:n,contentLayer:a,config:e,transform:d,getBounds:function(){return g(this)},updateTransform:function(t){this.transform={...this.transform,...t};const e=s(this.transform.scale,this.transform.translateX,this.transform.translateY),n=p(this.transformLayer,e);return u(this.config,"onTransformUpdate",()=>{this.config.onTransformUpdate(this.transform)}),n},reset:function(){return this.updateTransform({scale:1,translateX:0,translateY:0})},handleResize:function(){return!0},setZoom:function(t){const e=l(this.config,e=>e(t));return this.updateTransform({scale:e})},canvasToContent:function(t,e){return o(t,e,s(this.transform.scale,this.transform.translateX,this.transform.translateY))},zoomToPoint:function(t,e,n){return y(this.transformLayer,this.config,()=>{const r=i(t,e,this.transform,n/this.transform.scale,this.config);return this.updateTransform(r)})},resetView:function(){return y(this.transformLayer,this.config,()=>h(this,this.config.rulerSize,t=>{const e={scale:1,translateX:-1*t,translateY:-1*t};return this.updateTransform(e)}))},zoomToFitContent:function(){return y(this.transformLayer,this.config,()=>{const t=this.getBounds(),e=t.width/this.config.width,n=t.height/this.config.height,r=l(this.config,t=>t(.9*Math.min(e,n))),o=this.config.width*r,a=this.config.height*r,s=(t.width-o)/2,i=(t.height-a)/2;return this.updateTransform({scale:r,translateX:s,translateY:i})})}}}catch(t){return console.error("Failed to create canvas:",t),null}}function C(t={}){const e={...f,...t};return("number"!=typeof e.width||e.width<=0)&&(console.warn("Invalid width, using default"),e.width=f.width),("number"!=typeof e.height||e.height<=0)&&(console.warn("Invalid height, using default"),e.height=f.height),("number"!=typeof e.zoomSpeed||e.zoomSpeed<=0)&&(console.warn("Invalid zoomSpeed, using default"),e.zoomSpeed=f.zoomSpeed),("number"!=typeof e.minZoom||e.minZoom<=0)&&(console.warn("Invalid minZoom, using default"),e.minZoom=f.minZoom),("number"!=typeof e.maxZoom||e.maxZoom<=e.minZoom)&&(console.warn("Invalid maxZoom, using default"),e.maxZoom=f.maxZoom),("number"!=typeof e.keyboardPanStep||e.keyboardPanStep<=0)&&(console.warn("Invalid keyboardPanStep, using default"),e.keyboardPanStep=f.keyboardPanStep),("number"!=typeof e.keyboardFastMultiplier||e.keyboardFastMultiplier<=0)&&(console.warn("Invalid keyboardFastMultiplier, using default"),e.keyboardFastMultiplier=f.keyboardFastMultiplier),("number"!=typeof e.clickZoomLevel||e.clickZoomLevel<=0)&&(console.warn("Invalid clickZoomLevel, using default"),e.clickZoomLevel=f.clickZoomLevel),("number"!=typeof e.rulerFontSize||e.rulerFontSize<=0)&&(console.warn("Invalid rulerFontSize, using default"),e.rulerFontSize=f.rulerFontSize),("number"!=typeof e.rulerSize||e.rulerSize<=0)&&(console.warn("Invalid rulerSize, using default"),e.rulerSize=f.rulerSize),e}class x{constructor(){this.listeners=new Map}on(t,e){this.listeners.has(t)||this.listeners.set(t,new Set),this.listeners.get(t).add(e)}off(t,e){const n=this.listeners.get(t);n&&n.delete(e)}emit(t,e){const n=this.listeners.get(t);n&&n.forEach(n=>{try{n(e)}catch(e){console.error(`Error in event handler for "${String(t)}":`,e)}})}removeAllListeners(){this.listeners.clear()}}const T=300,S=5;function k(t,e){if(!t?.getBounds)return e;try{const n=t.getBounds(),r=n.width*n.height;return e*(r/2073600)**1}catch(t){return console.warn("Failed to calculate adaptive zoom speed, using base speed:",t),e}}function D(t,e){let n=0,r=0;function o(o){const a=t.container.getBoundingClientRect(),s=o.clientX-a.left,i=o.clientY-a.top;!function(t,e,n,r,o){h(t,e,t=>o(n-t,r-t))}(t,e.rulerSize,s,i,(t,e)=>{n=t,r=e})}function s(o){if(!(o instanceof KeyboardEvent))return;if(e.limitKeyboardEventsToCanvas&&document.activeElement!==t.container)return;const s=o.shiftKey,l=e.keyboardPanStep*(s?e.keyboardFastMultiplier:1);let c=!1;const u={};switch(o.key){case"ArrowLeft":u.translateX=t.transform.translateX+l,c=!0;break;case"ArrowRight":u.translateX=t.transform.translateX-l,c=!0;break;case"ArrowUp":u.translateY=t.transform.translateY+l,c=!0;break;case"ArrowDown":u.translateY=t.transform.translateY-l,c=!0;break;case"=":case"+":{const n=e.enableAdaptiveSpeed?k(t,e.keyboardZoomStep):e.keyboardZoomStep;u.scale=a(t.transform.scale*(1+n),e),c=!0}break;case"-":{const n=e.enableAdaptiveSpeed?k(t,e.keyboardZoomStep):e.keyboardZoomStep;u.scale=a(t.transform.scale*(1-n),e),c=!0}break;case"0":if(o.metaKey||o.ctrlKey){const o=1/t.transform.scale,a=i(n,r,t.transform,o,e);Object.assign(u,a),c=!0}break;case"g":case"G":t.toggleGrid&&t.toggleGrid(),c=!0;break;case"r":case"R":o.metaKey||o.ctrlKey||o.altKey||!t.toggleRulers||(t.toggleRulers(),c=!0)}c&&(o.preventDefault(),Object.keys(u).length>0&&t.updateTransform(u))}const l=e.limitKeyboardEventsToCanvas?t.container:document;return l.addEventListener("keydown",s),t.container.addEventListener("mousemove",o),()=>{l.removeEventListener("keydown",s),t.container.removeEventListener("mousemove",o)}}function M(t,e,n,r,o){n?e.requireSpaceForMouseDrag?t.container.style.cursor=r?"grab":"default":t.container.style.cursor=o?"grabbing":"grab":t.container.style.cursor="default"}function z(t,e,n,r,o){o.setIsDragging(!1),o.setDragButton(-1),M(t,e,n,r,!1)}function L(t,e,n,r,o,a,s,i,l,c){a&&t.button===s&&z(e,n,r,o,{setIsDragging:c.setIsDragging,setDragButton:c.setDragButton}),r&&0===t.button&&n.enableClickToZoom&&i>0&&function(t,e,n,r,o,a){const s=Date.now()-r,i=t.altKey,l=!n.requireOptionForClickZoom||i;if(s<T&&!o&&!a&&l){t.preventDefault();const r=e.container.getBoundingClientRect(),o=t.clientX-r.left,a=t.clientY-r.top,{clickX:s,clickY:i}=m(e,o,a,n.rulerSize,(t,e)=>({clickX:t,clickY:e})),l=e.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(e.transformLayer,e.config,()=>{e.updateTransform(h)})}}(t,e,n,i,l,a),0===t.button&&function(t){t.setMouseDownTime(0),t.setHasDragged(!1)}({setMouseDownTime:c.setMouseDownTime,setHasDragged:c.setHasDragged})}function $(t,e,n=!0){let r=!0,o=!1,a=0,s=0,i=-1,l=!1,c=0,u=0,h=0,m=!1;const f={setIsDragging:t=>{o=t},setDragButton:t=>{i=t},setIsSpacePressed:t=>{l=t},setMouseDownTime:t=>{c=t},setMouseDownX:t=>{u=t},setMouseDownY:t=>{h=t},setHasDragged:t=>{m=t},setLastMouseX:t=>{a=t},setLastMouseY:t=>{s=t}},g=n=>{!function(t,e,n,r,o,a){n.requireSpaceForMouseDrag&&" "===t.key&&(a.setIsSpacePressed(!0),M(e,n,r,!0,o))}(n,t,e,r,o,{setIsSpacePressed:f.setIsSpacePressed})},p=n=>{!function(t,e,n,r,o,a){n.requireSpaceForMouseDrag&&" "===t.key&&(a.setIsSpacePressed(!1),M(e,n,r,!1,o),o&&z(e,n,r,!1,{setIsDragging:a.setIsDragging,setDragButton:a.setDragButton}))}(n,t,e,r,o,{setIsSpacePressed:f.setIsSpacePressed,setIsDragging:f.setIsDragging,setDragButton:f.setDragButton})},v=n=>{!function(t,e,n,r,o,a){const s=0===t.button,i=1===t.button;if(s&&(a.setMouseDownTime(Date.now()),a.setMouseDownX(t.clientX),a.setMouseDownY(t.clientY),a.setHasDragged(!1)),!r)return;(!n.requireSpaceForMouseDrag||o)&&(s&&n.enableLeftDrag||i&&n.enableMiddleDrag)&&(t.preventDefault(),a.setDragButton(t.button),a.setLastMouseX(t.clientX),a.setLastMouseY(t.clientY),M(e,n,r,o,!1))}(n,t,e,r,l,f)},y=e=>{!function(t,e,n,r,o,a,s,i,l,c){if(o>0){const e=Math.abs(t.clientX-a),o=Math.abs(t.clientY-s);(e>S||o>S)&&(c.setHasDragged(!0),!r&&n&&c.setIsDragging(!0))}if(!r||!n)return;t.preventDefault(),d((...t)=>{const o=t[0];if(!r||!n)return;const a=o.clientX-i,s=o.clientY-l,u={translateX:e.transform.translateX+a,translateY:e.transform.translateY+s};e.updateTransform(u),c.setLastMouseX(o.clientX),c.setLastMouseY(o.clientY)})(t)}(e,t,r,o,c,u,h,a,s,{setHasDragged:f.setHasDragged,setIsDragging:f.setIsDragging,setLastMouseX:f.setLastMouseX,setLastMouseY:f.setLastMouseY})},b=n=>{L(n,t,e,r,l,o,i,c,m,{setIsDragging:f.setIsDragging,setDragButton:f.setDragButton,setMouseDownTime:f.setMouseDownTime,setHasDragged:f.setHasDragged})},w=()=>{!function(t,e,n,r,o,a){o&&z(t,e,n,r,a)}(t,e,r,l,o,{setIsDragging:f.setIsDragging,setDragButton:f.setDragButton})};t.container.addEventListener("mousedown",v),document.addEventListener("mousemove",y),document.addEventListener("mouseup",b),t.container.addEventListener("mouseleave",w),e.requireSpaceForMouseDrag&&(document.addEventListener("keydown",g),document.addEventListener("keyup",p)),M(t,e,r,l,o);const C=()=>{t.container.removeEventListener("mousedown",v),document.removeEventListener("mousemove",y),document.removeEventListener("mouseup",b),t.container.removeEventListener("mouseleave",w),e.requireSpaceForMouseDrag&&(document.removeEventListener("keydown",g),document.removeEventListener("keyup",p))};return n?{cleanup:C,enable:()=>(r=!0,M(t,e,r,l,o),!0),disable:()=>(r=!1,o&&z(t,e,r,l,{setIsDragging:f.setIsDragging,setDragButton:f.setDragButton}),M(t,e,r,l,o),!0),isEnabled:()=>r}:C}function Y(t,e){return{x:(t.clientX+e.clientX)/2,y:(t.clientY+e.clientY)/2}}function E(t,e){const n=t.clientX-e.clientX,r=t.clientY-e.clientY;return Math.sqrt(n*n+r*r)}function X(t,e,n,r){const o=i(n,r,t.transform,e,t.config);return t.updateTransform(o)}function F(t,e,n){t.preventDefault();const r=Array.from(t.touches);d((...t)=>{const r=t[0];if(1===r.length){if(1===n.touches.length){const t=r[0].clientX-n.touches[0].clientX,o=r[0].clientY-n.touches[0].clientY,a={translateX:e.transform.translateX+t,translateY:e.transform.translateY+o};e.updateTransform(a)}}else if(2===r.length){const t=E(r[0],r[1]),o=Y(r[0],r[1]);if(n.lastDistance>0){const r=t/n.lastDistance,a=e.container.getBoundingClientRect();let s=o.x-a.left,i=o.y-a.top;const l=function(t,e,n,r){return h(t,e,t=>{const e={...n,x:n.x-t,y:n.y-t};return r(e)})}(e,e.config.rulerSize,{x:s,y:i},t=>t);s=l.x,i=l.y,X(e,r,s,i)}n.lastDistance=t,n.lastCenter=o}n.touches=r})(r)}function R(t){const e={touches:[],lastDistance:0,lastCenter:{}},n=t=>{!function(t,e){t.preventDefault(),e.touches=Array.from(t.touches),2===e.touches.length&&(e.lastDistance=E(e.touches[0],e.touches[1]),e.lastCenter=Y(e.touches[0],e.touches[1]))}(t,e)},r=n=>{F(n,t,e)},o=t=>{!function(t,e){e.touches=Array.from(t.touches),e.touches.length<2&&(e.lastDistance=0)}(t,e)};return t.container.addEventListener("touchstart",n,{passive:!1}),t.container.addEventListener("touchmove",r,{passive:!1}),t.container.addEventListener("touchend",o,{passive:!1}),()=>{t.container.removeEventListener("touchstart",n),t.container.removeEventListener("touchmove",r),t.container.removeEventListener("touchend",o)}}function B(t){const e=t.ctrlKey||t.metaKey,n=[0===t.deltaMode,Math.abs(t.deltaY)<50,t.deltaY%1!=0,Math.abs(t.deltaX)>0&&Math.abs(t.deltaY)>0].filter(Boolean).length>=2;return{isTrackpad:n,isMouseWheel:!n,isTrackpadScroll:n&&!e,isTrackpadPinch:n&&e,isZoomGesture:e}}function Z(t,e){const n=(t=>d((...e)=>{const n=e[0];if(!n||!t?.updateTransform)return!1;try{const e=t.transform,r=1,o=n.deltaX*r,a=n.deltaY*r,s={scale:e.scale,translateX:e.translateX-o,translateY:e.translateY-a};return v(t.transformLayer,t.config),t.updateTransform(s)}catch(t){return console.error("Error handling trackpad pan:",t),!1}}))(t),r=r=>B(r).isTrackpadScroll?n(r):function(t,e,n){if(!t||"number"!=typeof t.deltaY)return console.warn("Invalid wheel event provided"),!1;if(!e?.updateTransform)return console.warn("Invalid canvas provided to handleWheelEvent"),!1;try{t.preventDefault();const r=e.container.getBoundingClientRect(),o=t.clientX-r.left,a=t.clientY-r.top,{mouseX:s,mouseY:i}=m(e,o,a,n.rulerSize,(t,e)=>({mouseX:t,mouseY:e})),l=n.zoomSpeed,c=B(t);if(!c.isZoomGesture)return!1;let u=n.enableAdaptiveSpeed?k(e,l):l;if(c.isTrackpadPinch){const t=.05*n.zoomSpeed;u=n.enableAdaptiveSpeed?k(e,t):t}return X(e,(t.deltaY<0?1:-1)>0?1+u:1/(1+u),s,i)}catch(t){return console.error("Error handling wheel event:",t),!1}}(r,t,e);return t.container.addEventListener("wheel",r,{passive:!1}),()=>{t.container.removeEventListener("wheel",r)}}const I=100,P=1e3,O=1001,A=6,_=4,H=8,q=4,K=5,G=100,N=100,V=20,U=200;function W(t,e){const n=function(t){const e=document.createElement("div");return e.className="canvas-ruler horizontal-ruler",e.style.cssText=`\n\tposition: absolute;\n\ttop: 0;\n\tleft: ${t.rulerSize}px;\n\tright: 0;\n\theight: ${t.rulerSize}px;\n\tbackground: ${t.rulerBackgroundColor};\n\tborder-bottom: 1px solid ${t.rulerBorderColor};\n\tborder-right: 1px solid ${t.rulerBorderColor};\n\tz-index: ${P};\n\tpointer-events: none;\n\tfont-family: ${t.rulerFontFamily};\n\tfont-size: ${t.rulerFontSize}px;\n\tcolor: ${t.rulerTextColor};\n\toverflow: hidden;\n `,e}(e),r=function(t){const e=document.createElement("div");return e.className="canvas-ruler vertical-ruler",e.style.cssText=`\n\tposition: absolute;\n\ttop: ${t.rulerSize}px;\n\tleft: 0;\n\tbottom: 0;\n\twidth: ${t.rulerSize}px;\n\tbackground: ${t.rulerBackgroundColor};\n\tborder-right: 1px solid ${t.rulerBorderColor};\n\tborder-bottom: 1px solid ${t.rulerBorderColor};\n\tz-index: ${P};\n\tpointer-events: none;\n\tfont-family: ${t.rulerFontFamily};\n\tfont-size: ${t.rulerFontSize}px;\n\tcolor: ${t.rulerTextColor};\n\toverflow: hidden;\n `,e}(e),o=function(t){const e=document.createElement("div");return e.className="canvas-ruler corner-box",e.style.cssText=`\n\t\tposition: absolute;\n\t\ttop: 0;\n\t\tleft: 0;\n\t\twidth: ${t.rulerSize}px;\n\t\theight: ${t.rulerSize}px;\n\t\tbackground: ${t.rulerBackgroundColor};\n\t\tborder-right: 1px solid ${t.rulerBorderColor};\n\t\tborder-bottom: 1px solid ${t.rulerBorderColor};\n\t\tz-index: ${O};\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t\tjustify-content: center;\n\t\tfont-family: ${t.rulerFontFamily};\n\t\tfont-size: ${t.rulerFontSize-2}px;\n\t\tcolor: ${t.rulerTextColor};\n\t\tpointer-events: none;\n\t`,e.textContent=t.rulerUnits,e}(e),a=e.enableGrid?function(t){const e=document.createElement("div");return e.className="canvas-ruler grid-overlay",e.style.cssText=`\n\t\tposition: absolute;\n\t\ttop: ${t.rulerSize}px;\n\t\tleft: ${t.rulerSize}px;\n\t\tright: 0;\n\t\tbottom: 0;\n\t\tpointer-events: none;\n\t\tz-index: ${I};\n\t\tbackground-image: \n\t\t\tlinear-gradient(${t.gridColor} 1px, transparent 1px),\n\t\t\tlinear-gradient(90deg, ${t.gridColor} 1px, transparent 1px);\n\t\tbackground-size: 100px 100px;\n\t\topacity: 0.5;\n\t`,e}(e):void 0;return t.appendChild(n),t.appendChild(r),t.appendChild(o),a&&t.appendChild(a),{horizontalRuler:n,verticalRuler:r,cornerBox:o,gridOverlay:a}}function j(t,e){const n=t/Math.max(5,Math.min(20,e/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 J(t,e,n,r,o){const a=document.createElement("div"),s=e%(r*K)===0,i=s?A:_;a.style.cssText=`\n\t\tposition: absolute;\n\t\tleft: ${n}px;\n\t\tbottom: 0;\n\t\twidth: 1px;\n\t\theight: ${i}px;\n\t\tbackground: ${s?o.rulerMajorTickColor:o.rulerMinorTickColor};\n\t`,t.appendChild(a);if(s||e%G===0){const r=document.createElement("div");r.style.cssText=`\n\t\t\tposition: absolute;\n\t\t\tleft: ${n}px;\n\t\t\tbottom: ${i}px;\n\t\t\tfont-size: ${o.rulerFontSize}px;\n\t\t\tline-height: 1;\n\t\t\tcolor: ${o.rulerTextColor};\n\t\t\twhite-space: nowrap;\n\t\t\tpointer-events: none;\n\t\t`,r.textContent=Math.round(e).toString(),t.appendChild(r)}}function Q(t,e,n,r,o){const a=document.createElement("div"),s=e%(r*K)===0,i=s?H:q;a.style.cssText=`\n\t\tposition: absolute;\n\t\ttop: ${n}px;\n\t\tright: 0;\n\t\twidth: ${i}px;\n\t\theight: 1px;\n\t\tbackground: ${s?o.rulerMajorTickColor:o.rulerMinorTickColor};\n\t`,t.appendChild(a);if(s||e%G===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: ${i+6}px;\n\t\t\tfont-size: ${o.rulerFontSize}px;\n\t\t\tline-height: 1;\n\t\t\tcolor: ${o.rulerTextColor};\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(e).toString(),t.appendChild(r)}}function tt(t,e,n,r,o){const a=t.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,m=h+u/s;!function(t,e,n,r,o,a){const s=r,i=j(n-e,s),l=document.createDocumentFragment(),c=Math.floor(e/i)*i,u=Math.ceil(n/i)*i;for(let t=c;t<=u;t+=i){const n=(t-e)*o;n>=-50&&n<=s+50&&J(l,t,n,i,a)}t.innerHTML="",t.appendChild(l)}(e,d,d+c/s,c,s,o),function(t,e,n,r,o,a){const s=r,i=j(n-e,s),l=document.createDocumentFragment(),c=Math.floor(e/i)*i,u=Math.ceil(n/i)*i;for(let t=c;t<=u;t+=i){const n=(t-e)*o;n>=-50&&n<=s+50&&Q(l,t,n,i,a)}t.innerHTML="",t.appendChild(l)}(n,h,m,u,s,o),r&&function(t,e,n,r){let o=N*e;for(;o<V;)o*=2;for(;o>U;)o/=2;t.style.backgroundSize=`${o}px ${o}px`,t.style.backgroundPosition=`${n%o}px ${r%o}px`}(r,s,i,l)}function et(t,e){if(!t?.container)return console.error("Invalid canvas provided to createRulers"),null;let n,r=null,o=!1;const a=()=>{!o&&n.horizontalRuler&&n.verticalRuler&&tt(t,n.horizontalRuler,n.verticalRuler,n.gridOverlay,e)};try{return n=W(t.container,e),r=function(t,e){const n=d(e),r=t.updateTransform;t.updateTransform=function(t){const e=r.call(this,t);return n(),e};const o=d(e);return window.addEventListener("resize",o),()=>{window.removeEventListener("resize",o),t.updateTransform=r,n.cleanup(),o.cleanup()}}(t,a),a(),{horizontalRuler:n.horizontalRuler,verticalRuler:n.verticalRuler,cornerBox:n.cornerBox,gridOverlay:n.gridOverlay,update:a,show:()=>{n.horizontalRuler&&(n.horizontalRuler.style.display="block"),n.verticalRuler&&(n.verticalRuler.style.display="block"),n.cornerBox&&(n.cornerBox.style.display="flex"),n.gridOverlay&&(n.gridOverlay.style.display="block")},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 t="none"!==n.gridOverlay.style.display;n.gridOverlay.style.display=t?"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(t){return console.error("Failed to create rulers:",t),null}}return class{constructor(t,e={}){if(this.cleanupFunctions=[],this.rulers=null,this.dragSetup=null,this._isReady=!1,this.listen=new x,!t)throw new Error("Container element is required");this.config=C(e);const n=w(t,this.config);if(!n)throw new Error("Failed to create canvas");this.baseCanvas=n,this.setupEventHandlers(),this._isReady=!0,this.listen.emit("ready",this)}setupEventHandlers(){try{u(this.config,"enableZoom",()=>{const t=Z(this,this.config);this.cleanupFunctions.push(t)}),(this.config.enablePan||this.config.enableClickToZoom)&&(this.dragSetup=$(this,this.config,!0),this.cleanupFunctions.push(this.dragSetup.cleanup)),u(this.config,"enableKeyboard",()=>{const t=D(this,this.config);this.cleanupFunctions.push(t)}),u(this.config,"enableTouch",()=>{const t=R(this);this.cleanupFunctions.push(t)}),u(this.config,"enableRulers",()=>{this.rulers=et(this.baseCanvas,this.config),this.cleanupFunctions.push(()=>{this.rulers&&this.rulers.destroy()})})}catch(t){throw console.error("Failed to set up event handlers:",t),this.cleanup(),t}}get container(){return this.baseCanvas.container}get transformLayer(){return this.baseCanvas.transformLayer}get contentLayer(){return this.baseCanvas.contentLayer}get transform(){return this.baseCanvas.transform}get isReady(){return this._isReady}get isTransforming(){return this.dragSetup?.isEnabled()||!1}get visibleBounds(){return this.getVisibleArea()}getBounds(){return this.baseCanvas.getBounds()}updateTransform(t){const e=this.baseCanvas.updateTransform(t);return e&&this.emitTransformEvents(),e}emitTransformEvents(){const t=this.baseCanvas.transform;this.listen.emit("transform",t),this.listen.emit("zoom",t.scale),this.listen.emit("pan",{x:t.translateX,y:t.translateY})}reset(){return this.baseCanvas.reset()}handleResize(){return this.baseCanvas.handleResize()}setZoom(t){return this.baseCanvas.setZoom(t)}canvasToContent(t,e){return this.baseCanvas.canvasToContent(t,e)}zoomToPoint(t,e,n){return y(this.transformLayer,this.config,()=>{const r=this.baseCanvas.zoomToPoint(t,e,n);return r&&this.emitTransformEvents(),r})}resetView(){return y(this.transformLayer,this.config,()=>{const t=!!this.baseCanvas.resetView&&this.baseCanvas.resetView();return t&&this.emitTransformEvents(),t})}zoomToFitContent(){return y(this.transformLayer,this.config,()=>{const t=this.baseCanvas.zoomToFitContent();return t&&this.emitTransformEvents(),t})}panLeft(t){const e=t??this.config.keyboardPanStep,n={translateX:this.baseCanvas.transform.translateX+e};return this.updateTransform(n)}panRight(t){const e=t??this.config.keyboardPanStep,n={translateX:this.baseCanvas.transform.translateX-e};return this.updateTransform(n)}panUp(t){const e=t??this.config.keyboardPanStep,n={translateY:this.baseCanvas.transform.translateY+e};return this.updateTransform(n)}panDown(t){const e=t??this.config.keyboardPanStep,n={translateY:this.baseCanvas.transform.translateY-e};return this.updateTransform(n)}zoomIn(t=.1){return y(this.transformLayer,this.config,()=>l(this.config,e=>{const n={scale:e(this.baseCanvas.transform.scale*(1+t))};return this.updateTransform(n)}))}zoomOut(t=.1){return y(this.transformLayer,this.config,()=>l(this.config,e=>{const n={scale:e(this.baseCanvas.transform.scale*(1-t))};return this.updateTransform(n)}))}resetZoom(){return this.resetView()}enableMouseDrag(){return this.dragSetup?.enable()??!1}disableMouseDrag(){return this.dragSetup?.disable()??!1}isMouseDragEnabled(){return this.dragSetup?.isEnabled()??!1}toggleGrid(){return!!this.rulers?.toggleGrid&&(this.rulers.toggleGrid(),!0)}showGrid(){return!!this.rulers?.gridOverlay&&(this.rulers.gridOverlay.style.display="block",!0)}hideGrid(){return!!this.rulers?.gridOverlay&&(this.rulers.gridOverlay.style.display="none",!0)}isGridVisible(){return!!this.rulers?.gridOverlay&&"none"!==this.rulers.gridOverlay.style.display}toggleRulers(){if(this.rulers){return this.areRulersVisible()?this.rulers.hide():this.rulers.show(),!0}return!1}showRulers(){return!!this.rulers&&(this.rulers.show(),!0)}hideRulers(){return!!this.rulers&&(this.rulers.hide(),!0)}areRulersVisible(){return!!this.rulers?.horizontalRuler&&"none"!==this.rulers.horizontalRuler.style.display}centerContent(){return y(this.transformLayer,this.config,()=>{const t=this.baseCanvas.getBounds(),e=(t.width-t.contentWidth*this.baseCanvas.transform.scale)/2,n=(t.height-t.contentHeight*this.baseCanvas.transform.scale)/2;return this.updateTransform({translateX:e,translateY:n})})}fitToScreen(){return y(this.transformLayer,this.config,()=>{const t=this.baseCanvas.zoomToFitContent();return t&&this.emitTransformEvents(),t})}getVisibleArea(){return this.baseCanvas.getBounds().visibleArea}isPointVisible(t,e){const n=this.getVisibleArea();return t>=n.x&&t<=n.x+n.width&&e>=n.y&&e<=n.y+n.height}scrollToPoint(t,e){return y(this.transformLayer,this.config,()=>{const n=this.baseCanvas.getBounds(),r=n.width/2,o=n.height/2,a=r-t*this.baseCanvas.transform.scale,s=o-e*this.baseCanvas.transform.scale;return this.updateTransform({translateX:a,translateY:s})})}getConfig(){return{...this.config}}updateConfig(t){this.config=C({...this.config,...t})}cleanup(){this.cleanupFunctions.forEach(t=>{try{t()}catch(t){console.warn("Error during cleanup:",t)}}),this.cleanupFunctions=[],this.removeAllListeners()}on(t,e){this.listen.on(t,e)}off(t,e){this.listen.off(t,e)}emit(t,e){this.listen.emit(t,e)}removeAllListeners(){this.listen.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";const e="canvas-container",t="transform-layer",n="content-layer";function r(e,r){const o=Array.from(e.children);let a=e.querySelector(`.${t}`);a||(a=document.createElement("div"),a.className=t,e.appendChild(a)),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"}(a,r);let s=a.querySelector(`.${n}`);return s||(s=document.createElement("div"),s.className=n,a.appendChild(s),function(e,n,r){e.forEach(e=>{e===r||e.classList.contains(t)||n.appendChild(e)})}(o,s,a)),function(e){e.style.position="relative",e.style.width="100%",e.style.height="100%",e.style.pointerEvents="auto"}(s),{transformLayer:a,contentLayer:s}}function o(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 a(e,t){return Math.max(t.minZoom,Math.min(t.maxZoom,e))}function s(e,t,n){return new DOMMatrix([e,0,0,e,t,n])}function i(e,t,n,r,o){const s=o.enableRulers?-o.rulerSize:0,i=n||{scale:1,translateX:s,translateY:s},{scale:l,translateX:c,translateY:u}=i,d=a(l*r,o);if(Math.abs(d-l)<.001)return{scale:l,translateX:c,translateY:u};return{scale:d,translateX:e-(e-c)/l*d,translateY:t-(t-u)/l*d}}function l(e,t){return t(t=>a(t,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 m(e,t,n,r,o){const a=null!==e.container.querySelector(".canvas-ruler");return o(a?t-r:t,a?n-r:n)}function g(e,t){if("dark"===e.themeMode){return e[`${t}Dark`]}return e[t]}const f={width:8e3,height:8e3,enableAcceleration:!0,enableZoom:!0,enablePan:!0,enableTouch:!0,enableKeyboard:!0,limitKeyboardEventsToCanvas:!1,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",onTransformUpdate:()=>{}};function p(e){try{const t=e.container,n=e.config,r=e.transform||{scale:1,translateX:0,translateY:0},a=t.getBoundingClientRect(),i=a.width||t.clientWidth||0,l=a.height||t.clientHeight||0,c=h({container:t},n.rulerSize,e=>Math.max(0,i-e)),u=h({container:t},n.rulerSize,e=>Math.max(0,l-e)),d=n.width||f.width,m=n.height||f.height,g=function(e,t,n,r,a){const i=o(0,0,s(a.scale,a.translateX,a.translateY)),l=o(e,t,s(a.scale,a.translateX,a.translateY));return{x:Math.max(0,Math.min(n,i.x)),y:Math.max(0,Math.min(r,i.y)),width:Math.max(0,Math.min(n-i.x,l.x-i.x)),height:Math.max(0,Math.min(r-i.y,l.y-i.y))}}(c,u,d,m,r);return{width:c,height:u,contentWidth:d,contentHeight:m,scale:r.scale,translateX:r.translateX,translateY:r.translateY,visibleArea:g,scaledContentWidth:d*r.scale,scaledContentHeight:m*r.scale,canPanLeft:r.translateX<0,canPanRight:r.translateX+d*r.scale>c,canPanUp:r.translateY<0,canPanDown:r.translateY+m*r.scale>u,canZoomIn:r.scale<3.5,canZoomOut:r.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 v(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 y(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 b(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{y(e,t)}}function w(t,n){if("static"===getComputedStyle(t).position&&(t.style.position="relative"),t.style.overflow="hidden",t.style.cursor="grab",t.style.overscrollBehavior="none",n){const e=g(n,"canvasBackgroundColor");t.style.backgroundColor=e}t.hasAttribute("tabindex")||t.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)}(t),t.classList.contains(e)||t.classList.add(e)}function x(e,t){if(!e?.appendChild)return console.error("Invalid container element provided to createCanvas"),null;try{w(e,t);const{transformLayer:n,contentLayer:a}=r(e,t);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}}(n);const c=t.enableRulers?-t.rulerSize:0,d={scale:1,translateX:c,translateY:c};v(n,s(d.scale,d.translateX,d.translateY));return{container:e,transformLayer:n,contentLayer:a,config:t,transform:d,getBounds:function(){return p(this)},updateTransform:function(e){this.transform={...this.transform,...e};const t=s(this.transform.scale,this.transform.translateX,this.transform.translateY),n=v(this.transformLayer,t);return u(this.config,"onTransformUpdate",()=>{this.config.onTransformUpdate(this.transform)}),n},reset:function(){return this.updateTransform({scale:1,translateX:0,translateY:0})},handleResize:function(){return!0},setZoom:function(e){const t=l(this.config,t=>t(e));return this.updateTransform({scale:t})},canvasToContent:function(e,t){return o(e,t,s(this.transform.scale,this.transform.translateX,this.transform.translateY))},zoomToPoint:function(e,t,n){return b(this.transformLayer,this.config,()=>{const r=i(e,t,this.transform,n/this.transform.scale,this.config);return this.updateTransform(r)})},resetView:function(){return b(this.transformLayer,this.config,()=>h(this,this.config.rulerSize,e=>{const t={scale:1,translateX:-1*e,translateY:-1*e};return this.updateTransform(t)}))},zoomToFitContent:function(){return b(this.transformLayer,this.config,()=>{const e=this.getBounds(),t=e.width/this.config.width,n=e.height/this.config.height,r=l(this.config,e=>e(.9*Math.min(t,n))),o=this.config.width*r,a=this.config.height*r,s=(e.width-o)/2,i=(e.height-a)/2;return this.updateTransform({scale:r,translateX:s,translateY:i})})}}}catch(e){return console.error("Failed to create canvas:",e),null}}function C(e={}){const t={...f,...e};return("number"!=typeof t.width||t.width<=0)&&(console.warn("Invalid width, using default"),t.width=f.width),("number"!=typeof t.height||t.height<=0)&&(console.warn("Invalid height, using default"),t.height=f.height),("number"!=typeof t.zoomSpeed||t.zoomSpeed<=0)&&(console.warn("Invalid zoomSpeed, using default"),t.zoomSpeed=f.zoomSpeed),("number"!=typeof t.minZoom||t.minZoom<=0)&&(console.warn("Invalid minZoom, using default"),t.minZoom=f.minZoom),("number"!=typeof t.maxZoom||t.maxZoom<=t.minZoom)&&(console.warn("Invalid maxZoom, using default"),t.maxZoom=f.maxZoom),("number"!=typeof t.keyboardPanStep||t.keyboardPanStep<=0)&&(console.warn("Invalid keyboardPanStep, using default"),t.keyboardPanStep=f.keyboardPanStep),("number"!=typeof t.keyboardFastMultiplier||t.keyboardFastMultiplier<=0)&&(console.warn("Invalid keyboardFastMultiplier, using default"),t.keyboardFastMultiplier=f.keyboardFastMultiplier),("number"!=typeof t.clickZoomLevel||t.clickZoomLevel<=0)&&(console.warn("Invalid clickZoomLevel, using default"),t.clickZoomLevel=f.clickZoomLevel),("number"!=typeof t.rulerFontSize||t.rulerFontSize<=0)&&(console.warn("Invalid rulerFontSize, using default"),t.rulerFontSize=f.rulerFontSize),("number"!=typeof t.rulerSize||t.rulerSize<=0)&&(console.warn("Invalid rulerSize, using default"),t.rulerSize=f.rulerSize),t}class k{constructor(){this.listeners=new Map}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){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()}}const T=300,S=5;function D(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 z(e,t){let n=0,r=0;function o(o){const a=e.container.getBoundingClientRect(),s=o.clientX-a.left,i=o.clientY-a.top;!function(e,t,n,r,o){h(e,t,e=>o(n-e,r-e))}(e,t.rulerSize,s,i,(e,t)=>{n=e,r=t})}function s(o){if(!(o instanceof KeyboardEvent))return;if(t.limitKeyboardEventsToCanvas&&document.activeElement!==e.container)return;const s=o.shiftKey,l=t.keyboardPanStep*(s?t.keyboardFastMultiplier:1);let c=!1;const u={};switch(o.key){case"ArrowLeft":u.translateX=e.transform.translateX+l,c=!0;break;case"ArrowRight":u.translateX=e.transform.translateX-l,c=!0;break;case"ArrowUp":u.translateY=e.transform.translateY+l,c=!0;break;case"ArrowDown":u.translateY=e.transform.translateY-l,c=!0;break;case"=":case"+":{const n=t.enableAdaptiveSpeed?D(e,t.keyboardZoomStep):t.keyboardZoomStep;u.scale=a(e.transform.scale*(1+n),t),c=!0}break;case"-":{const n=t.enableAdaptiveSpeed?D(e,t.keyboardZoomStep):t.keyboardZoomStep;u.scale=a(e.transform.scale*(1-n),t),c=!0}break;case"0":if(o.metaKey||o.ctrlKey){const o=1/e.transform.scale,a=i(n,r,e.transform,o,t);Object.assign(u,a),c=!0}break;case"g":case"G":e.toggleGrid&&e.toggleGrid(),c=!0;break;case"r":case"R":o.metaKey||o.ctrlKey||o.altKey||!e.toggleRulers||(e.toggleRulers(),c=!0)}c&&(o.preventDefault(),Object.keys(u).length>0&&e.updateTransform(u))}const l=t.limitKeyboardEventsToCanvas?e.container:document;return l.addEventListener("keydown",s),e.container.addEventListener("mousemove",o),()=>{l.removeEventListener("keydown",s),e.container.removeEventListener("mousemove",o)}}function M(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 L(e,t,n,r,o){o.setIsDragging(!1),o.setDragButton(-1),M(e,t,n,r,!1)}function R(e,t,n,r,o,a,s,i,l,c){a&&e.button===s&&L(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<T&&!o&&!a&&l){e.preventDefault();const r=t.container.getBoundingClientRect(),o=e.clientX-r.left,a=e.clientY-r.top,{clickX:s,clickY:i}=m(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};b(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 Y(e,t,n=!0){let r=!0,o=!1,a=0,s=0,i=-1,l=!1,c=0,u=0,h=0,m=!1;const g={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=>{m=e},setLastMouseX:e=>{a=e},setLastMouseY:e=>{s=e}},f=n=>{!function(e,t,n,r,o,a){n.requireSpaceForMouseDrag&&" "===e.key&&(a.setIsSpacePressed(!0),M(t,n,r,!0,o))}(n,e,t,r,o,{setIsSpacePressed:g.setIsSpacePressed})},p=n=>{!function(e,t,n,r,o,a){n.requireSpaceForMouseDrag&&" "===e.key&&(a.setIsSpacePressed(!1),M(t,n,r,!1,o),o&&L(t,n,r,!1,{setIsDragging:a.setIsDragging,setDragButton:a.setDragButton}))}(n,e,t,r,o,{setIsSpacePressed:g.setIsSpacePressed,setIsDragging:g.setIsDragging,setDragButton:g.setDragButton})},v=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),M(t,n,r,o,!1))}(n,e,t,r,l,g)},y=t=>{!function(e,t,n,r,o,a,s,i,l,c){if(o>0){const t=Math.abs(e.clientX-a),o=Math.abs(e.clientY-s);(t>S||o>S)&&(c.setHasDragged(!0),!r&&n&&c.setIsDragging(!0))}if(!r||!n)return;e.preventDefault(),d((...e)=>{const o=e[0];if(!r||!n)return;const a=o.clientX-i,s=o.clientY-l,u={translateX:t.transform.translateX+a,translateY:t.transform.translateY+s};t.updateTransform(u),c.setLastMouseX(o.clientX),c.setLastMouseY(o.clientY)})(e)}(t,e,r,o,c,u,h,a,s,{setHasDragged:g.setHasDragged,setIsDragging:g.setIsDragging,setLastMouseX:g.setLastMouseX,setLastMouseY:g.setLastMouseY})},b=n=>{R(n,e,t,r,l,o,i,c,m,{setIsDragging:g.setIsDragging,setDragButton:g.setDragButton,setMouseDownTime:g.setMouseDownTime,setHasDragged:g.setHasDragged})},w=()=>{!function(e,t,n,r,o,a){o&&L(e,t,n,r,a)}(e,t,r,l,o,{setIsDragging:g.setIsDragging,setDragButton:g.setDragButton})};e.container.addEventListener("mousedown",v),document.addEventListener("mousemove",y),document.addEventListener("mouseup",b),e.container.addEventListener("mouseleave",w),t.requireSpaceForMouseDrag&&(document.addEventListener("keydown",f),document.addEventListener("keyup",p)),M(e,t,r,l,o);const x=()=>{e.container.removeEventListener("mousedown",v),document.removeEventListener("mousemove",y),document.removeEventListener("mouseup",b),e.container.removeEventListener("mouseleave",w),t.requireSpaceForMouseDrag&&(document.removeEventListener("keydown",f),document.removeEventListener("keyup",p))};return n?{cleanup:x,enable:()=>(r=!0,M(e,t,r,l,o),!0),disable:()=>(r=!1,o&&L(e,t,r,l,{setIsDragging:g.setIsDragging,setDragButton:g.setDragButton}),M(e,t,r,l,o),!0),isEnabled:()=>r}:x}function E(e,t){return{x:(e.clientX+t.clientX)/2,y:(e.clientY+t.clientY)/2}}function X(e,t){const n=e.clientX-t.clientX,r=e.clientY-t.clientY;return Math.sqrt(n*n+r*r)}function F(e,t,n,r){const o=i(n,r,e.transform,t,e.config);return e.updateTransform(o)}function B(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=X(r[0],r[1]),o=E(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,F(t,r,s,i)}n.lastDistance=e,n.lastCenter=o}n.touches=r})(r)}function $(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=X(t.touches[0],t.touches[1]),t.lastCenter=E(t.touches[0],t.touches[1]))}(e,t)},r=n=>{B(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 P(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 Z(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 y(e.transformLayer,e.config),e.updateTransform(s)}catch(e){return console.error("Error handling trackpad pan:",e),!1}}))(e),r=r=>P(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}=m(t,o,a,n.rulerSize,(e,t)=>({mouseX:e,mouseY:t})),l=n.zoomSpeed,c=P(e);if(!c.isZoomGesture)return!1;let u=n.enableAdaptiveSpeed?D(t,l):l;if(c.isTrackpadPinch){const e=.05*n.zoomSpeed;u=n.enableAdaptiveSpeed?D(t,e):e}return F(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 I=100,O=1e3,A=1001,_=4,H=4,q=100,G=100,N=20,K=200;function V(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: ${O};\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: ${O};\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: ${A};\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: ${I};\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 U(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 W(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: ${_}px;\n\t\tbackground: var(--ruler-tick-color);\n\t`,e.appendChild(a);if(t%q===0){const r=document.createElement("div");r.style.cssText=`\n\t\t\tposition: absolute;\n\t\t\tleft: ${n}px;\n\t\t\tbottom: ${_+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 j(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: ${H}px;\n\t\theight: 1px;\n\t\tbackground: var(--ruler-tick-color);\n\t`,e.appendChild(a);if(t%q===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: ${H+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 J(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,m=h+u/s;!function(e,t,n,r,o,a){const s=r,i=U(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&&W(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=U(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&&j(l,e,n,0,a)}e.innerHTML="",e.appendChild(l)}(n,h,m,u,s,o),r&&function(e,t,n,r){let o=G*t;for(;o<N;)o*=2;for(;o>K;)o/=2;e.style.backgroundSize=`${o}px ${o}px`,e.style.backgroundPosition=`${n%o}px ${r%o}px`}(r,s,i,l)}function Q(e,t){const n=g(t,"rulerBackgroundColor"),r=g(t,"rulerBorderColor"),o=g(t,"rulerTextColor"),a=g(t,"rulerTickColor"),s=g(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 ee(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&&J(e,n.horizontalRuler,n.verticalRuler,n.gridOverlay,t)};try{return n=V(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),Q(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||Q(n,e)},show:()=>{n.horizontalRuler&&(n.horizontalRuler.style.display="block"),n.verticalRuler&&(n.verticalRuler.style.display="block"),n.cornerBox&&(n.cornerBox.style.display="flex"),n.gridOverlay&&(n.gridOverlay.style.display="block")},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.cleanupFunctions=[],this.rulers=null,this.dragSetup=null,this._isReady=!1,this.listen=new k,!e)throw new Error("Container element is required");this.config=C(t);const n=x(e,this.config);if(!n)throw new Error("Failed to create canvas");this.baseCanvas=n,this.setupEventHandlers(),this._isReady=!0,this.listen.emit("ready",this)}setupEventHandlers(){try{u(this.config,"enableZoom",()=>{const e=Z(this,this.config);this.cleanupFunctions.push(e)}),(this.config.enablePan||this.config.enableClickToZoom)&&(this.dragSetup=Y(this,this.config,!0),this.cleanupFunctions.push(this.dragSetup.cleanup)),u(this.config,"enableKeyboard",()=>{const e=z(this,this.config);this.cleanupFunctions.push(e)}),u(this.config,"enableTouch",()=>{const e=$(this);this.cleanupFunctions.push(e)}),u(this.config,"enableRulers",()=>{this.rulers=ee(this.baseCanvas,this.config),this.cleanupFunctions.push(()=>{this.rulers&&this.rulers.destroy()})})}catch(e){throw console.error("Failed to set up event handlers:",e),this.cleanup(),e}}get container(){return this.baseCanvas.container}get transformLayer(){return this.baseCanvas.transformLayer}get contentLayer(){return this.baseCanvas.contentLayer}get transform(){return this.baseCanvas.transform}get isReady(){return this._isReady}get isTransforming(){return this.dragSetup?.isEnabled()||!1}get visibleBounds(){return this.getVisibleArea()}getBounds(){return this.baseCanvas.getBounds()}updateTransform(e){const t=this.baseCanvas.updateTransform(e);return t&&this.emitTransformEvents(),t}emitTransformEvents(){const e=this.baseCanvas.transform;this.listen.emit("transform",e),this.listen.emit("zoom",e.scale),this.listen.emit("pan",{x:e.translateX,y:e.translateY})}reset(){return this.baseCanvas.reset()}handleResize(){return this.baseCanvas.handleResize()}setZoom(e){return this.baseCanvas.setZoom(e)}canvasToContent(e,t){return this.baseCanvas.canvasToContent(e,t)}zoomToPoint(e,t,n){return b(this.transformLayer,this.config,()=>{const r=this.baseCanvas.zoomToPoint(e,t,n);return r&&this.emitTransformEvents(),r})}resetView(){return b(this.transformLayer,this.config,()=>{const e=!!this.baseCanvas.resetView&&this.baseCanvas.resetView();return e&&this.emitTransformEvents(),e})}zoomToFitContent(){return b(this.transformLayer,this.config,()=>{const e=this.baseCanvas.zoomToFitContent();return e&&this.emitTransformEvents(),e})}panLeft(e){const t=e??this.config.keyboardPanStep,n={translateX:this.baseCanvas.transform.translateX+t};return this.updateTransform(n)}panRight(e){const t=e??this.config.keyboardPanStep,n={translateX:this.baseCanvas.transform.translateX-t};return this.updateTransform(n)}panUp(e){const t=e??this.config.keyboardPanStep,n={translateY:this.baseCanvas.transform.translateY+t};return this.updateTransform(n)}panDown(e){const t=e??this.config.keyboardPanStep,n={translateY:this.baseCanvas.transform.translateY-t};return this.updateTransform(n)}zoomIn(e=.1){return b(this.transformLayer,this.config,()=>l(this.config,t=>{const n={scale:t(this.baseCanvas.transform.scale*(1+e))};return this.updateTransform(n)}))}zoomOut(e=.1){return b(this.transformLayer,this.config,()=>l(this.config,t=>{const n={scale:t(this.baseCanvas.transform.scale*(1-e))};return this.updateTransform(n)}))}resetZoom(){return this.resetView()}enableMouseDrag(){return this.dragSetup?.enable()??!1}disableMouseDrag(){return this.dragSetup?.disable()??!1}isMouseDragEnabled(){return this.dragSetup?.isEnabled()??!1}toggleGrid(){return!!this.rulers?.toggleGrid&&(this.rulers.toggleGrid(),!0)}showGrid(){return!!this.rulers?.gridOverlay&&(this.rulers.gridOverlay.style.display="block",!0)}hideGrid(){return!!this.rulers?.gridOverlay&&(this.rulers.gridOverlay.style.display="none",!0)}isGridVisible(){return!!this.rulers?.gridOverlay&&"none"!==this.rulers.gridOverlay.style.display}toggleRulers(){if(this.rulers){return this.areRulersVisible()?this.rulers.hide():this.rulers.show(),!0}return!1}showRulers(){return!!this.rulers&&(this.rulers.show(),!0)}hideRulers(){return!!this.rulers&&(this.rulers.hide(),!0)}areRulersVisible(){return!!this.rulers?.horizontalRuler&&"none"!==this.rulers.horizontalRuler.style.display}centerContent(){return b(this.transformLayer,this.config,()=>{const e=this.baseCanvas.getBounds(),t=(e.width-e.contentWidth*this.baseCanvas.transform.scale)/2,n=(e.height-e.contentHeight*this.baseCanvas.transform.scale)/2;return this.updateTransform({translateX:t,translateY:n})})}fitToScreen(){return b(this.transformLayer,this.config,()=>{const e=this.baseCanvas.zoomToFitContent();return e&&this.emitTransformEvents(),e})}getVisibleArea(){return this.baseCanvas.getBounds().visibleArea}isPointVisible(e,t){const n=this.getVisibleArea();return e>=n.x&&e<=n.x+n.width&&t>=n.y&&t<=n.y+n.height}scrollToPoint(e,t){return b(this.transformLayer,this.config,()=>{const n=this.baseCanvas.getBounds(),r=n.width/2,o=n.height/2,a=r-e*this.baseCanvas.transform.scale,s=o-t*this.baseCanvas.transform.scale;return this.updateTransform({translateX:a,translateY:s})})}getConfig(){return{...this.config}}updateConfig(e){this.config=C({...this.config,...e})}updateThemeMode(e){const t={...this.config,themeMode:e};this.config=C(t);const n=g(this.config,"canvasBackgroundColor");this.baseCanvas.container.style.backgroundColor=n,this.rulers&&this.rulers.updateTheme(this.config)}cleanup(){this.cleanupFunctions.forEach(e=>{try{e()}catch(e){console.warn("Error during cleanup:",e)}}),this.cleanupFunctions=[],this.removeAllListeners()}on(e,t){this.listen.on(e,t)}off(e,t){this.listen.off(e,t)}emit(e,t){this.listen.emit(e,t)}removeAllListeners(){this.listen.removeAllListeners()}destroy(){this.cleanup(),window.__markupCanvasTransitionTimeout&&clearTimeout(window.__markupCanvasTransitionTimeout)}}});
@@ -25,15 +25,24 @@ export interface MarkupCanvasConfig {
25
25
  requireOptionForClickZoom?: boolean;
26
26
  enableRulers?: boolean;
27
27
  enableGrid?: boolean;
28
+ showRulers?: boolean;
29
+ showGrid?: boolean;
28
30
  gridColor?: string;
31
+ canvasBackgroundColor?: string;
32
+ canvasBackgroundColorDark?: string;
29
33
  rulerBackgroundColor?: string;
30
34
  rulerBorderColor?: string;
31
35
  rulerTextColor?: string;
32
- rulerMajorTickColor?: string;
33
- rulerMinorTickColor?: string;
36
+ rulerTickColor?: string;
34
37
  rulerFontSize?: number;
35
38
  rulerFontFamily?: string;
36
39
  rulerUnits?: string;
37
40
  rulerSize?: number;
41
+ rulerBackgroundColorDark?: string;
42
+ rulerBorderColorDark?: string;
43
+ rulerTextColorDark?: string;
44
+ rulerTickColorDark?: string;
45
+ gridColorDark?: string;
46
+ themeMode?: "light" | "dark";
38
47
  onTransformUpdate?: (transform: Transform) => void;
39
48
  }
@@ -1,10 +1,12 @@
1
1
  import type { CanvasBounds, Transform } from "./canvas.js";
2
+ import type { MarkupCanvasConfig } from "./config.js";
2
3
  export interface RulerSystem {
3
4
  horizontalRuler: HTMLElement;
4
5
  verticalRuler: HTMLElement;
5
6
  cornerBox: HTMLElement;
6
7
  gridOverlay?: HTMLElement;
7
8
  update: () => void;
9
+ updateTheme: (config: Required<MarkupCanvasConfig>) => void;
8
10
  show: () => void;
9
11
  hide: () => void;
10
12
  toggleGrid: () => void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@markup-canvas/core",
3
- "version": "1.0.6",
3
+ "version": "1.0.8",
4
4
  "description": "High-performance canvas-like container with pan and zoom capabilities",
5
5
  "type": "module",
6
6
  "main": "dist/markup-canvas.cjs.js",
@@ -35,11 +35,11 @@
35
35
  "@biomejs/biome": "2.2.6",
36
36
  "@rollup/plugin-alias": "^5.1.1",
37
37
  "@rollup/plugin-commonjs": "^28.0.8",
38
- "@rollup/plugin-node-resolve": "^15.2.3",
38
+ "@rollup/plugin-node-resolve": "^16.0.3",
39
39
  "@rollup/plugin-terser": "^0.4.4",
40
- "@rollup/plugin-typescript": "^11.1.6",
40
+ "@rollup/plugin-typescript": "^12.1.4",
41
41
  "glob": "^11.0.3",
42
- "rollup": "^4.52.4",
42
+ "rollup": "^4.52.5",
43
43
  "tslib": "^2.8.1",
44
44
  "ttypescript": "^1.5.15",
45
45
  "typescript": "^5.9.3",
@@ -2,7 +2,7 @@ import { createCanvas } from "@/lib/canvas/index.js";
2
2
  import { createMarkupCanvasConfig } from "@/lib/config/createMarkupCanvasConfig.js";
3
3
  import { EventEmitter } from "@/lib/events/EventEmitter.js";
4
4
  import { setupKeyboardEvents, setupMouseEvents, setupTouchEvents, setupWheelEvents } from "@/lib/events/index.js";
5
- import { withClampedZoom, withFeatureEnabled } from "@/lib/helpers/index.js";
5
+ import { getThemeValue, withClampedZoom, withFeatureEnabled } from "@/lib/helpers/index.js";
6
6
  import { createRulers } from "@/lib/rulers/index.js";
7
7
  import { withTransition } from "@/lib/transition/withTransition.js";
8
8
  import type {
@@ -392,6 +392,24 @@ export class MarkupCanvas implements Canvas {
392
392
  this.config = createMarkupCanvasConfig({ ...this.config, ...newConfig });
393
393
  }
394
394
 
395
+ // Theme management
396
+ updateThemeMode(mode: "light" | "dark"): void {
397
+ const newConfig = {
398
+ ...this.config,
399
+ themeMode: mode,
400
+ };
401
+ this.config = createMarkupCanvasConfig(newConfig);
402
+
403
+ // Update canvas background color
404
+ const backgroundColor = getThemeValue(this.config, "canvasBackgroundColor");
405
+ this.baseCanvas.container.style.backgroundColor = backgroundColor;
406
+
407
+ // Update rulers if they exist
408
+ if (this.rulers) {
409
+ this.rulers.updateTheme(this.config);
410
+ }
411
+ }
412
+
395
413
  // Cleanup method
396
414
  cleanup(): void {
397
415
  this.cleanupFunctions.forEach((cleanup) => {
@@ -14,7 +14,7 @@ export function createCanvas(container: HTMLElement, config: Required<MarkupCanv
14
14
  }
15
15
 
16
16
  try {
17
- setupCanvasContainer(container);
17
+ setupCanvasContainer(container, config);
18
18
 
19
19
  const { transformLayer, contentLayer } = createCanvasLayers(container, config);
20
20
 
@@ -1,7 +1,9 @@
1
1
  import { checkContainerDimensions } from "@/lib/canvas/checkContainerDimensions";
2
2
  import { CANVAS_CONTAINER_CLASS } from "@/lib/constants";
3
+ import { getThemeValue } from "@/lib/helpers/index.js";
4
+ import type { MarkupCanvasConfig } from "@/types/index.js";
3
5
 
4
- export function setupCanvasContainer(container: HTMLElement): void {
6
+ export function setupCanvasContainer(container: HTMLElement, config?: Required<MarkupCanvasConfig>): void {
5
7
  const currentPosition = getComputedStyle(container).position;
6
8
  if (currentPosition === "static") {
7
9
  container.style.position = "relative";
@@ -10,6 +12,12 @@ export function setupCanvasContainer(container: HTMLElement): void {
10
12
  container.style.cursor = "grab";
11
13
  container.style.overscrollBehavior = "none";
12
14
 
15
+ // Apply canvas background color
16
+ if (config) {
17
+ const backgroundColor = getThemeValue(config, "canvasBackgroundColor");
18
+ container.style.backgroundColor = backgroundColor;
19
+ }
20
+
13
21
  if (!container.hasAttribute("tabindex")) {
14
22
  container.setAttribute("tabindex", "0");
15
23
  }