sketchmark 1.1.1 → 1.1.3

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.
@@ -20,6 +20,7 @@ export declare class AnimationController {
20
20
  private _config?;
21
21
  private _step;
22
22
  private _pendingStepTimers;
23
+ private _pendingNarrationTimers;
23
24
  private _transforms;
24
25
  private _listeners;
25
26
  readonly drawTargetEdges: Set<string>;
@@ -34,6 +35,7 @@ export declare class AnimationController {
34
35
  private readonly _groupDescendantIds;
35
36
  private _captionEl;
36
37
  private _captionTextEl;
38
+ private _narrationRunId;
37
39
  private _annotationLayer;
38
40
  private _annotations;
39
41
  private _pointerEl;
@@ -67,7 +69,10 @@ export declare class AnimationController {
67
69
  prev(): boolean;
68
70
  play(msPerStep?: number): Promise<void>;
69
71
  goTo(index: number): void;
72
+ private _clearTimerBucket;
70
73
  private _clearPendingStepTimers;
74
+ private _cancelNarrationTyping;
75
+ private _scheduleTimer;
71
76
  private _scheduleStep;
72
77
  private _stepWaitMs;
73
78
  private _playbackWaitMs;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/animation/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/animation/index.ts"],"names":[],"mappings":"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"}
package/dist/index.cjs CHANGED
@@ -9248,11 +9248,13 @@ class AnimationController {
9248
9248
  this._config = _config;
9249
9249
  this._step = -1;
9250
9250
  this._pendingStepTimers = new Set();
9251
+ this._pendingNarrationTimers = new Set();
9251
9252
  this._transforms = new Map();
9252
9253
  this._listeners = [];
9253
9254
  // ── Narration caption ──
9254
9255
  this._captionEl = null;
9255
9256
  this._captionTextEl = null;
9257
+ this._narrationRunId = 0;
9256
9258
  // ── Annotations ──
9257
9259
  this._annotationLayer = null;
9258
9260
  this._annotations = [];
@@ -9515,20 +9517,30 @@ class AnimationController {
9515
9517
  }
9516
9518
  this.emit("step-change");
9517
9519
  }
9520
+ _clearTimerBucket(bucket) {
9521
+ bucket.forEach((id) => window.clearTimeout(id));
9522
+ bucket.clear();
9523
+ }
9518
9524
  _clearPendingStepTimers() {
9519
- this._pendingStepTimers.forEach((id) => window.clearTimeout(id));
9520
- this._pendingStepTimers.clear();
9525
+ this._clearTimerBucket(this._pendingStepTimers);
9521
9526
  }
9522
- _scheduleStep(fn, delayMs) {
9527
+ _cancelNarrationTyping() {
9528
+ this._narrationRunId += 1;
9529
+ this._clearTimerBucket(this._pendingNarrationTimers);
9530
+ }
9531
+ _scheduleTimer(fn, delayMs, bucket = this._pendingStepTimers) {
9523
9532
  if (delayMs <= 0) {
9524
9533
  fn();
9525
9534
  return;
9526
9535
  }
9527
9536
  const id = window.setTimeout(() => {
9528
- this._pendingStepTimers.delete(id);
9537
+ bucket.delete(id);
9529
9538
  fn();
9530
9539
  }, delayMs);
9531
- this._pendingStepTimers.add(id);
9540
+ bucket.add(id);
9541
+ }
9542
+ _scheduleStep(fn, delayMs) {
9543
+ this._scheduleTimer(fn, delayMs, this._pendingStepTimers);
9532
9544
  }
9533
9545
  _stepWaitMs(step, fallbackMs) {
9534
9546
  const delay = Math.max(0, step.delay ?? 0);
@@ -9572,6 +9584,7 @@ class AnimationController {
9572
9584
  }
9573
9585
  _clearAll() {
9574
9586
  this._clearPendingStepTimers();
9587
+ this._cancelNarrationTyping();
9575
9588
  this._cancelSpeech();
9576
9589
  this._transforms.clear();
9577
9590
  // Nodes
@@ -10126,6 +10139,7 @@ class AnimationController {
10126
10139
  _doNarrate(text, silent) {
10127
10140
  if (!this._captionEl || !this._captionTextEl)
10128
10141
  return;
10142
+ this._cancelNarrationTyping();
10129
10143
  this._captionEl.style.opacity = "1";
10130
10144
  if (silent || !text) {
10131
10145
  this._captionTextEl.textContent = text;
@@ -10136,12 +10150,16 @@ class AnimationController {
10136
10150
  this._speak(text);
10137
10151
  // Typing effect
10138
10152
  this._captionTextEl.textContent = "";
10153
+ const narrationRunId = this._narrationRunId;
10139
10154
  let charIdx = 0;
10140
10155
  const typeNext = () => {
10156
+ if (this._narrationRunId !== narrationRunId || !this._captionTextEl)
10157
+ return;
10141
10158
  if (charIdx < text.length) {
10142
10159
  this._captionTextEl.textContent += text[charIdx++];
10143
- const id = window.setTimeout(typeNext, ANIMATION.narrationTypeMs);
10144
- this._pendingStepTimers.add(id);
10160
+ if (charIdx < text.length) {
10161
+ this._scheduleTimer(typeNext, ANIMATION.narrationTypeMs, this._pendingNarrationTimers);
10162
+ }
10145
10163
  }
10146
10164
  };
10147
10165
  typeNext();
@@ -10251,12 +10269,11 @@ class AnimationController {
10251
10269
  requestAnimationFrame(animate);
10252
10270
  }
10253
10271
  // After guide finishes: reveal rough.js element, remove guide
10254
- const id = window.setTimeout(() => {
10272
+ this._scheduleTimer(() => {
10255
10273
  roughEl.style.transition = `opacity 120ms ease`;
10256
10274
  roughEl.style.opacity = "1";
10257
10275
  guide.remove();
10258
10276
  }, dur + 30);
10259
- this._pendingStepTimers.add(id);
10260
10277
  }));
10261
10278
  }
10262
10279
  _doAnnotationCircle(target, silent) {
@@ -10567,13 +10584,13 @@ function exportHTML(svg, dslSource, opts = {}) {
10567
10584
  </head>
10568
10585
  <body>
10569
10586
  <div class="diagram">${svgStr}</div>
10570
- <details class="dsl"><summary style="cursor:pointer;color:#f0c96a">DSL source</summary><pre>${escapeHtml(dslSource)}</pre></details>
10587
+ <details class="dsl"><summary style="cursor:pointer;color:#f0c96a">DSL source</summary><pre>${escapeHtml$1(dslSource)}</pre></details>
10571
10588
  </body>
10572
10589
  </html>`;
10573
10590
  const blob = new Blob([html], { type: 'text/html;charset=utf-8' });
10574
10591
  download(blob, opts.filename ?? 'diagram.html');
10575
10592
  }
10576
- function escapeHtml(s) {
10593
+ function escapeHtml$1(s) {
10577
10594
  return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
10578
10595
  }
10579
10596
  // ── GIF stub (requires gifshot or gif.js at runtime) ──────
@@ -10799,7 +10816,7 @@ const CANVAS_CSS = `
10799
10816
  .skm-canvas__viewport.is-panning{cursor:grabbing}
10800
10817
  .skm-canvas--dark .skm-canvas__viewport{background:#12100a}
10801
10818
  .skm-canvas__grid{position:absolute;inset:0;width:100%;height:100%;pointer-events:none}
10802
- .skm-canvas__world{position:absolute;top:0;left:0;transform-origin:0 0;will-change:transform}
10819
+ .skm-canvas__world{position:absolute;top:0;left:0;transform-origin:0 0;}
10803
10820
  .skm-canvas__controls{position:absolute;right:14px;bottom:14px;display:flex;flex-direction:column;align-items:center;gap:4px;z-index:2}
10804
10821
  .skm-canvas__zoom{min-width:40px;text-align:center;color:#8a6040;font-size:10px}
10805
10822
  .skm-canvas__minimap{position:absolute;left:14px;bottom:14px;width:120px;height:80px;background:rgba(255,248,234,.94);border:1px solid #caba98;border-radius:6px;overflow:hidden;z-index:2}
@@ -11449,20 +11466,44 @@ const EDITOR_CSS = `
11449
11466
  color: #fff;
11450
11467
  }
11451
11468
 
11452
- .skm-editor__input {
11469
+ .skm-editor__surface {
11470
+ position: relative;
11453
11471
  flex: 1;
11454
- width: 100%;
11455
11472
  min-height: 0;
11456
- border: 0;
11457
- outline: 0;
11458
- resize: none;
11459
11473
  background: #1c1608;
11460
- color: #e0c898;
11474
+ overflow: hidden;
11475
+ }
11476
+
11477
+ .skm-editor__highlight,
11478
+ .skm-editor__input {
11479
+ position: absolute;
11480
+ inset: 0;
11481
+ width: 100%;
11482
+ height: 100%;
11461
11483
  padding: 12px 14px;
11462
11484
  font: inherit;
11463
11485
  font-size: 12px;
11464
11486
  line-height: 1.7;
11465
11487
  tab-size: 2;
11488
+ white-space: pre-wrap;
11489
+ overflow: auto;
11490
+ }
11491
+
11492
+ .skm-editor__highlight {
11493
+ margin: 0;
11494
+ border: 0;
11495
+ background: #1c1608;
11496
+ color: #e0c898;
11497
+ pointer-events: none;
11498
+ word-break: break-word;
11499
+ }
11500
+
11501
+ .skm-editor__input {
11502
+ border: 0;
11503
+ outline: 0;
11504
+ resize: none;
11505
+ background: transparent;
11506
+ color: transparent;
11466
11507
  caret-color: #f0c96a;
11467
11508
  }
11468
11509
 
@@ -11470,6 +11511,40 @@ const EDITOR_CSS = `
11470
11511
  color: #80633b;
11471
11512
  }
11472
11513
 
11514
+ .skm-editor__input::selection {
11515
+ background: rgba(240, 201, 106, 0.22);
11516
+ }
11517
+
11518
+ .skm-editor__token--keyword {
11519
+ color: #e07040;
11520
+ }
11521
+
11522
+ .skm-editor__token--property {
11523
+ color: #70a8d0;
11524
+ }
11525
+
11526
+ .skm-editor__token--string {
11527
+ color: #8db870;
11528
+ }
11529
+
11530
+ .skm-editor__token--number {
11531
+ color: #d4a020;
11532
+ }
11533
+
11534
+ .skm-editor__token--comment {
11535
+ color: #6a5a3a;
11536
+ }
11537
+
11538
+ .skm-editor__token--connector {
11539
+ color: #c8b070;
11540
+ }
11541
+
11542
+ .skm-editor__token--color {
11543
+ color: var(--skm-editor-color, #f0c96a);
11544
+ box-shadow: inset 0 -1px 0 rgba(255, 255, 255, 0.08);
11545
+ font-weight: 600;
11546
+ }
11547
+
11473
11548
  .skm-editor__error {
11474
11549
  display: none;
11475
11550
  flex-shrink: 0;
@@ -11486,12 +11561,112 @@ const EDITOR_CSS = `
11486
11561
  display: block;
11487
11562
  }
11488
11563
  `;
11564
+ const CONNECTORS = ["<-->", "<->", "-->", "<--", "---", "--", "->", "<-"];
11565
+ const HEX_COLOR_RE = /#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})\b/g;
11489
11566
  function defaultFormatter(value) {
11490
11567
  return normalizeNewlines(value)
11491
11568
  .split("\n")
11492
11569
  .map((line) => line.replace(/[ \t]+$/g, ""))
11493
11570
  .join("\n");
11494
11571
  }
11572
+ function escapeHtml(value) {
11573
+ return value
11574
+ .replace(/&/g, "&amp;")
11575
+ .replace(/</g, "&lt;")
11576
+ .replace(/>/g, "&gt;")
11577
+ .replace(/"/g, "&quot;");
11578
+ }
11579
+ function wrapToken(kind, value) {
11580
+ return `<span class="skm-editor__token skm-editor__token--${kind}">${escapeHtml(value)}</span>`;
11581
+ }
11582
+ function renderColorLiteral(value) {
11583
+ return `<span class="skm-editor__token skm-editor__token--color" style="--skm-editor-color:${value}">${escapeHtml(value)}</span>`;
11584
+ }
11585
+ function renderStringToken(value) {
11586
+ HEX_COLOR_RE.lastIndex = 0;
11587
+ if (!HEX_COLOR_RE.test(value)) {
11588
+ return wrapToken("string", value);
11589
+ }
11590
+ HEX_COLOR_RE.lastIndex = 0;
11591
+ let html = "";
11592
+ let lastIndex = 0;
11593
+ let match = null;
11594
+ while ((match = HEX_COLOR_RE.exec(value))) {
11595
+ if (match.index > lastIndex) {
11596
+ html += wrapToken("string", value.slice(lastIndex, match.index));
11597
+ }
11598
+ html += renderColorLiteral(match[0]);
11599
+ lastIndex = match.index + match[0].length;
11600
+ }
11601
+ if (lastIndex < value.length) {
11602
+ html += wrapToken("string", value.slice(lastIndex));
11603
+ }
11604
+ return html;
11605
+ }
11606
+ function renderPlainToken(value, nextChar) {
11607
+ if (/^-?\d/.test(value)) {
11608
+ return wrapToken("number", value);
11609
+ }
11610
+ if (nextChar === "=") {
11611
+ return wrapToken("property", value);
11612
+ }
11613
+ if (KEYWORDS.has(value)) {
11614
+ return wrapToken("keyword", value);
11615
+ }
11616
+ return escapeHtml(value);
11617
+ }
11618
+ function highlightLine(line) {
11619
+ let html = "";
11620
+ let index = 0;
11621
+ while (index < line.length) {
11622
+ const rest = line.slice(index);
11623
+ if (rest.startsWith("//") || rest.startsWith("#")) {
11624
+ html += wrapToken("comment", rest);
11625
+ break;
11626
+ }
11627
+ if (line[index] === "\"") {
11628
+ let end = index + 1;
11629
+ while (end < line.length) {
11630
+ if (line[end] === "\"" && line[end - 1] !== "\\") {
11631
+ end += 1;
11632
+ break;
11633
+ }
11634
+ end += 1;
11635
+ }
11636
+ html += renderStringToken(line.slice(index, end));
11637
+ index = end;
11638
+ continue;
11639
+ }
11640
+ const connector = CONNECTORS.find((candidate) => line.startsWith(candidate, index));
11641
+ if (connector) {
11642
+ html += wrapToken("connector", connector);
11643
+ index += connector.length;
11644
+ continue;
11645
+ }
11646
+ const wordMatch = /^[A-Za-z_][A-Za-z0-9_-]*/.exec(rest);
11647
+ if (wordMatch) {
11648
+ const word = wordMatch[0];
11649
+ const nextChar = line[index + word.length] ?? "";
11650
+ html += renderPlainToken(word, nextChar);
11651
+ index += word.length;
11652
+ continue;
11653
+ }
11654
+ const numberMatch = /^-?\d+(?:\.\d+)?/.exec(rest);
11655
+ if (numberMatch) {
11656
+ html += wrapToken("number", numberMatch[0]);
11657
+ index += numberMatch[0].length;
11658
+ continue;
11659
+ }
11660
+ html += escapeHtml(line[index]);
11661
+ index += 1;
11662
+ }
11663
+ return html;
11664
+ }
11665
+ function renderHighlightedValue(value) {
11666
+ const normalized = normalizeNewlines(value);
11667
+ const html = normalized.split("\n").map(highlightLine).join("\n");
11668
+ return html || " ";
11669
+ }
11495
11670
  class SketchmarkEditor {
11496
11671
  constructor(options) {
11497
11672
  this.emitter = new EventEmitter();
@@ -11528,16 +11703,23 @@ class SketchmarkEditor {
11528
11703
  if (options.showClearButton !== false)
11529
11704
  this.toolbar.appendChild(clearButton);
11530
11705
  this.toolbar.appendChild(hint);
11706
+ this.surface = document.createElement("div");
11707
+ this.surface.className = "skm-editor__surface";
11708
+ this.highlightElement = document.createElement("pre");
11709
+ this.highlightElement.className = "skm-editor__highlight";
11710
+ this.highlightElement.setAttribute("aria-hidden", "true");
11531
11711
  this.textarea = document.createElement("textarea");
11532
11712
  this.textarea.className = "skm-editor__input";
11533
11713
  this.textarea.spellcheck = false;
11534
11714
  this.textarea.placeholder = options.placeholder ?? "diagram\nbox a label=\"Hello\"\nend";
11535
11715
  this.textarea.value = normalizeNewlines(options.value ?? DEFAULT_CLEAR_VALUE);
11536
11716
  this.textarea.addEventListener("input", () => {
11717
+ this.syncHighlight();
11537
11718
  const payload = { value: this.getValue(), editor: this };
11538
11719
  options.onChange?.(payload.value, this);
11539
11720
  this.emitter.emit("change", payload);
11540
11721
  });
11722
+ this.textarea.addEventListener("scroll", () => this.syncScroll());
11541
11723
  this.textarea.addEventListener("keydown", (event) => {
11542
11724
  if ((event.ctrlKey || event.metaKey) && event.key === "Enter") {
11543
11725
  event.preventDefault();
@@ -11549,9 +11731,12 @@ class SketchmarkEditor {
11549
11731
  if (options.showToolbar !== false) {
11550
11732
  this.root.appendChild(this.toolbar);
11551
11733
  }
11552
- this.root.appendChild(this.textarea);
11734
+ this.surface.appendChild(this.highlightElement);
11735
+ this.surface.appendChild(this.textarea);
11736
+ this.root.appendChild(this.surface);
11553
11737
  this.root.appendChild(this.errorElement);
11554
11738
  host.appendChild(this.root);
11739
+ this.syncHighlight();
11555
11740
  if (options.autoFocus) {
11556
11741
  this.focus();
11557
11742
  }
@@ -11561,6 +11746,7 @@ class SketchmarkEditor {
11561
11746
  }
11562
11747
  setValue(value, emitChange = false) {
11563
11748
  this.textarea.value = normalizeNewlines(value);
11749
+ this.syncHighlight();
11564
11750
  if (emitChange) {
11565
11751
  const payload = { value: this.getValue(), editor: this };
11566
11752
  this.options.onChange?.(payload.value, this);
@@ -11602,6 +11788,14 @@ class SketchmarkEditor {
11602
11788
  destroy() {
11603
11789
  this.root.remove();
11604
11790
  }
11791
+ syncHighlight() {
11792
+ this.highlightElement.innerHTML = renderHighlightedValue(this.textarea.value);
11793
+ this.syncScroll();
11794
+ }
11795
+ syncScroll() {
11796
+ this.highlightElement.scrollTop = this.textarea.scrollTop;
11797
+ this.highlightElement.scrollLeft = this.textarea.scrollLeft;
11798
+ }
11605
11799
  }
11606
11800
 
11607
11801
  const EMBED_STYLE_ID = "sketchmark-embed-ui";