@markdy/renderer-dom 1.0.12 → 1.0.14

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 +591 -82
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -1636,6 +1636,16 @@ function ensureNodeStyles(doc) {
1636
1636
  transform: rotate(0deg);
1637
1637
  clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);
1638
1638
  }
1639
+ .markdy-node[data-shape="diamond"] .markdy-node__body {
1640
+ justify-content: center;
1641
+ padding: 6px 16%;
1642
+ text-align: center;
1643
+ }
1644
+ .markdy-node[data-shape="diamond"] .markdy-node__label {
1645
+ flex: 0 1 auto;
1646
+ line-height: 1.18;
1647
+ text-align: center;
1648
+ }
1639
1649
  .markdy-node[data-shape="pill"] {
1640
1650
  border-radius: 999px;
1641
1651
  min-height: 54px;
@@ -2100,11 +2110,11 @@ function createNodeEl(node, theme, assets) {
2100
2110
  el.setAttribute("aria-label", el.title);
2101
2111
  const body = document.createElement("div");
2102
2112
  body.className = "markdy-node__body";
2103
- const icon = createNodeMediaEl(document, node, assets);
2104
2113
  const label = document.createElement("div");
2105
2114
  label.className = "markdy-node__label";
2106
2115
  label.textContent = node.label;
2107
- body.append(icon, label);
2116
+ if (node.shape !== "diamond") body.append(createNodeMediaEl(document, node, assets));
2117
+ body.append(label);
2108
2118
  const value = node.props?.value ?? node.props?.metric;
2109
2119
  if (value !== void 0 && value !== null) {
2110
2120
  const valueEl = document.createElement("div");
@@ -2493,15 +2503,26 @@ function ensureSceneStyles(doc) {
2493
2503
  will-change: opacity, transform;
2494
2504
  }
2495
2505
  .markdy-footer {
2496
- font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
2506
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
2497
2507
  width: 100%;
2498
2508
  box-sizing: border-box;
2509
+ display: flex;
2510
+ align-items: center;
2511
+ justify-content: space-between;
2512
+ gap: 8px;
2513
+ padding: 6px 12px;
2514
+ background: var(--md-footer-bg, rgba(15, 23, 42, 0.85));
2515
+ backdrop-filter: blur(16px);
2516
+ -webkit-backdrop-filter: blur(16px);
2517
+ border-top: 1px solid var(--md-footer-border, rgba(148, 163, 184, 0.15));
2518
+ z-index: 20;
2499
2519
  }
2500
2520
  .markdy-controls {
2501
2521
  display: flex;
2502
2522
  align-items: center;
2503
- flex-wrap: nowrap;
2504
- gap: 2.5px;
2523
+ justify-content: flex-start;
2524
+ width: 100%;
2525
+ gap: 8px;
2505
2526
  max-width: 100%;
2506
2527
  overflow-x: auto;
2507
2528
  scrollbar-width: none;
@@ -2509,65 +2530,367 @@ function ensureSceneStyles(doc) {
2509
2530
  .markdy-controls::-webkit-scrollbar {
2510
2531
  display: none;
2511
2532
  }
2512
- @media (max-width: 640px) {
2513
- .markdy-controls {
2514
- flex-wrap: wrap;
2515
- justify-content: center;
2516
- gap: 3px;
2517
- }
2533
+ .markdy-controls-group {
2534
+ display: inline-flex;
2535
+ align-items: center;
2536
+ gap: 4px;
2537
+ flex-shrink: 0;
2538
+ }
2539
+ .markdy-controls-playback {
2540
+ display: inline-flex;
2541
+ align-items: center;
2542
+ gap: 4px;
2543
+ flex-shrink: 0;
2544
+ }
2545
+ .markdy-controls-timeline {
2546
+ display: flex;
2547
+ align-items: center;
2548
+ gap: 8px;
2549
+ flex: 1 1 180px;
2550
+ min-width: 110px;
2551
+ max-width: 340px;
2552
+ }
2553
+ .markdy-controls-tools {
2554
+ display: inline-flex;
2555
+ align-items: center;
2556
+ gap: 4px;
2557
+ flex-shrink: 0;
2558
+ margin-left: auto;
2559
+ }
2560
+ .markdy-control-divider {
2561
+ width: 1px;
2562
+ height: 14px;
2563
+ background: var(--md-divider, rgba(148, 163, 184, 0.2));
2564
+ margin: 0 2px;
2565
+ flex-shrink: 0;
2518
2566
  }
2519
2567
  .markdy-controls button {
2520
2568
  appearance: none;
2569
+ -webkit-appearance: none;
2521
2570
  touch-action: manipulation;
2522
2571
  user-select: none;
2523
2572
  -webkit-user-select: none;
2524
- border: 1px solid var(--md-control-border, rgba(148, 163, 184, 0.45));
2525
- border-radius: 5px;
2526
- background: var(--md-control-bg, rgba(248, 250, 252, 0.92));
2527
- color: var(--md-control-text, #334155);
2573
+ border: 1px solid var(--md-control-border, rgba(148, 163, 184, 0.2));
2574
+ border-radius: 7px;
2575
+ background: var(--md-control-bg, rgba(255, 255, 255, 0.04));
2576
+ color: var(--md-control-text, #94a3b8);
2528
2577
  cursor: pointer;
2529
- font: 600 10px/1.2 system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
2530
- padding: 2.5px 5.5px;
2531
- min-height: 23px;
2532
- min-width: 22px;
2578
+ font: 600 11px/1 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
2579
+ height: 27px;
2580
+ min-width: 27px;
2581
+ padding: 0 6px;
2533
2582
  display: inline-flex;
2534
2583
  align-items: center;
2535
2584
  justify-content: center;
2536
- gap: 2px;
2585
+ gap: 5px;
2537
2586
  white-space: nowrap;
2538
- box-shadow: 0 1px 2px rgba(0, 0, 0, 0.03);
2587
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
2539
2588
  transition: all 0.15s cubic-bezier(0.4, 0, 0.2, 1);
2540
2589
  }
2541
2590
  .markdy-controls button:hover:not([aria-pressed="true"]) {
2542
- background: var(--md-control-hover-bg, #ffffff);
2543
- color: var(--md-control-hover-text, #0f172a);
2544
- border-color: var(--md-control-hover-border, #94a3b8);
2545
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);
2591
+ background: var(--md-control-hover-bg, rgba(255, 255, 255, 0.1));
2592
+ color: var(--md-control-hover-text, #f8fafc);
2593
+ border-color: var(--md-control-hover-border, rgba(148, 163, 184, 0.35));
2594
+ transform: translateY(-1px);
2595
+ box-shadow: 0 2px 5px rgba(0, 0, 0, 0.12);
2546
2596
  }
2547
2597
  .markdy-controls button[aria-pressed="true"] {
2548
- background: #0f172a !important;
2598
+ background: var(--accent, #10b981) !important;
2549
2599
  color: #ffffff !important;
2550
- border-color: #0f172a !important;
2551
- box-shadow: 0 1px 3px rgba(15, 23, 42, 0.25) !important;
2600
+ border-color: var(--accent, #10b981) !important;
2601
+ box-shadow: 0 0 10px var(--accent-glow, rgba(16, 185, 129, 0.4)) !important;
2552
2602
  }
2553
2603
  .markdy-controls button:focus-visible {
2554
- outline: 2px solid #3b82f6;
2604
+ outline: 2px solid var(--accent, #10b981);
2555
2605
  outline-offset: 1px;
2556
2606
  }
2557
2607
  .markdy-controls button:active {
2558
2608
  transform: scale(0.95);
2559
2609
  }
2560
- .markdy-control-play::before { content: "\u25B6"; font-size: 7.5px; margin-right: 1px; }
2561
- .markdy-control-play[aria-label*="Pause"]::before,
2562
- .markdy-control-play[title*="Pause"]::before { content: "\u23F8"; font-size: 7.5px; margin-right: 1px; }
2563
- .markdy-control-restart::before { content: "\u21BA"; font-size: 10px; font-weight: 700; margin-right: 1px; }
2564
- .markdy-control-prev-beat::before { content: "\u23EE"; font-size: 7.5px; margin-right: 1px; }
2565
- .markdy-control-next-beat::before { content: "\u23ED"; font-size: 7.5px; margin-right: 1px; }
2566
- .markdy-control-fit::before { content: "\u26F6"; font-size: 8.5px; margin-right: 1px; }
2567
- .markdy-control-reset-view::before { content: "\u2299"; font-size: 8.5px; margin-right: 1px; }
2568
- .markdy-control-fullscreen::before { content: "\u26F6"; font-size: 8.5px; margin-right: 1px; }
2569
- .markdy-control-svg::before { content: "\u{1F4E5}"; font-size: 8.5px; margin-right: 1px; }
2570
- .markdy-control-share::before { content: "\u{1F517}"; font-size: 8.5px; margin-right: 1px; }
2610
+ .markdy-icon {
2611
+ display: inline-block;
2612
+ flex-shrink: 0;
2613
+ vertical-align: middle;
2614
+ }
2615
+ .markdy-control-play {
2616
+ background: var(--accent, #10b981) !important;
2617
+ color: #ffffff !important;
2618
+ border-color: var(--accent, #10b981) !important;
2619
+ padding: 0 10px !important;
2620
+ font-weight: 700 !important;
2621
+ box-shadow: 0 2px 8px var(--accent-glow, rgba(16, 185, 129, 0.35)) !important;
2622
+ }
2623
+ .markdy-control-play:hover {
2624
+ filter: brightness(1.08);
2625
+ box-shadow: 0 2px 12px var(--accent-glow, rgba(16, 185, 129, 0.55)) !important;
2626
+ transform: translateY(-1px) scale(1.02);
2627
+ }
2628
+ .markdy-badge {
2629
+ display: inline-flex;
2630
+ align-items: center;
2631
+ gap: 4px;
2632
+ font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
2633
+ font-size: 11px;
2634
+ font-weight: 600;
2635
+ color: var(--md-control-text, #94a3b8);
2636
+ text-decoration: none;
2637
+ padding: 3px 8px;
2638
+ border-radius: 999px;
2639
+ background: var(--md-control-bg, rgba(255, 255, 255, 0.05));
2640
+ border: 1px solid var(--md-control-border, rgba(148, 163, 184, 0.18));
2641
+ margin-left: auto;
2642
+ flex-shrink: 0;
2643
+ transition: all 0.15s ease;
2644
+ white-space: nowrap;
2645
+ }
2646
+ .markdy-badge:hover {
2647
+ color: var(--accent, #10b981);
2648
+ background: var(--accent-light, rgba(16, 185, 129, 0.12));
2649
+ border-color: var(--accent, #10b981);
2650
+ transform: translateY(-1px);
2651
+ }
2652
+ .markdy-speed-group {
2653
+ display: inline-flex;
2654
+ align-items: center;
2655
+ background: var(--md-segmented-bg, rgba(0, 0, 0, 0.18));
2656
+ border: 1px solid var(--md-control-border, rgba(148, 163, 184, 0.18));
2657
+ border-radius: 8px;
2658
+ padding: 2px;
2659
+ gap: 1px;
2660
+ }
2661
+ .markdy-speed-group .markdy-control-rate {
2662
+ border: none;
2663
+ background: transparent;
2664
+ border-radius: 5px;
2665
+ height: 22px;
2666
+ min-width: 25px;
2667
+ padding: 0 5px;
2668
+ font-size: 10px;
2669
+ font-weight: 700;
2670
+ color: var(--md-control-text, #94a3b8);
2671
+ box-shadow: none;
2672
+ }
2673
+ .markdy-speed-group .markdy-control-rate:hover:not([aria-pressed="true"]) {
2674
+ background: rgba(255, 255, 255, 0.08);
2675
+ color: #ffffff;
2676
+ transform: none;
2677
+ }
2678
+ .markdy-speed-group .markdy-control-rate[aria-pressed="true"] {
2679
+ background: var(--accent, #10b981) !important;
2680
+ color: #ffffff !important;
2681
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25) !important;
2682
+ }
2683
+ .markdy-control-seek {
2684
+ appearance: none;
2685
+ -webkit-appearance: none;
2686
+ width: 100%;
2687
+ height: 5px;
2688
+ border-radius: 999px;
2689
+ background: linear-gradient(
2690
+ to right,
2691
+ var(--accent, #10b981) 0%,
2692
+ var(--accent, #10b981) var(--seek-pct, 0%),
2693
+ rgba(148, 163, 184, 0.22) var(--seek-pct, 0%),
2694
+ rgba(148, 163, 184, 0.22) 100%
2695
+ );
2696
+ outline: none;
2697
+ cursor: pointer;
2698
+ margin: 0;
2699
+ transition: height 0.15s ease;
2700
+ }
2701
+ .markdy-control-seek:hover {
2702
+ height: 7px;
2703
+ }
2704
+ .markdy-control-seek::-webkit-slider-thumb {
2705
+ appearance: none;
2706
+ -webkit-appearance: none;
2707
+ width: 12px;
2708
+ height: 12px;
2709
+ border-radius: 50%;
2710
+ background: #ffffff;
2711
+ border: 2px solid var(--accent, #10b981);
2712
+ box-shadow: 0 1px 4px rgba(0, 0, 0, 0.35);
2713
+ cursor: pointer;
2714
+ transition: transform 0.15s ease, box-shadow 0.15s ease;
2715
+ }
2716
+ .markdy-control-seek:hover::-webkit-slider-thumb {
2717
+ transform: scale(1.25);
2718
+ box-shadow: 0 0 8px var(--accent-glow, rgba(16, 185, 129, 0.6));
2719
+ }
2720
+ .markdy-control-seek::-moz-range-thumb {
2721
+ width: 12px;
2722
+ height: 12px;
2723
+ border-radius: 50%;
2724
+ background: #ffffff;
2725
+ border: 2px solid var(--accent, #10b981);
2726
+ box-shadow: 0 1px 4px rgba(0, 0, 0, 0.35);
2727
+ cursor: pointer;
2728
+ transition: transform 0.15s ease, box-shadow 0.15s ease;
2729
+ }
2730
+ .markdy-control-seek:hover::-moz-range-thumb {
2731
+ transform: scale(1.25);
2732
+ box-shadow: 0 0 8px var(--accent-glow, rgba(16, 185, 129, 0.6));
2733
+ }
2734
+ .markdy-control-time {
2735
+ font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
2736
+ font-size: 10px;
2737
+ font-weight: 600;
2738
+ color: var(--md-control-text, #94a3b8);
2739
+ white-space: nowrap;
2740
+ flex-shrink: 0;
2741
+ letter-spacing: -0.02em;
2742
+ }
2743
+ .markdy-btn-flashed {
2744
+ background: rgba(16, 185, 129, 0.2) !important;
2745
+ color: #10b981 !important;
2746
+ border-color: #10b981 !important;
2747
+ }
2748
+ /* \u2500\u2500 Code panel overlay \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
2749
+ .markdy-code-panel-overlay {
2750
+ position: fixed;
2751
+ inset: 0;
2752
+ z-index: 9000;
2753
+ background: rgba(2, 6, 23, 0.55);
2754
+ backdrop-filter: blur(3px);
2755
+ -webkit-backdrop-filter: blur(3px);
2756
+ display: flex;
2757
+ align-items: center;
2758
+ justify-content: center;
2759
+ padding: 24px;
2760
+ box-sizing: border-box;
2761
+ opacity: 0;
2762
+ animation: markdy-fade-in 0.18s ease forwards;
2763
+ }
2764
+ .markdy-code-panel-overlay[data-closing="1"] {
2765
+ animation: markdy-fade-out 0.15s ease forwards;
2766
+ }
2767
+ @keyframes markdy-fade-in {
2768
+ from { opacity: 0; }
2769
+ to { opacity: 1; }
2770
+ }
2771
+ @keyframes markdy-fade-out {
2772
+ from { opacity: 1; }
2773
+ to { opacity: 0; }
2774
+ }
2775
+ .markdy-code-panel {
2776
+ position: relative;
2777
+ background: #0f172a;
2778
+ border: 1px solid rgba(71, 85, 105, 0.7);
2779
+ border-radius: 12px;
2780
+ box-shadow: 0 24px 60px rgba(0, 0, 0, 0.6), 0 0 0 1px rgba(255, 255, 255, 0.04);
2781
+ width: 100%;
2782
+ max-width: 780px;
2783
+ max-height: min(680px, 82vh);
2784
+ display: flex;
2785
+ flex-direction: column;
2786
+ overflow: hidden;
2787
+ transform: translateY(10px) scale(0.98);
2788
+ animation: markdy-panel-in 0.2s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
2789
+ }
2790
+ .markdy-code-panel-overlay[data-closing="1"] .markdy-code-panel {
2791
+ animation: markdy-panel-out 0.15s ease forwards;
2792
+ }
2793
+ @keyframes markdy-panel-in {
2794
+ from { transform: translateY(12px) scale(0.97); opacity: 0; }
2795
+ to { transform: translateY(0) scale(1); opacity: 1; }
2796
+ }
2797
+ @keyframes markdy-panel-out {
2798
+ from { transform: translateY(0) scale(1); opacity: 1; }
2799
+ to { transform: translateY(8px) scale(0.98); opacity: 0; }
2800
+ }
2801
+ .markdy-code-panel__header {
2802
+ display: flex;
2803
+ align-items: center;
2804
+ justify-content: space-between;
2805
+ padding: 12px 16px 10px;
2806
+ border-bottom: 1px solid rgba(71, 85, 105, 0.4);
2807
+ flex-shrink: 0;
2808
+ }
2809
+ .markdy-code-panel__title {
2810
+ font: 600 12px/1.4 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
2811
+ color: #94a3b8;
2812
+ letter-spacing: 0.06em;
2813
+ text-transform: uppercase;
2814
+ }
2815
+ .markdy-code-panel__actions {
2816
+ display: flex;
2817
+ align-items: center;
2818
+ gap: 6px;
2819
+ }
2820
+ .markdy-code-panel__copy,
2821
+ .markdy-code-panel__playground,
2822
+ .markdy-code-panel__close {
2823
+ appearance: none;
2824
+ border: 1px solid rgba(71, 85, 105, 0.55);
2825
+ border-radius: 6px;
2826
+ background: rgba(30, 41, 59, 0.8);
2827
+ color: #94a3b8;
2828
+ cursor: pointer;
2829
+ font: 600 10.5px/1.2 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
2830
+ text-decoration: none;
2831
+ padding: 3px 9px;
2832
+ min-height: 24px;
2833
+ display: inline-flex;
2834
+ align-items: center;
2835
+ gap: 4px;
2836
+ transition: all 0.15s ease;
2837
+ white-space: nowrap;
2838
+ }
2839
+ .markdy-code-panel__playground {
2840
+ background: var(--accent-light, rgba(16, 185, 129, 0.15));
2841
+ color: var(--accent, #10b981);
2842
+ border-color: var(--accent, #10b981);
2843
+ font-weight: 700;
2844
+ }
2845
+ .markdy-code-panel__playground:hover {
2846
+ background: var(--accent, #10b981);
2847
+ color: #ffffff;
2848
+ border-color: var(--accent, #10b981);
2849
+ transform: translateY(-1px);
2850
+ }
2851
+ .markdy-code-panel__copy:hover,
2852
+ .markdy-code-panel__close:hover {
2853
+ background: rgba(51, 65, 85, 0.95);
2854
+ color: #e2e8f0;
2855
+ border-color: #64748b;
2856
+ }
2857
+ .markdy-code-panel__copy:focus-visible,
2858
+ .markdy-code-panel__playground:focus-visible,
2859
+ .markdy-code-panel__close:focus-visible {
2860
+ outline: 2px solid #3b82f6;
2861
+ outline-offset: 1px;
2862
+ }
2863
+ .markdy-code-panel__body {
2864
+ overflow-y: auto;
2865
+ flex: 1 1 auto;
2866
+ padding: 16px 20px;
2867
+ scrollbar-width: thin;
2868
+ scrollbar-color: rgba(71, 85, 105, 0.5) transparent;
2869
+ }
2870
+ .markdy-code-panel__body::-webkit-scrollbar {
2871
+ width: 5px;
2872
+ }
2873
+ .markdy-code-panel__body::-webkit-scrollbar-track {
2874
+ background: transparent;
2875
+ }
2876
+ .markdy-code-panel__body::-webkit-scrollbar-thumb {
2877
+ background: rgba(71, 85, 105, 0.5);
2878
+ border-radius: 9999px;
2879
+ }
2880
+ .markdy-code-panel__pre {
2881
+ margin: 0;
2882
+ font: 400 12.5px/1.65 "JetBrains Mono", ui-monospace, "Cascadia Code", "Fira Code", monospace;
2883
+ color: #e2e8f0;
2884
+ white-space: pre;
2885
+ tab-size: 2;
2886
+ overflow-x: auto;
2887
+ }
2888
+ /* Syntax tinting \u2014 purely decorative, lightweight regex-free colorization */
2889
+ .markdy-code-panel__pre .t-keyword { color: #7dd3fc; }
2890
+ .markdy-code-panel__pre .t-string { color: #86efac; }
2891
+ .markdy-code-panel__pre .t-comment { color: #64748b; font-style: italic; }
2892
+ .markdy-code-panel__pre .t-edge { color: #f9a8d4; }
2893
+ .markdy-code-panel__pre .t-number { color: #fcd34d; }
2571
2894
  .markdy-control-rate {
2572
2895
  font-family: "JetBrains Mono", monospace, system-ui;
2573
2896
  font-size: 9px;
@@ -2839,7 +3162,9 @@ function createDiagram(opts) {
2839
3162
  resetView: resetViewButton,
2840
3163
  fullscreen: fullscreenButton,
2841
3164
  svg: svgButton,
2842
- share: shareButton
3165
+ share: shareButton,
3166
+ code: codeButton,
3167
+ theme: themeButton
2843
3168
  } = player.controls;
2844
3169
  const copyright = player.chrome.badge;
2845
3170
  const progressMode = player.chrome.progress;
@@ -2916,22 +3241,13 @@ function createDiagram(opts) {
2916
3241
  let badge = null;
2917
3242
  if (copyright) {
2918
3243
  badge = document.createElement("a");
3244
+ badge.className = "markdy-badge";
2919
3245
  badge.href = `${MARKDY_PLAYGROUND_URL}#code=${encodeCodeForPlaygroundHash(code)}`;
2920
3246
  badge.target = "_blank";
2921
3247
  badge.rel = "noopener noreferrer";
2922
- badge.textContent = "Powered by Markdy";
2923
- Object.assign(badge.style, {
2924
- display: "inline-flex",
2925
- alignItems: "center",
2926
- textAlign: "right",
2927
- fontSize: "10px",
2928
- fontFamily: "system-ui, sans-serif",
2929
- color: "#999",
2930
- textDecoration: "none",
2931
- padding: "0",
2932
- opacity: "0.7",
2933
- marginLeft: "auto"
2934
- });
3248
+ badge.title = "Open and edit in Markdy Playground";
3249
+ badge.style.marginLeft = "auto";
3250
+ badge.innerHTML = `<span style="opacity:0.9">\u26A1</span> Markdy`;
2935
3251
  ensureFooter().appendChild(badge);
2936
3252
  }
2937
3253
  ensureSceneStyles(document);
@@ -2973,7 +3289,7 @@ function createDiagram(opts) {
2973
3289
  Object.assign(structuralEdgeHost.style, {
2974
3290
  position: "absolute",
2975
3291
  inset: "0",
2976
- zIndex: "45",
3292
+ zIndex: "55",
2977
3293
  pointerEvents: "none"
2978
3294
  });
2979
3295
  cameraLayer.appendChild(structuralEdgeHost);
@@ -3159,8 +3475,24 @@ function createDiagram(opts) {
3159
3475
  let controlsPlayButton = null;
3160
3476
  let controlsRateButtons = [];
3161
3477
  let controlsSeekBar = null;
3478
+ let controlsTimeEl = null;
3162
3479
  let controlsFitButton = null;
3163
3480
  let fitViewActive = false;
3481
+ const ICONS2 = {
3482
+ play: '<svg class="markdy-icon" width="12" height="12" viewBox="0 0 24 24" fill="currentColor"><path d="M8 5v14l11-7z"/></svg>',
3483
+ pause: '<svg class="markdy-icon" width="12" height="12" viewBox="0 0 24 24" fill="currentColor"><path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/></svg>',
3484
+ restart: '<svg class="markdy-icon" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/></svg>',
3485
+ prevBeat: '<svg class="markdy-icon" width="12" height="12" viewBox="0 0 24 24" fill="currentColor"><path d="M6 6h2v12H6zm3.5 6 8.5 6V6z"/></svg>',
3486
+ nextBeat: '<svg class="markdy-icon" width="12" height="12" viewBox="0 0 24 24" fill="currentColor"><path d="M6 18l8.5-6L6 6v12zM16 6v12h2V6h-2z"/></svg>',
3487
+ fit: '<svg class="markdy-icon" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3"/></svg>',
3488
+ resetView: '<svg class="markdy-icon" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><circle cx="12" cy="12" r="3"/></svg>',
3489
+ fullscreen: '<svg class="markdy-icon" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 3h6v6M9 21H3v-6M21 3l-7 7M3 21l7-7"/></svg>',
3490
+ svg: '<svg class="markdy-icon" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>',
3491
+ share: '<svg class="markdy-icon" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg>',
3492
+ code: '<svg class="markdy-icon" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></svg>',
3493
+ theme: '<svg class="markdy-icon" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 3v18"/><path d="M12 3a9 9 0 0 1 0 18z" fill="currentColor"/></svg>',
3494
+ check: '<svg class="markdy-icon" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="#10b981" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>'
3495
+ };
3164
3496
  function applyViewportTransform() {
3165
3497
  viewportTransform.style.transform = `translate(${viewportPanX}px, ${viewportPanY}px) scale(${viewportScale})`;
3166
3498
  }
@@ -3247,7 +3579,7 @@ function createDiagram(opts) {
3247
3579
  function syncControls() {
3248
3580
  if (controlsPlayButton) {
3249
3581
  const playing = isPlaying;
3250
- controlsPlayButton.textContent = playing ? "Pause" : "Play";
3582
+ controlsPlayButton.innerHTML = `${playing ? ICONS2.pause : ICONS2.play}${playing ? "Pause" : "Play"}`;
3251
3583
  const playLabel = playing ? "Pause diagram" : "Play diagram";
3252
3584
  controlsPlayButton.setAttribute("aria-label", playLabel);
3253
3585
  controlsPlayButton.title = playLabel;
@@ -3257,7 +3589,16 @@ function createDiagram(opts) {
3257
3589
  const active = Math.abs(rate - playbackRate) < 1e-3;
3258
3590
  button.setAttribute("aria-pressed", active ? "true" : "false");
3259
3591
  }
3260
- if (controlsSeekBar) controlsSeekBar.value = String(sceneMs / 1e3);
3592
+ if (controlsSeekBar) {
3593
+ controlsSeekBar.value = String(sceneMs / 1e3);
3594
+ const pct = totalDurationMs > 0 ? sceneMs / totalDurationMs * 100 : 0;
3595
+ controlsSeekBar.style.setProperty("--seek-pct", `${pct}%`);
3596
+ }
3597
+ if (controlsTimeEl) {
3598
+ const cur = (sceneMs / 1e3).toFixed(1);
3599
+ const tot = durationSeconds.toFixed(1);
3600
+ controlsTimeEl.textContent = `${cur}s / ${tot}s`;
3601
+ }
3261
3602
  if (controlsFitButton) {
3262
3603
  controlsFitButton.setAttribute("aria-pressed", fitViewActive ? "true" : "false");
3263
3604
  }
@@ -3367,17 +3708,21 @@ function createDiagram(opts) {
3367
3708
  diagram.play();
3368
3709
  }
3369
3710
  }
3370
- function makeControlButton(label, ariaLabel) {
3711
+ function makeControlButton(label, ariaLabel, iconSvg) {
3371
3712
  const button = document.createElement("button");
3372
3713
  button.type = "button";
3373
- button.textContent = label;
3374
3714
  button.setAttribute("aria-label", ariaLabel);
3375
3715
  button.title = ariaLabel;
3716
+ if (iconSvg) {
3717
+ button.innerHTML = `${iconSvg}${label}`;
3718
+ } else {
3719
+ button.textContent = label;
3720
+ }
3376
3721
  return button;
3377
3722
  }
3378
3723
  function mountPlayControl(toolbar) {
3379
3724
  if (!playButton) return;
3380
- controlsPlayButton = makeControlButton("Play", "Play diagram");
3725
+ controlsPlayButton = makeControlButton("Play", "Play diagram", ICONS2.play);
3381
3726
  controlsPlayButton.className = "markdy-control-play";
3382
3727
  controlsPlayButton.addEventListener("click", togglePlayback);
3383
3728
  toolbar.appendChild(controlsPlayButton);
@@ -3386,14 +3731,15 @@ function createDiagram(opts) {
3386
3731
  const wanted = position === "prev" ? prevBeatButton : nextBeatButton;
3387
3732
  if (!wanted || plan.beats.length < 2) return;
3388
3733
  const label = position === "prev" ? "Prev" : "Next";
3389
- const button = makeControlButton(label, `${label === "Prev" ? "Previous" : "Next"} beat`);
3734
+ const icon = position === "prev" ? ICONS2.prevBeat : ICONS2.nextBeat;
3735
+ const button = makeControlButton(label, `${label === "Prev" ? "Previous" : "Next"} beat`, icon);
3390
3736
  button.className = `markdy-control-${position}-beat`;
3391
3737
  button.addEventListener("click", () => position === "prev" ? diagram.prevBeat() : diagram.nextBeat());
3392
3738
  toolbar.appendChild(button);
3393
3739
  }
3394
3740
  function mountRestartControl(toolbar) {
3395
3741
  if (!restartButton) return;
3396
- const button = makeControlButton("Restart", "Restart diagram");
3742
+ const button = makeControlButton("Restart", "Restart diagram", ICONS2.restart);
3397
3743
  button.className = "markdy-control-restart";
3398
3744
  button.addEventListener("click", () => {
3399
3745
  diagram.seek(0);
@@ -3413,6 +3759,10 @@ function createDiagram(opts) {
3413
3759
  controlsSeekBar.setAttribute("aria-label", "Seek diagram timeline");
3414
3760
  controlsSeekBar.addEventListener("input", () => diagram.seek(Number(controlsSeekBar?.value ?? 0)));
3415
3761
  toolbar.appendChild(controlsSeekBar);
3762
+ controlsTimeEl = document.createElement("span");
3763
+ controlsTimeEl.className = "markdy-control-time";
3764
+ controlsTimeEl.textContent = `${(sceneMs / 1e3).toFixed(1)}s / ${durationSeconds.toFixed(1)}s`;
3765
+ toolbar.appendChild(controlsTimeEl);
3416
3766
  }
3417
3767
  function mountSpeedControls(toolbar) {
3418
3768
  if (!speedControls) return;
@@ -3427,11 +3777,14 @@ function createDiagram(opts) {
3427
3777
  });
3428
3778
  }
3429
3779
  function flashControlLabel(button, message) {
3430
- const original = button.textContent ?? "";
3431
- button.textContent = message;
3780
+ const originalHtml = button.innerHTML;
3781
+ const isSuccess = !message.toLowerCase().includes("fail");
3782
+ button.innerHTML = isSuccess ? `${ICONS2.check}${message}` : message;
3783
+ button.classList.add("markdy-btn-flashed");
3432
3784
  setTimeout(() => {
3433
- button.textContent = original;
3434
- }, 1400);
3785
+ button.innerHTML = originalHtml;
3786
+ button.classList.remove("markdy-btn-flashed");
3787
+ }, 1500);
3435
3788
  }
3436
3789
  function downloadFile(filename, contents, type) {
3437
3790
  const blob = new Blob([contents], { type });
@@ -3447,7 +3800,7 @@ function createDiagram(opts) {
3447
3800
  }
3448
3801
  function mountSvgControl(toolbar) {
3449
3802
  if (!svgButton) return;
3450
- const button = makeControlButton("SVG", "Export diagram as SVG");
3803
+ const button = makeControlButton("SVG", "Export diagram as SVG", ICONS2.svg);
3451
3804
  button.className = "markdy-control-svg";
3452
3805
  button.addEventListener("click", async () => {
3453
3806
  const resumeAt = sceneMs;
@@ -3459,6 +3812,7 @@ function createDiagram(opts) {
3459
3812
  const svg = exportDiagramAsVectorSvg2(container);
3460
3813
  const name = (plan.title || "markdy-diagram").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
3461
3814
  downloadFile(`${name || "markdy-diagram"}.svg`, svg, "image/svg+xml");
3815
+ flashControlLabel(button, "Saved");
3462
3816
  } catch (error) {
3463
3817
  onWarning({ severity: "warning", message: `SVG export failed: ${String(error)}`, line: 0 });
3464
3818
  flashControlLabel(button, "Failed");
@@ -3471,7 +3825,7 @@ function createDiagram(opts) {
3471
3825
  }
3472
3826
  function mountShareControl(toolbar) {
3473
3827
  if (!shareButton) return;
3474
- const button = makeControlButton("Share", "Copy a share link for this diagram");
3828
+ const button = makeControlButton("Share", "Copy a share link for this diagram", ICONS2.share);
3475
3829
  button.className = "markdy-control-share";
3476
3830
  button.addEventListener("click", async () => {
3477
3831
  try {
@@ -3486,9 +3840,132 @@ function createDiagram(opts) {
3486
3840
  });
3487
3841
  toolbar.appendChild(button);
3488
3842
  }
3843
+ function mountThemeControl(toolbar) {
3844
+ if (!themeButton) return;
3845
+ const button = makeControlButton("Theme", "Toggle dark/light theme palette", ICONS2.theme);
3846
+ button.className = "markdy-control-theme";
3847
+ button.addEventListener("click", () => {
3848
+ const darkThemes = ["midnight", "blueprint", "graphite", "nebula", "terminal"];
3849
+ const lightThemes = ["paper", "editorial", "sketchy"];
3850
+ const currentName = plan.theme.name || "paper";
3851
+ const isDark = darkThemes.includes(currentName);
3852
+ const targetThemes = isDark ? lightThemes : darkThemes;
3853
+ const nextTheme = targetThemes[Math.floor(Math.random() * targetThemes.length)];
3854
+ flashControlLabel(button, nextTheme);
3855
+ container.dispatchEvent(
3856
+ new CustomEvent("markdy-theme-switch", {
3857
+ bubbles: true,
3858
+ detail: { theme: nextTheme, isDark: !isDark }
3859
+ })
3860
+ );
3861
+ });
3862
+ toolbar.appendChild(button);
3863
+ }
3864
+ function tintCode(raw) {
3865
+ return raw.split("\n").map((line) => {
3866
+ if (/^\s*\/\//.test(line)) {
3867
+ return `<span class="t-comment">${escHtml(line)}</span>`;
3868
+ }
3869
+ line = line.replace(/(->|<-|~>|--|<~)/g, '<span class="t-edge">$1</span>');
3870
+ line = line.replace(/"([^"]*)"/g, '"<span class="t-string">$1</span>"');
3871
+ line = line.replace(
3872
+ /^(\s*)(scene|beat|group|player|show|frame|glow|focus|layout|edge|annotation|start|end|decision|service|browser|gateway|database|cache|queue|worker|function|pod|user|client|hub|station|metric|mobile)\b/,
3873
+ '$1<span class="t-keyword">$2</span>'
3874
+ );
3875
+ line = line.replace(/\b(\d[\d.]*(?:ms|px|s)?)\b/g, '<span class="t-number">$1</span>');
3876
+ return line;
3877
+ }).join("\n");
3878
+ }
3879
+ function escHtml(str) {
3880
+ return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
3881
+ }
3882
+ function mountCodeControl(toolbar) {
3883
+ if (!codeButton) return;
3884
+ const button = makeControlButton("Code", "View MarkdyScript source");
3885
+ button.className = "markdy-control-code";
3886
+ button.setAttribute("aria-haspopup", "dialog");
3887
+ button.addEventListener("click", () => {
3888
+ const overlay = document.createElement("div");
3889
+ overlay.className = "markdy-code-panel-overlay";
3890
+ overlay.setAttribute("role", "dialog");
3891
+ overlay.setAttribute("aria-modal", "true");
3892
+ overlay.setAttribute("aria-label", "MarkdyScript source code");
3893
+ const panel = document.createElement("div");
3894
+ panel.className = "markdy-code-panel";
3895
+ const header = document.createElement("div");
3896
+ header.className = "markdy-code-panel__header";
3897
+ const title = document.createElement("div");
3898
+ title.className = "markdy-code-panel__title";
3899
+ title.textContent = "MarkdyScript source";
3900
+ const actions = document.createElement("div");
3901
+ actions.className = "markdy-code-panel__actions";
3902
+ const copyBtn = document.createElement("button");
3903
+ copyBtn.type = "button";
3904
+ copyBtn.className = "markdy-code-panel__copy";
3905
+ copyBtn.textContent = "Copy";
3906
+ copyBtn.setAttribute("aria-label", "Copy source code to clipboard");
3907
+ copyBtn.addEventListener("click", async () => {
3908
+ try {
3909
+ await navigator.clipboard.writeText(code);
3910
+ copyBtn.textContent = "Copied \u2713";
3911
+ setTimeout(() => {
3912
+ copyBtn.textContent = "Copy";
3913
+ }, 1800);
3914
+ } catch {
3915
+ copyBtn.textContent = "Failed";
3916
+ setTimeout(() => {
3917
+ copyBtn.textContent = "Copy";
3918
+ }, 1800);
3919
+ }
3920
+ });
3921
+ const playgroundBtn = document.createElement("a");
3922
+ playgroundBtn.className = "markdy-code-panel__playground";
3923
+ playgroundBtn.href = `${shareUrl ?? MARKDY_PLAYGROUND_URL}#code=${encodeCodeForPlaygroundHash(code)}`;
3924
+ playgroundBtn.target = "_blank";
3925
+ playgroundBtn.rel = "noopener noreferrer";
3926
+ playgroundBtn.textContent = "Open in Studio \u2197";
3927
+ playgroundBtn.setAttribute("aria-label", "Open diagram in Markdy Studio playground");
3928
+ const closeBtn = document.createElement("button");
3929
+ closeBtn.type = "button";
3930
+ closeBtn.className = "markdy-code-panel__close";
3931
+ closeBtn.textContent = "\u2715 Close";
3932
+ closeBtn.setAttribute("aria-label", "Close code panel");
3933
+ actions.append(copyBtn, playgroundBtn, closeBtn);
3934
+ header.append(title, actions);
3935
+ const body = document.createElement("div");
3936
+ body.className = "markdy-code-panel__body";
3937
+ const pre = document.createElement("pre");
3938
+ pre.className = "markdy-code-panel__pre";
3939
+ pre.innerHTML = tintCode(code);
3940
+ body.appendChild(pre);
3941
+ panel.append(header, body);
3942
+ overlay.appendChild(panel);
3943
+ document.body.appendChild(overlay);
3944
+ closeBtn.focus();
3945
+ function closePanel() {
3946
+ overlay.dataset.closing = "1";
3947
+ overlay.addEventListener("animationend", () => overlay.remove(), { once: true });
3948
+ }
3949
+ closeBtn.addEventListener("click", closePanel);
3950
+ overlay.addEventListener("click", (e) => {
3951
+ if (e.target === overlay) closePanel();
3952
+ });
3953
+ function handleEscape(e) {
3954
+ if (e.key === "Escape") {
3955
+ closePanel();
3956
+ document.removeEventListener("keydown", handleEscape);
3957
+ }
3958
+ }
3959
+ document.addEventListener("keydown", handleEscape);
3960
+ overlay.addEventListener("animationend", () => {
3961
+ if (overlay.dataset.closing === "1") document.removeEventListener("keydown", handleEscape);
3962
+ }, { once: true });
3963
+ });
3964
+ toolbar.appendChild(button);
3965
+ }
3489
3966
  function mountFitControl(toolbar) {
3490
3967
  if (!fitViewButton) return;
3491
- controlsFitButton = makeControlButton("Fit", "Fit all items in view and ignore camera zoom");
3968
+ controlsFitButton = makeControlButton("Fit", "Fit all items in view and ignore camera zoom", ICONS2.fit);
3492
3969
  controlsFitButton.className = "markdy-control-fit";
3493
3970
  controlsFitButton.setAttribute("aria-pressed", "false");
3494
3971
  controlsFitButton.addEventListener("click", toggleFitView);
@@ -3496,14 +3973,14 @@ function createDiagram(opts) {
3496
3973
  }
3497
3974
  function mountResetViewControl(toolbar) {
3498
3975
  if (!resetViewButton) return;
3499
- const button = makeControlButton("Reset", "Reset diagram view");
3976
+ const button = makeControlButton("Reset", "Reset diagram view", ICONS2.resetView);
3500
3977
  button.className = "markdy-control-reset-view";
3501
3978
  button.addEventListener("click", resetViewportTransform);
3502
3979
  toolbar.appendChild(button);
3503
3980
  }
3504
3981
  function mountFullscreenControl(toolbar) {
3505
3982
  if (!fullscreenButton) return;
3506
- const button = makeControlButton("Full", "Toggle fullscreen view");
3983
+ const button = makeControlButton("Full", "Toggle fullscreen view", ICONS2.fullscreen);
3507
3984
  button.className = "markdy-control-fullscreen";
3508
3985
  button.setAttribute("aria-pressed", "false");
3509
3986
  const host = container.parentElement ?? container;
@@ -3584,17 +4061,49 @@ function createDiagram(opts) {
3584
4061
  for (const eventName of ["click", "dblclick", "pointerdown", "pointermove", "pointerup", "wheel"]) {
3585
4062
  toolbar.addEventListener(eventName, (event) => event.stopPropagation());
3586
4063
  }
3587
- mountPlayControl(toolbar);
3588
- mountBeatNavControls(toolbar, "prev");
3589
- mountBeatNavControls(toolbar, "next");
3590
- mountRestartControl(toolbar);
3591
- mountSeekControl(toolbar);
3592
- mountSpeedControls(toolbar);
3593
- mountFitControl(toolbar);
3594
- mountResetViewControl(toolbar);
3595
- mountFullscreenControl(toolbar);
3596
- mountSvgControl(toolbar);
3597
- mountShareControl(toolbar);
4064
+ const playbackGroup = document.createElement("div");
4065
+ playbackGroup.className = "markdy-controls-group markdy-controls-playback";
4066
+ mountPlayControl(playbackGroup);
4067
+ mountBeatNavControls(playbackGroup, "prev");
4068
+ mountBeatNavControls(playbackGroup, "next");
4069
+ mountRestartControl(playbackGroup);
4070
+ if (playbackGroup.children.length > 0) toolbar.appendChild(playbackGroup);
4071
+ if (seekBar) {
4072
+ const timelineGroup = document.createElement("div");
4073
+ timelineGroup.className = "markdy-controls-group markdy-controls-timeline";
4074
+ mountSeekControl(timelineGroup);
4075
+ toolbar.appendChild(timelineGroup);
4076
+ }
4077
+ const toolsGroup = document.createElement("div");
4078
+ toolsGroup.className = "markdy-controls-group markdy-controls-tools";
4079
+ if (speedControls) {
4080
+ const speedGroup = document.createElement("div");
4081
+ speedGroup.className = "markdy-speed-group";
4082
+ mountSpeedControls(speedGroup);
4083
+ toolsGroup.appendChild(speedGroup);
4084
+ }
4085
+ if (fitViewButton || resetViewButton || fullscreenButton) {
4086
+ if (toolsGroup.children.length > 0) {
4087
+ const divider = document.createElement("div");
4088
+ divider.className = "markdy-control-divider";
4089
+ toolsGroup.appendChild(divider);
4090
+ }
4091
+ mountFitControl(toolsGroup);
4092
+ mountResetViewControl(toolsGroup);
4093
+ mountFullscreenControl(toolsGroup);
4094
+ }
4095
+ if (svgButton || shareButton || codeButton || themeButton) {
4096
+ if (toolsGroup.children.length > 0) {
4097
+ const divider = document.createElement("div");
4098
+ divider.className = "markdy-control-divider";
4099
+ toolsGroup.appendChild(divider);
4100
+ }
4101
+ mountThemeControl(toolsGroup);
4102
+ mountSvgControl(toolsGroup);
4103
+ mountShareControl(toolsGroup);
4104
+ mountCodeControl(toolsGroup);
4105
+ }
4106
+ if (toolsGroup.children.length > 0) toolbar.appendChild(toolsGroup);
3598
4107
  ensureFooter().insertBefore(toolbar, badge ?? null);
3599
4108
  syncControls();
3600
4109
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@markdy/renderer-dom",
3
- "version": "1.0.12",
3
+ "version": "1.0.14",
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.12"
48
+ "@markdy/core": "1.0.14"
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.12"
55
+ "@markdy/stdlib-systems": "1.0.14"
56
56
  },
57
57
  "scripts": {
58
58
  "build": "tsup",