@markdy/renderer-dom 1.0.21 → 1.0.23

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 (2) hide show
  1. package/dist/index.js +137 -41
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -625,9 +625,68 @@ function circleBoundaryRoute(from, to) {
625
625
  { x: toCenter.x - ux * toRadius, y: toCenter.y - uy * toRadius }
626
626
  ]);
627
627
  }
628
+ function snapPortToNodeShape(node, port, neighbor, isSource) {
629
+ if (!node.shape || node.shape === "card" || node.shape === "rounded" || node.shape === "terminal" || node.shape === "container") {
630
+ return port;
631
+ }
632
+ const cx = node.x + node.width / 2;
633
+ const cy = node.y + node.height / 2;
634
+ const hw = node.width / 2;
635
+ const hh = node.height / 2;
636
+ if (node.shape === "diamond") {
637
+ const isVert = Math.abs(port.x - neighbor.x) < 0.01;
638
+ const isHoriz = Math.abs(port.y - neighbor.y) < 0.01;
639
+ if (isVert) {
640
+ const goingDown = isSource ? neighbor.y > port.y : port.y > neighbor.y;
641
+ const boundaryY = goingDown ? cy + hh * (1 - Math.min(1, Math.abs(port.x - cx) / hw)) : cy - hh * (1 - Math.min(1, Math.abs(port.x - cx) / hw));
642
+ return { x: port.x, y: Math.round(boundaryY * 10) / 10 };
643
+ }
644
+ if (isHoriz) {
645
+ const goingRight = isSource ? neighbor.x > port.x : port.x > neighbor.x;
646
+ const boundaryX = goingRight ? cx + hw * (1 - Math.min(1, Math.abs(port.y - cy) / hh)) : cx - hw * (1 - Math.min(1, Math.abs(port.y - cy) / hh));
647
+ return { x: Math.round(boundaryX * 10) / 10, y: port.y };
648
+ }
649
+ }
650
+ if (node.shape === "circle") {
651
+ const r = Math.min(node.width, node.height) / 2;
652
+ const isVert = Math.abs(port.x - neighbor.x) < 0.01;
653
+ const isHoriz = Math.abs(port.y - neighbor.y) < 0.01;
654
+ if (isVert) {
655
+ const goingDown = isSource ? neighbor.y > port.y : port.y > neighbor.y;
656
+ return { x: cx, y: goingDown ? cy + r : cy - r };
657
+ }
658
+ if (isHoriz) {
659
+ const goingRight = isSource ? neighbor.x > port.x : port.x > neighbor.x;
660
+ return { x: goingRight ? cx + r : cx - r, y: cy };
661
+ }
662
+ }
663
+ if (node.shape === "pill") {
664
+ const r = node.height / 2;
665
+ const isVert = Math.abs(port.x - neighbor.x) < 0.01;
666
+ const isHoriz = Math.abs(port.y - neighbor.y) < 0.01;
667
+ if (isHoriz) {
668
+ const goingRight = isSource ? neighbor.x > port.x : port.x > neighbor.x;
669
+ return { x: goingRight ? node.x + node.width : node.x, y: cy };
670
+ }
671
+ if (isVert) {
672
+ const goingDown = isSource ? neighbor.y > port.y : port.y > neighbor.y;
673
+ const clampedX = Math.max(node.x + r, Math.min(node.x + node.width - r, port.x));
674
+ return { x: clampedX, y: goingDown ? node.y + node.height : node.y };
675
+ }
676
+ }
677
+ return port;
678
+ }
679
+ function snapRouteEndpointsToShapes(points, from, to) {
680
+ if (points.length < 2) return points;
681
+ const out = [...points];
682
+ out[0] = snapPortToNodeShape(from, out[0], out[1], true);
683
+ out[out.length - 1] = snapPortToNodeShape(to, out[out.length - 1], out[out.length - 2], false);
684
+ return dedupePoints(out);
685
+ }
628
686
  function routeEdgePoints(from, to, routeObstacles, bounds, lane) {
629
687
  if (from.shape === "circle" && to.shape === "circle") return circleBoundaryRoute(from, to);
630
- return routeOrthogonal(boxRect(from), boxRect(to), routeObstacles, bounds, lane);
688
+ const raw = routeOrthogonal(boxRect(from), boxRect(to), routeObstacles, bounds, lane);
689
+ return snapRouteEndpointsToShapes(raw, from, to);
631
690
  }
632
691
  function ensureEdgeLayer(scene) {
633
692
  const existing = scene.querySelector(`svg[${EDGE_LAYER_ATTR}='1']`);
@@ -1782,8 +1841,30 @@ function ensureNodeStyles(doc) {
1782
1841
  opacity: 1;
1783
1842
  transform: translateY(0);
1784
1843
  }
1844
+ .markdy-node[data-shape="diamond"],
1845
+ .markdy-node[data-shape="diamond"][data-visible="1"],
1846
+ .markdy-node[data-shape="diamond"][data-focal="1"],
1847
+ .markdy-node[data-shape="diamond"][data-focused="1"],
1848
+ .markdy-node[data-shape="diamond"][data-glow="1"],
1849
+ .markdy-scene-root .markdy-node[data-shape="diamond"],
1850
+ .markdy-scene-root .markdy-node[data-shape="diamond"][data-visible="1"],
1851
+ .markdy-scene-root .markdy-node[data-shape="diamond"][data-focal="1"],
1852
+ .markdy-scene-root .markdy-node[data-shape="diamond"][data-focused="1"],
1853
+ .markdy-scene-root .markdy-node[data-shape="diamond"][data-glow="1"],
1854
+ .markdy-scene-root[data-flat="1"] .markdy-node[data-shape="diamond"],
1855
+ .markdy-scene-root[data-flat="1"] .markdy-node[data-shape="diamond"][data-visible="1"],
1856
+ .markdy-scene-root[data-flat="1"] .markdy-node[data-shape="diamond"][data-focal="1"],
1857
+ .markdy-scene-root[data-markdy-theme="terminal"] .markdy-node[data-shape="diamond"],
1858
+ .markdy-scene-root[data-markdy-theme="terminal"] .markdy-node[data-shape="diamond"][data-focal="1"],
1859
+ .markdy-scene-root[data-markdy-theme="sketchy"] .markdy-node[data-shape="diamond"],
1860
+ .markdy-scene-root[data-markdy-theme="sketchy"] .markdy-node[data-shape="diamond"][data-focal="1"],
1861
+ .markdy-scene-root[data-markdy-theme="nebula"] .markdy-node[data-shape="diamond"],
1862
+ .markdy-scene-root[data-markdy-theme="nebula"] .markdy-node[data-shape="diamond"][data-focal="1"] {
1863
+ border: none;
1864
+ box-shadow: none;
1865
+ }
1785
1866
  .markdy-node[data-shape="diamond"] {
1786
- border-radius: 4px;
1867
+ border-radius: 0;
1787
1868
  transform: rotate(0deg);
1788
1869
  clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);
1789
1870
  filter: drop-shadow(0 0 1px var(--md-hairline, rgba(15, 23, 42, 0.2))) drop-shadow(0 4px 12px var(--md-shadow, rgba(2, 6, 23, 0.15)));
@@ -1791,6 +1872,12 @@ function ensureNodeStyles(doc) {
1791
1872
  .markdy-node[data-shape="diamond"][data-focal="1"] {
1792
1873
  filter: drop-shadow(0 0 1.5px var(--md-accent)) drop-shadow(0 4px 14px var(--md-shadow, rgba(2, 6, 23, 0.15)));
1793
1874
  }
1875
+ .markdy-node[data-shape="diamond"][data-focused="1"] {
1876
+ filter: drop-shadow(0 0 2px var(--md-accent)) drop-shadow(0 0 14px color-mix(in srgb, var(--md-accent) 60%, transparent));
1877
+ }
1878
+ .markdy-node[data-shape="diamond"][data-glow="1"] {
1879
+ filter: drop-shadow(0 0 2px color-mix(in srgb, var(--md-glow-color, var(--md-accent)) 70%, transparent)) drop-shadow(0 0 24px color-mix(in srgb, var(--md-glow-color, var(--md-accent)) 55%, transparent));
1880
+ }
1794
1881
  .markdy-node[data-shape="diamond"] .markdy-node__body {
1795
1882
  justify-content: center;
1796
1883
  padding: 6px 16%;
@@ -2722,6 +2809,13 @@ function ensureSceneStyles(doc) {
2722
2809
  transform: translateY(8px);
2723
2810
  will-change: opacity, transform;
2724
2811
  }
2812
+ .markdy-diagram-root {
2813
+ position: relative;
2814
+ display: flex;
2815
+ flex-direction: column;
2816
+ box-sizing: border-box;
2817
+ width: 100%;
2818
+ }
2725
2819
  .markdy-footer {
2726
2820
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
2727
2821
  position: relative;
@@ -3191,37 +3285,13 @@ function ensureSceneStyles(doc) {
3191
3285
  color: #64748b !important;
3192
3286
  }
3193
3287
  /* Fullscreen & Fallback Pseudo-Fullscreen Views */
3288
+ .markdy-diagram-root:fullscreen,
3289
+ .markdy-diagram-root:-webkit-full-screen,
3290
+ .markdy-diagram-root:-moz-full-screen,
3291
+ .markdy-diagram-root:-ms-fullscreen,
3292
+ .markdy-viewport:fullscreen,
3293
+ .markdy-viewport:-webkit-full-screen,
3194
3294
  .markdy-fullscreen-host,
3195
- :fullscreen {
3196
- background-color: var(--md-canvas, #0b101b) !important;
3197
- width: 100vw !important;
3198
- height: 100vh !important;
3199
- max-width: 100vw !important;
3200
- max-height: 100vh !important;
3201
- box-sizing: border-box !important;
3202
- display: flex !important;
3203
- flex-direction: column !important;
3204
- justify-content: space-between !important;
3205
- align-items: center !important;
3206
- padding: 16px 20px 12px !important;
3207
- overflow: hidden !important;
3208
- }
3209
- .markdy-fullscreen-host .markdy-viewport,
3210
- :fullscreen .markdy-viewport {
3211
- flex: 1 1 auto !important;
3212
- width: 100% !important;
3213
- height: 100% !important;
3214
- max-width: 100% !important;
3215
- max-height: calc(100vh - 64px) !important;
3216
- }
3217
- .markdy-fullscreen-host .markdy-footer,
3218
- :fullscreen .markdy-footer {
3219
- flex-shrink: 0 !important;
3220
- width: 100% !important;
3221
- max-width: 1400px !important;
3222
- margin: 0 auto !important;
3223
- padding: 8px 12px 4px !important;
3224
- }
3225
3295
  .markdy--pseudo-fullscreen {
3226
3296
  position: fixed !important;
3227
3297
  inset: 0 !important;
@@ -3231,21 +3301,34 @@ function ensureSceneStyles(doc) {
3231
3301
  max-width: 100vw !important;
3232
3302
  max-height: 100vh !important;
3233
3303
  background-color: var(--md-canvas, #0b101b) !important;
3304
+ box-sizing: border-box !important;
3234
3305
  display: flex !important;
3235
3306
  flex-direction: column !important;
3236
3307
  justify-content: space-between !important;
3237
3308
  align-items: center !important;
3238
3309
  padding: 16px 20px 12px !important;
3239
- box-sizing: border-box !important;
3240
3310
  overflow: hidden !important;
3241
3311
  }
3312
+ .markdy-diagram-root:fullscreen .markdy-viewport,
3313
+ .markdy-diagram-root:-webkit-full-screen .markdy-viewport,
3314
+ .markdy-diagram-root:-moz-full-screen .markdy-viewport,
3315
+ .markdy-diagram-root:-ms-fullscreen .markdy-viewport,
3316
+ .markdy-fullscreen-host .markdy-viewport,
3242
3317
  .markdy--pseudo-fullscreen .markdy-viewport {
3243
3318
  flex: 1 1 auto !important;
3244
3319
  width: 100% !important;
3245
3320
  height: 100% !important;
3246
3321
  max-width: 100% !important;
3247
3322
  max-height: calc(100vh - 64px) !important;
3323
+ display: flex !important;
3324
+ align-items: center !important;
3325
+ justify-content: center !important;
3248
3326
  }
3327
+ .markdy-diagram-root:fullscreen .markdy-footer,
3328
+ .markdy-diagram-root:-webkit-full-screen .markdy-footer,
3329
+ .markdy-diagram-root:-moz-full-screen .markdy-footer,
3330
+ .markdy-diagram-root:-ms-fullscreen .markdy-footer,
3331
+ .markdy-fullscreen-host .markdy-footer,
3249
3332
  .markdy--pseudo-fullscreen .markdy-footer {
3250
3333
  flex-shrink: 0 !important;
3251
3334
  width: 100% !important;
@@ -3447,6 +3530,16 @@ function createDiagram(opts) {
3447
3530
  const DEFAULT_RAINBOW = "hsl(0,90%,60%), hsl(45,90%,55%), hsl(90,80%,50%), hsl(180,80%,50%), hsl(270,80%,55%), hsl(330,90%,60%)";
3448
3531
  const totalDurationMs = plan.duration * 1e3;
3449
3532
  const durationSeconds = plan.duration;
3533
+ container.classList.add("markdy-diagram-root");
3534
+ Object.assign(container.style, {
3535
+ position: "relative",
3536
+ display: "flex",
3537
+ flexDirection: "column",
3538
+ boxSizing: "border-box",
3539
+ width: "100%"
3540
+ });
3541
+ if (container.style.aspectRatio) container.style.aspectRatio = "unset";
3542
+ if (container.style.overflow === "hidden") container.style.overflow = "visible";
3450
3543
  const viewport = document.createElement("div");
3451
3544
  viewport.className = "markdy-viewport";
3452
3545
  Object.assign(viewport.style, {
@@ -3511,8 +3604,7 @@ function createDiagram(opts) {
3511
3604
  padding: "6px 8px 2px",
3512
3605
  background: "transparent"
3513
3606
  });
3514
- if (container.parentNode) container.parentNode.insertBefore(footer, container.nextSibling);
3515
- else container.appendChild(footer);
3607
+ container.appendChild(footer);
3516
3608
  return footer;
3517
3609
  }
3518
3610
  let badge = null;
@@ -4057,8 +4149,11 @@ function createDiagram(opts) {
4057
4149
  removeFullscreenListeners?.();
4058
4150
  closeCodePanel?.();
4059
4151
  closeCodePanel = null;
4152
+ container.classList.remove("markdy-diagram-root");
4153
+ container.classList.remove("markdy-fullscreen-host");
4154
+ container.classList.remove("markdy--pseudo-fullscreen");
4060
4155
  if (progressEl?.parentNode === viewport) viewport.removeChild(progressEl);
4061
- if (footer?.parentNode) footer.parentNode.removeChild(footer);
4156
+ if (footer?.parentNode === container) container.removeChild(footer);
4062
4157
  if (viewport.parentNode === container) container.removeChild(viewport);
4063
4158
  }
4064
4159
  };
@@ -4366,10 +4461,10 @@ function createDiagram(opts) {
4366
4461
  const button = makeControlButton("Full", "Toggle fullscreen view", ICONS2.fullscreen);
4367
4462
  button.className = "markdy-control-fullscreen";
4368
4463
  button.setAttribute("aria-pressed", "false");
4369
- const host = footer && footer.parentElement ? footer.parentElement : container.parentElement ?? container;
4464
+ const host = container;
4370
4465
  let isPseudoFull = false;
4371
4466
  function syncFullscreenState() {
4372
- const isFull = isPseudoFull || document.fullscreenElement === host || document.fullscreenElement === container || document.fullscreenElement === viewport || document.webkitFullscreenElement === host || document.webkitFullscreenElement === container;
4467
+ const isFull = isPseudoFull || document.fullscreenElement === host || document.fullscreenElement === viewport || document.webkitFullscreenElement === host || document.webkitFullscreenElement === viewport || document.mozFullScreenElement === host || document.msFullscreenElement === host;
4373
4468
  button.setAttribute("aria-pressed", isFull ? "true" : "false");
4374
4469
  button.title = isFull ? "Exit fullscreen" : "Toggle fullscreen view";
4375
4470
  button.innerHTML = isFull ? `${ICONS2.fullscreen}Exit` : `${ICONS2.fullscreen}Full`;
@@ -4380,15 +4475,16 @@ function createDiagram(opts) {
4380
4475
  host.classList.remove("markdy--pseudo-fullscreen");
4381
4476
  }
4382
4477
  requestAnimationFrame(() => {
4478
+ scaleScene();
4383
4479
  applyViewportTransform();
4384
4480
  syncControls();
4385
4481
  });
4386
4482
  }
4387
4483
  async function toggleFullscreen() {
4388
4484
  try {
4389
- const isCurrentlyFull = isPseudoFull || document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement;
4485
+ const isCurrentlyFull = isPseudoFull || document.fullscreenElement === host || document.fullscreenElement === viewport || document.webkitFullscreenElement === host || document.mozFullScreenElement === host || document.msFullscreenElement === host;
4390
4486
  if (!isCurrentlyFull) {
4391
- const req = host.requestFullscreen?.bind(host) || host.webkitRequestFullscreen?.bind(host) || host.mozRequestFullScreen?.bind(host) || host.msRequestFullscreen?.bind(host) || container.requestFullscreen?.bind(container) || container.webkitRequestFullscreen?.bind(container);
4487
+ const req = host.requestFullscreen?.bind(host) || host.webkitRequestFullscreen?.bind(host) || host.mozRequestFullScreen?.bind(host) || host.msRequestFullscreen?.bind(host) || viewport.requestFullscreen?.bind(viewport) || viewport.webkitRequestFullscreen?.bind(viewport);
4392
4488
  if (req) {
4393
4489
  try {
4394
4490
  await req();
@@ -4414,7 +4510,7 @@ function createDiagram(opts) {
4414
4510
  }
4415
4511
  }
4416
4512
  }
4417
- } catch (err) {
4513
+ } catch {
4418
4514
  if (!isPseudoFull) {
4419
4515
  isPseudoFull = true;
4420
4516
  host.classList.add("markdy--pseudo-fullscreen");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@markdy/renderer-dom",
3
- "version": "1.0.21",
3
+ "version": "1.0.23",
4
4
  "description": "Browser renderer for diagram-native animated MarkdyScript architecture diagrams, built on the Web Animations API.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -45,14 +45,14 @@
45
45
  },
46
46
  "dependencies": {
47
47
  "html2canvas": "^1.4.1",
48
- "@markdy/core": "1.0.21"
48
+ "@markdy/core": "1.0.23"
49
49
  },
50
50
  "devDependencies": {
51
51
  "jsdom": "^29.1.1",
52
52
  "tsup": "^8.5.1",
53
53
  "typescript": "^5.9.3",
54
54
  "vitest": "^4.1.7",
55
- "@markdy/stdlib-systems": "1.0.21"
55
+ "@markdy/stdlib-systems": "1.0.23"
56
56
  },
57
57
  "scripts": {
58
58
  "build": "tsup",