@helping-ai-workflow/md2doc 3.17.0 → 3.17.1

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.
@@ -2503,9 +2503,11 @@ function sameLane(a, b) {
2503
2503
  * Paint one cycle of one lane, addressed by display index.
2504
2504
  *
2505
2505
  * `ch` is a single character: a level, a value character, `|` for a gap, or `.`
2506
- * to make the cycle continue the one in front of it. Anything else — a longer
2507
- * string, a cycle outside the lane, a `.` or `|` at cycle 0 where there is
2508
- * nothing to continue or to draw over — answers the doc unchanged.
2506
+ * to make the cycle continue the one in front of it. A cycle past the lane's
2507
+ * end grows the lane first, continuing its last level up to that cycle (see
2508
+ * `paint`). Anything else — a longer string, a negative or fractional cycle, a
2509
+ * `.` or `|` at cycle 0 where there is nothing to continue or to draw over —
2510
+ * answers the doc unchanged.
2509
2511
  *
2510
2512
  * A newly painted value cell keeps the label of the value cell it replaced and
2511
2513
  * otherwise starts blank; a cell painted with something that is not a value
@@ -2542,12 +2544,20 @@ function paint(doc, laneIndex, from, to, ch, asRun) {
2542
2544
  lo = hi;
2543
2545
  hi = swap;
2544
2546
  }
2545
- if (!isIndex(lo, n) || !isIndex(hi, n)) return null;
2547
+ if (lo < 0) return null;
2546
2548
  // A repeater at cycle 0 has nothing to repeat, and the engine answers that
2547
2549
  // by drawing the run and the cycle after it as x. Refusing is the honest
2548
2550
  // reply to a brush that cannot mean anything where it was aimed.
2549
2551
  if (lo === 0 && (ch === HELD_CHAR || ch === GAP_CHAR)) return null;
2550
- const anchored = anchorAfter(model.cells, hi);
2552
+ // Past the lane's end: continue its last level up to `hi` first, then
2553
+ // paint. A lane shorter than the diagram is ordinary (新增訊號 writes one
2554
+ // cycle, hand-written lanes differ in length) and the editor's grid is as
2555
+ // wide as the whole diagram, so `geometry.cellAt` hands out these cells on
2556
+ // purpose; refusing them here left every click past a short lane's end
2557
+ // silently doing nothing. How far past is bounded by the caller (the
2558
+ // grid), not here.
2559
+ const grown = hi < n ? model.cells : model.cells.concat(fillerCells(model.cells, n, hi + 1 - n));
2560
+ const anchored = anchorAfter(grown, hi);
2551
2561
  const before = resolveCells(anchored);
2552
2562
  const heldLevel = lo > 0 ? before.levels[lo - 1] : '';
2553
2563
  const cells = anchored.slice();
@@ -1690,6 +1690,14 @@
1690
1690
  if (added) notify('notice', lead + where);
1691
1691
  return added;
1692
1692
  }
1693
+ /** The lane 新增訊號 writes: `x` across the whole diagram, not one cycle
1694
+ * of it. A one-cycle lane draws a single x and then nothing, which read
1695
+ * as a broken signal (user report 2026-10-28), and every cycle after it
1696
+ * had to be grown by painting before it showed anything. */
1697
+ function newSignalLane() {
1698
+ const cycles = layoutNow().cycles;
1699
+ return { name: '', wave: 'x' + '.'.repeat(Math.max(0, cycles - 1)) };
1700
+ }
1693
1701
  function addLaneFromToolbar(name, lane) {
1694
1702
  addLaneAt(signalInsertAt(), name, lane);
1695
1703
  }
@@ -1705,7 +1713,7 @@
1705
1713
  const el = panels.menu('ed-wave-signal-pop', [
1706
1714
  { key: 'ed-wave-signal-add', label: '新增訊號',
1707
1715
  title: '在選取的 lane 後面加一條(沒有選取就加在最前面)—— 會落在' + where,
1708
- run: function () { closePopover(true); addLaneFromToolbar('add-lane', { name: '', wave: 'x' }); } },
1716
+ run: function () { closePopover(true); addLaneFromToolbar('add-lane', newSignalLane()); } },
1709
1717
  { key: 'ed-wave-signal-blank', label: '新增空白列',
1710
1718
  title: '在選取的 lane 後面插入一個空白列(WaveJSON 的 {},用來空出間距)—— 會落在' + where,
1711
1719
  run: function () { closePopover(true); addLaneFromToolbar('add-spacer', {}); } },
@@ -1950,7 +1958,7 @@
1950
1958
  const row = layoutNow().lanes[i];
1951
1959
  const actions = {
1952
1960
  copy: picked(function () { duplicateLaneAt(i); }),
1953
- addBelow: picked(function () { addLaneAt(i + 1, 'add-lane', { name: '', wave: 'x' }); }),
1961
+ addBelow: picked(function () { addLaneAt(i + 1, 'add-lane', newSignalLane()); }),
1954
1962
  blankBelow: picked(function () { addLaneAt(i + 1, 'add-spacer', {}); }),
1955
1963
  up: picked(function () { moveLaneBy(i, -1); }),
1956
1964
  down: picked(function () { moveLaneBy(i, 1); }),
@@ -2473,7 +2481,7 @@
2473
2481
  // signal at the end — the one insert position the ⠿ menus (which add
2474
2482
  // BELOW a row) and 訊號 (after the selection) do not make obvious.
2475
2483
  panels.toolButton('ed-wave-add-lane', '+ 新增訊號', '在最後面加一條訊號', function () {
2476
- addLaneAt(layoutNow().lanes.length, 'add-lane', { name: '', wave: 'x' });
2484
+ addLaneAt(layoutNow().lanes.length, 'add-lane', newSignalLane());
2477
2485
  }, stage);
2478
2486
  // One canvas per editor session (spec §3.2); `close()` destroys it.
2479
2487
  engineCanvas = opts.canvas.createCanvas({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@helping-ai-workflow/md2doc",
3
- "version": "3.17.0",
3
+ "version": "3.17.1",
4
4
  "description": "Markdown → HTML / PDF renderer with WaveDrom, Mermaid, Graphviz, and draw.io support",
5
5
  "keywords": [
6
6
  "markdown",