@diagrammo/dgmo 0.39.0 → 0.40.0

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.
package/dist/auto.cjs CHANGED
@@ -105,7 +105,7 @@ function vennAliasKeywordRemovedMessage(args) {
105
105
  return `Venn 'alias' keyword was removed. Use 'as' instead \u2014 '${args.name} as ${args.alias}'.`;
106
106
  }
107
107
  function pipeOperatorRemovedMessage() {
108
- return `'|' removed \u2014 'Node | c: red' \u2192 'Node c: red'`;
108
+ return `'|' is no longer metadata syntax \u2014 write metadata inline as 'key: value' (e.g. "Name color: red"), or remove the '|'.`;
109
109
  }
110
110
  function ganttBarePercentRemovedMessage(percent) {
111
111
  return `Bare-percent progress shorthand '| ${percent}' was removed. Use 'progress: ${percent.replace(/%$/, "")}' (integer 0\u2013100, no '%').`;
@@ -13609,7 +13609,8 @@ function buildScatterOption(parsed, palette, isDark, textColor, axisLineColor, g
13609
13609
  solid: parsed.solidFill === true
13610
13610
  }),
13611
13611
  borderColor: catColor,
13612
- borderWidth: CHART_BORDER_WIDTH
13612
+ borderWidth: CHART_BORDER_WIDTH,
13613
+ opacity: SCATTER_FILL_OPACITY
13613
13614
  },
13614
13615
  label: labelConfig,
13615
13616
  emphasis: emphasisConfig,
@@ -13636,6 +13637,7 @@ function buildScatterOption(parsed, palette, isDark, textColor, axisLineColor, g
13636
13637
  {
13637
13638
  type: "scatter",
13638
13639
  data,
13640
+ itemStyle: { opacity: SCATTER_FILL_OPACITY },
13639
13641
  label: labelConfig,
13640
13642
  emphasis: emphasisConfig,
13641
13643
  blur: blurConfig
@@ -14941,7 +14943,7 @@ async function renderExtendedChartForExport(content, theme, palette) {
14941
14943
  chart.dispose();
14942
14944
  }
14943
14945
  }
14944
- var echarts, import_charts, import_components, import_renderers, EMPHASIS_SELF, EMPHASIS_SERIES, BLUR_DIM, EMPHASIS_LINE, CHART_BASE, CHART_BORDER_WIDTH, VALID_EXTENDED_TYPES, KNOWN_EXTENDED_OPTIONS, EXTENDED_CHART_DOORS, FIT_PADDING, OFFSCREEN, fitStackedLabelToSegment, ECHART_EXPORT_WIDTH, ECHART_EXPORT_HEIGHT, STANDARD_CHART_TYPES;
14946
+ var echarts, import_charts, import_components, import_renderers, EMPHASIS_SELF, EMPHASIS_SERIES, BLUR_DIM, EMPHASIS_LINE, CHART_BASE, CHART_BORDER_WIDTH, SCATTER_FILL_OPACITY, VALID_EXTENDED_TYPES, KNOWN_EXTENDED_OPTIONS, EXTENDED_CHART_DOORS, FIT_PADDING, OFFSCREEN, fitStackedLabelToSegment, ECHART_EXPORT_WIDTH, ECHART_EXPORT_HEIGHT, STANDARD_CHART_TYPES;
14945
14947
  var init_echarts = __esm({
14946
14948
  "src/echarts.ts"() {
14947
14949
  "use strict";
@@ -14999,6 +15001,7 @@ var init_echarts = __esm({
14999
15001
  tooltip: { show: false }
15000
15002
  };
15001
15003
  CHART_BORDER_WIDTH = 2;
15004
+ SCATTER_FILL_OPACITY = 0.65;
15002
15005
  VALID_EXTENDED_TYPES = /* @__PURE__ */ new Set([
15003
15006
  "sankey",
15004
15007
  "chord",
@@ -15274,8 +15277,61 @@ function parseEventLine(content, palette) {
15274
15277
  EVENT_LINE_DIAGNOSTIC_CODES.NO_EVENTS
15275
15278
  );
15276
15279
  }
15280
+ if (options.scale) {
15281
+ validateEraDateOrder(result.events, result.eras, pushWarning);
15282
+ }
15277
15283
  return result;
15278
15284
  }
15285
+ function validateEraDateOrder(events, eras, pushWarning) {
15286
+ if (eras.length < 2) return;
15287
+ const order = new Map(eras.map((e, i) => [e.name, i]));
15288
+ const dated = events.filter(
15289
+ (e) => e.dateValue !== null && e.era !== null && order.has(e.era)
15290
+ );
15291
+ if (dated.length === 0) return;
15292
+ const perEra = /* @__PURE__ */ new Map();
15293
+ for (const ev of dated) {
15294
+ const idx = order.get(ev.era);
15295
+ const cur = perEra.get(idx);
15296
+ if (!cur) {
15297
+ perEra.set(idx, { min: ev, max: ev });
15298
+ } else {
15299
+ if (ev.dateValue < cur.min.dateValue) cur.min = ev;
15300
+ if (ev.dateValue > cur.max.dateValue) cur.max = ev;
15301
+ }
15302
+ }
15303
+ const n = eras.length;
15304
+ const prefixMax = new Array(n).fill(null);
15305
+ const suffixMin = new Array(n).fill(null);
15306
+ for (let k = 1; k < n; k++) {
15307
+ const prev = perEra.get(k - 1)?.max ?? null;
15308
+ const carried = prefixMax[k - 1] ?? null;
15309
+ prefixMax[k] = prev && (!carried || prev.dateValue > carried.dateValue) ? prev : carried;
15310
+ }
15311
+ for (let k = n - 2; k >= 0; k--) {
15312
+ const next = perEra.get(k + 1)?.min ?? null;
15313
+ const carried = suffixMin[k + 1] ?? null;
15314
+ suffixMin[k] = next && (!carried || next.dateValue < carried.dateValue) ? next : carried;
15315
+ }
15316
+ for (const ev of dated) {
15317
+ const k = order.get(ev.era);
15318
+ const ahead = suffixMin[k];
15319
+ const behind = prefixMax[k];
15320
+ if (ahead && ev.dateValue > ahead.dateValue) {
15321
+ pushWarning(
15322
+ ev.lineNumber,
15323
+ `"${ev.label}" (${ev.date}) is in era "${ev.era}" but dated after era "${ahead.era}" begins (${ahead.date}). event-line eras run left-to-right by date \u2014 fix the date or move it to the right era, or their brackets will overlap.`,
15324
+ EVENT_LINE_DIAGNOSTIC_CODES.ERA_DATE_ORDER
15325
+ );
15326
+ } else if (behind && ev.dateValue < behind.dateValue) {
15327
+ pushWarning(
15328
+ ev.lineNumber,
15329
+ `"${ev.label}" (${ev.date}) is in era "${ev.era}" but dated before era "${behind.era}" ends (${behind.date}). event-line eras run left-to-right by date \u2014 fix the date or move it to the right era, or their brackets will overlap.`,
15330
+ EVENT_LINE_DIAGNOSTIC_CODES.ERA_DATE_ORDER
15331
+ );
15332
+ }
15333
+ }
15334
+ }
15279
15335
  function parseEventHeader(trimmed, lineNumber, era, aliasMap, diagnostics, pushWarning) {
15280
15336
  let date = null;
15281
15337
  let dateValue = null;
@@ -15342,7 +15398,8 @@ var init_parser13 = __esm({
15342
15398
  EVENT_LINE_DIAGNOSTIC_CODES = {
15343
15399
  NO_EVENTS: "E_EVENT_LINE_NO_EVENTS",
15344
15400
  BAD_DATE: "E_EVENT_LINE_BAD_DATE",
15345
- UNSUPPORTED: "E_EVENT_LINE_UNSUPPORTED"
15401
+ UNSUPPORTED: "E_EVENT_LINE_UNSUPPORTED",
15402
+ ERA_DATE_ORDER: "E_EVENT_LINE_ERA_DATE_ORDER"
15346
15403
  };
15347
15404
  NON_ISO_DATE_RE = /^\d{1,4}[/.]\d/;
15348
15405
  SIDE_RE = /^side\s+(above|below|alternate)\b/i;
@@ -26278,9 +26335,6 @@ function renderEventLine(container, parsed, palette, isDark, onClickItem, export
26278
26335
  const hasExpandedEra = parsed.events.some(
26279
26336
  (e) => e.era && eraByName.has(e.era) && !collapsedSet.has(e.era)
26280
26337
  );
26281
- const anyCollapsed = parsed.events.some(
26282
- (e) => e.era && collapsedSet.has(e.era)
26283
- );
26284
26338
  const sideOpt = parsed.options.side;
26285
26339
  const alternate = sideOpt === "alternate";
26286
26340
  const eraSide = alternate ? "below" : sideOpt === "above" ? "below" : "above";
@@ -26347,7 +26401,8 @@ function renderEventLine(container, parsed, palette, isDark, onClickItem, export
26347
26401
  x: 0,
26348
26402
  side,
26349
26403
  lane: 0,
26350
- left: 0
26404
+ left: 0,
26405
+ spanHalf: 0
26351
26406
  };
26352
26407
  }
26353
26408
  const era = slot.era;
@@ -26360,19 +26415,19 @@ function renderEventLine(container, parsed, palette, isDark, onClickItem, export
26360
26415
  palette.textOnFillLight,
26361
26416
  palette.textOnFillDark
26362
26417
  );
26363
- const overflow = slot.members.length > ERA_MEMBER_MAX;
26364
- const shown = overflow ? slot.members.slice(0, ERA_MEMBER_MAX - 1) : slot.members;
26365
- const memberStrs = shown.map(
26418
+ let spanLo = null;
26419
+ let spanHi = null;
26420
+ for (const m of slot.members) {
26421
+ if (m.dateValue === null) continue;
26422
+ if (spanLo === null || m.dateValue < spanLo) spanLo = m.dateValue;
26423
+ if (spanHi === null || m.dateValue > spanHi) spanHi = m.dateValue;
26424
+ }
26425
+ const repDateValue = spanLo !== null && spanHi !== null ? (spanLo + spanHi) / 2 : null;
26426
+ const memberStrs = slot.members.map(
26366
26427
  (m) => `\u2022 ${m.date ? `${m.date} ` : ""}${m.label}`
26367
26428
  );
26368
- const bulletColors = shown.map(eventColor);
26429
+ const bulletColors = slot.members.map(eventColor);
26369
26430
  const lines = wrapDescription(memberStrs, charsPerLine);
26370
- if (overflow) {
26371
- lines.push({
26372
- text: `+${slot.members.length - (ERA_MEMBER_MAX - 1)} more`,
26373
- kind: "plain"
26374
- });
26375
- }
26376
26431
  return {
26377
26432
  kind: "era",
26378
26433
  event: null,
@@ -26380,7 +26435,7 @@ function renderEventLine(container, parsed, palette, isDark, onClickItem, export
26380
26435
  members: slot.members,
26381
26436
  label: era.name,
26382
26437
  date: null,
26383
- dateValue: null,
26438
+ dateValue: repDateValue,
26384
26439
  lineNumber: era.lineNumber,
26385
26440
  eraName: era.name,
26386
26441
  color: solid,
@@ -26392,87 +26447,189 @@ function renderEventLine(container, parsed, palette, isDark, onClickItem, export
26392
26447
  x: 0,
26393
26448
  side,
26394
26449
  lane: 0,
26395
- left: 0
26450
+ left: 0,
26451
+ spanHalf: 0
26396
26452
  };
26397
26453
  });
26398
- const scaled = parsed.options.scale && !anyCollapsed && placed.every((p) => p.dateValue !== null);
26454
+ const scaled = parsed.options.scale && placed.every((p) => p.dateValue !== null);
26399
26455
  const innerW = width - H_MARGIN * 2;
26400
- if (scaled) {
26401
- const vals = placed.map((p) => p.dateValue);
26402
- const lo = Math.min(...vals);
26403
- const hi = Math.max(...vals);
26404
- placed.forEach((p) => {
26405
- p.x = H_MARGIN + (hi > lo ? (p.dateValue - lo) / (hi - lo) * innerW : innerW / 2);
26456
+ const MIN_DOT_GAP = 16;
26457
+ const STRETCH_CAP = 8;
26458
+ const COLLAPSE_W = 64;
26459
+ const SEG_GAP = 16;
26460
+ const segments = [];
26461
+ let run2 = [];
26462
+ const flushRun = () => {
26463
+ if (!run2.length) return;
26464
+ const ds = run2.map((e) => e.dateValue);
26465
+ segments.push({
26466
+ kind: "run",
26467
+ events: run2,
26468
+ lo: Math.min(...ds),
26469
+ hi: Math.max(...ds)
26406
26470
  });
26407
- const MIN_DOT_GAP = 16;
26408
- let prevX = -Infinity;
26409
- let prevVal = null;
26410
- for (const p of [...placed].sort((a, b) => a.x - b.x)) {
26411
- if (p.dateValue === prevVal) {
26412
- p.x = prevX;
26413
- continue;
26471
+ run2 = [];
26472
+ };
26473
+ for (const p of placed) {
26474
+ if (p.kind === "era") {
26475
+ flushRun();
26476
+ segments.push({ kind: "capsule", p });
26477
+ } else {
26478
+ run2.push(p);
26479
+ }
26480
+ }
26481
+ flushRun();
26482
+ const totalRunTime = segments.reduce(
26483
+ (s, seg) => s + (seg.kind === "run" ? seg.hi - seg.lo : 0),
26484
+ 0
26485
+ );
26486
+ const place = (stretch) => {
26487
+ if (scaled) {
26488
+ const pxPerUnit = totalRunTime > 0 ? innerW * stretch / totalRunTime : 0;
26489
+ let cursor = H_MARGIN;
26490
+ for (const seg of segments) {
26491
+ if (seg.kind === "capsule") {
26492
+ seg.p.x = cursor + COLLAPSE_W / 2;
26493
+ seg.p.spanHalf = COLLAPSE_W / 2;
26494
+ cursor += COLLAPSE_W + SEG_GAP;
26495
+ } else {
26496
+ for (const e of seg.events) {
26497
+ e.x = cursor + (e.dateValue - seg.lo) * pxPerUnit;
26498
+ e.spanHalf = 0;
26499
+ }
26500
+ cursor += (seg.hi - seg.lo) * pxPerUnit + SEG_GAP;
26501
+ }
26502
+ }
26503
+ let prevX = -Infinity;
26504
+ let prevVal = null;
26505
+ for (const p of [...placed].sort((a, b) => a.x - b.x)) {
26506
+ if (p.kind === "era") {
26507
+ prevX = p.x + p.spanHalf;
26508
+ prevVal = null;
26509
+ continue;
26510
+ }
26511
+ if (p.dateValue === prevVal) {
26512
+ p.x = prevX;
26513
+ continue;
26514
+ }
26515
+ if (p.x < prevX + MIN_DOT_GAP) p.x = prevX + MIN_DOT_GAP;
26516
+ prevX = p.x;
26517
+ prevVal = p.dateValue;
26518
+ }
26519
+ } else {
26520
+ placed.forEach((p) => {
26521
+ p.spanHalf = 0;
26522
+ });
26523
+ const n = placed.length;
26524
+ const spacing = n > 1 ? Math.max(MIN_SPACING, innerW / (n - 1)) : 0;
26525
+ placed.forEach((p, i) => {
26526
+ p.x = H_MARGIN + i * spacing;
26527
+ });
26528
+ }
26529
+ for (const side of ["above", "below"]) {
26530
+ const arr = placed.filter((p) => p.side === side).sort((a, b) => a.x - b.x);
26531
+ const laneRight = [];
26532
+ for (let i = 0; i < arr.length; i++) {
26533
+ const p = arr[i];
26534
+ const next = arr[i + 1];
26535
+ const crowdedRight = !!next && next.x - p.x < CARD_W + FAN_GAP;
26536
+ const preferred = crowdedRight ? p.x - CARD_W + CARD_INSET : p.x - CARD_W / 2;
26537
+ const maxLeft = p.x - CARD_INSET;
26538
+ const minLeft = p.x - CARD_W + CARD_INSET;
26539
+ let lane = laneRight.length;
26540
+ let left = Math.max(preferred, minLeft);
26541
+ for (let l = 0; l < laneRight.length; l++) {
26542
+ const want = Math.max(preferred, laneRight[l] + FAN_GAP, minLeft);
26543
+ if (want <= maxLeft) {
26544
+ lane = l;
26545
+ left = want;
26546
+ break;
26547
+ }
26548
+ }
26549
+ p.lane = lane;
26550
+ p.left = Math.max(6, left);
26551
+ laneRight[lane] = p.left + CARD_W;
26552
+ }
26553
+ }
26554
+ };
26555
+ const derive = () => {
26556
+ const contentW2 = Math.max(
26557
+ width,
26558
+ Math.max(...placed.map((p) => p.x + p.spanHalf)) + H_MARGIN,
26559
+ Math.max(...placed.map((p) => p.left + CARD_W)) + 6
26560
+ );
26561
+ const laneOffset = { above: [], below: [] };
26562
+ for (const side of ["above", "below"]) {
26563
+ const laneH = [];
26564
+ for (const p of placed) {
26565
+ if (p.side !== side) continue;
26566
+ laneH[p.lane] = Math.max(laneH[p.lane] ?? 0, p.cardH);
26414
26567
  }
26415
- if (p.x < prevX + MIN_DOT_GAP) p.x = prevX + MIN_DOT_GAP;
26416
- prevX = p.x;
26417
- prevVal = p.dateValue;
26568
+ const off = [];
26569
+ let acc = 0;
26570
+ for (let l = 0; l < laneH.length; l++) {
26571
+ off[l] = acc;
26572
+ acc += (laneH[l] ?? 0) + LANE_GAP;
26573
+ }
26574
+ laneOffset[side] = off;
26418
26575
  }
26576
+ const laneNear2 = (p) => (p.side === "above" ? LEADER_ABOVE : LEADER_BELOW) + (laneOffset[p.side][p.lane] ?? 0);
26577
+ const ext = (side) => Math.max(
26578
+ 0,
26579
+ ...placed.filter((p) => p.side === side).map((p) => laneNear2(p) + p.cardH)
26580
+ );
26581
+ const dateAbove = placed.some((p) => p.side === "below" && p.date);
26582
+ const dateBelow = placed.some((p) => p.side === "above" && p.date);
26583
+ const contentAbove = Math.max(
26584
+ ext("above"),
26585
+ dateAbove ? DATE_OFFSET + 10 : 0
26586
+ );
26587
+ const contentBelow = Math.max(
26588
+ ext("below"),
26589
+ dateBelow ? DATE_OFFSET + 10 : 0
26590
+ );
26591
+ const aboveExt = contentAbove + (hasExpandedEra && eraSide === "above" ? ERA_BLOCK : 0);
26592
+ const belowExt = contentBelow + (hasExpandedEra && eraSide === "below" ? ERA_BLOCK : 0);
26593
+ const TOP_PAD = 14;
26594
+ const BOT_PAD = 14;
26595
+ const spineY2 = topUsed + TOP_PAD + aboveExt;
26596
+ const eraBaseY2 = eraSide === "above" ? spineY2 - (contentAbove + 14) : spineY2 + (contentBelow + 14);
26597
+ const contentH = spineY2 + belowExt + BOT_PAD;
26598
+ const totalH2 = Math.max(heightHint, contentH);
26599
+ return { contentW: contentW2, contentH, totalH: totalH2, spineY: spineY2, eraBaseY: eraBaseY2, laneNear: laneNear2 };
26600
+ };
26601
+ const envStretch = Number(
26602
+ globalThis.process?.env?.["DGMO_EVT_STRETCH"]
26603
+ );
26604
+ let layout;
26605
+ if (Number.isFinite(envStretch) && envStretch > 0) {
26606
+ place(envStretch);
26607
+ layout = derive();
26419
26608
  } else {
26420
- const n = placed.length;
26421
- const spacing = n > 1 ? Math.max(MIN_SPACING, innerW / (n - 1)) : 0;
26422
- placed.forEach((p, i) => {
26423
- p.x = H_MARGIN + i * spacing;
26424
- });
26425
- }
26426
- for (const side of ["above", "below"]) {
26427
- const arr = placed.filter((p) => p.side === side).sort((a, b) => a.x - b.x);
26428
- const laneRight = [];
26429
- for (let i = 0; i < arr.length; i++) {
26430
- const p = arr[i];
26431
- const next = arr[i + 1];
26432
- const crowdedRight = !!next && next.x - p.x < CARD_W + FAN_GAP;
26433
- const preferred = crowdedRight ? p.x - CARD_W + CARD_INSET : p.x - CARD_W / 2;
26434
- const maxLeft = p.x - CARD_INSET;
26435
- const minLeft = p.x - CARD_W + CARD_INSET;
26436
- let lane = laneRight.length;
26437
- let left = Math.max(preferred, minLeft);
26438
- for (let l = 0; l < laneRight.length; l++) {
26439
- const want = Math.max(preferred, laneRight[l] + FAN_GAP, minLeft);
26440
- if (want <= maxLeft) {
26441
- lane = l;
26442
- left = want;
26443
- break;
26609
+ place(1);
26610
+ layout = derive();
26611
+ const panelAspect = width / heightHint;
26612
+ const aspectOf = (l) => l.contentW / l.contentH;
26613
+ if (scaled && layout.contentH > heightHint && aspectOf(layout) < panelAspect) {
26614
+ place(STRETCH_CAP);
26615
+ const capped = derive();
26616
+ if (aspectOf(capped) <= panelAspect) {
26617
+ layout = capped;
26618
+ } else {
26619
+ let loF = 1;
26620
+ let hiF = STRETCH_CAP;
26621
+ for (let it = 0; it < 8; it++) {
26622
+ const mid = (loF + hiF) / 2;
26623
+ place(mid);
26624
+ if (aspectOf(derive()) >= panelAspect) hiF = mid;
26625
+ else loF = mid;
26444
26626
  }
26627
+ place(hiF);
26628
+ layout = derive();
26445
26629
  }
26446
- p.lane = lane;
26447
- p.left = Math.max(6, left);
26448
- laneRight[lane] = p.left + CARD_W;
26449
26630
  }
26450
26631
  }
26451
- const contentW = Math.max(
26452
- width,
26453
- Math.max(...placed.map((p) => p.x)) + H_MARGIN,
26454
- Math.max(...placed.map((p) => p.left + CARD_W)) + 6
26455
- );
26456
- const rowGap = (side) => Math.max(0, ...placed.filter((p) => p.side === side).map((p) => p.cardH)) + LANE_GAP;
26457
- const rowGapA = rowGap("above");
26458
- const rowGapB = rowGap("below");
26459
- const ext = (side) => Math.max(
26460
- 0,
26461
- ...placed.filter((p) => p.side === side).map(
26462
- (p) => (side === "above" ? LEADER_ABOVE : LEADER_BELOW) + p.lane * (side === "above" ? rowGapA : rowGapB) + p.cardH
26463
- )
26464
- );
26465
- const dateAbove = placed.some((p) => p.side === "below" && p.date);
26466
- const dateBelow = placed.some((p) => p.side === "above" && p.date);
26467
- const contentAbove = Math.max(ext("above"), dateAbove ? DATE_OFFSET + 10 : 0);
26468
- const contentBelow = Math.max(ext("below"), dateBelow ? DATE_OFFSET + 10 : 0);
26469
- const aboveExt = contentAbove + (hasExpandedEra && eraSide === "above" ? ERA_BLOCK : 0);
26470
- const belowExt = contentBelow + (hasExpandedEra && eraSide === "below" ? ERA_BLOCK : 0);
26471
- const TOP_PAD = 14;
26472
- const BOT_PAD = 14;
26473
- const spineY = topUsed + TOP_PAD + aboveExt;
26474
- const eraBaseY = eraSide === "above" ? spineY - (contentAbove + 14) : spineY + (contentBelow + 14);
26475
- const totalH = Math.max(heightHint, spineY + belowExt + BOT_PAD);
26632
+ const { contentW, totalH, spineY, eraBaseY, laneNear } = layout;
26476
26633
  const svg = d3Selection6.select(container).append("svg").attr("width", contentW).attr("height", totalH).attr("viewBox", `0 0 ${contentW} ${totalH}`).attr("preserveAspectRatio", "xMidYMin meet").attr("xmlns", "http://www.w3.org/2000/svg").style("font-family", FONT_FAMILY);
26477
26634
  svg.append("rect").attr("width", contentW).attr("height", totalH).attr("fill", palette.bg);
26478
26635
  if (showTitle) {
@@ -26500,12 +26657,11 @@ function renderEventLine(container, parsed, palette, isDark, onClickItem, export
26500
26657
  activeGroup
26501
26658
  });
26502
26659
  }
26503
- const xs = placed.map((p) => p.x);
26504
- const x0 = Math.min(...xs);
26505
- const x1 = Math.max(...xs);
26660
+ const x0 = Math.min(...placed.map((p) => p.x - p.spanHalf));
26661
+ const x1 = Math.max(...placed.map((p) => p.x + p.spanHalf));
26506
26662
  svg.append("line").attr("x1", x0 - 20).attr("y1", spineY).attr("x2", x1 + 20).attr("y2", spineY).attr("stroke", palette.text).attr("stroke-width", 2.5).attr("stroke-linecap", "round");
26507
26663
  const geo = placed.map((p) => {
26508
- const near = p.side === "above" ? spineY - LEADER_ABOVE - p.lane * rowGapA : spineY + LEADER_BELOW + p.lane * rowGapB;
26664
+ const near = p.side === "above" ? spineY - laneNear(p) : spineY + laneNear(p);
26509
26665
  const top = p.side === "above" ? near - p.cardH : near;
26510
26666
  return { p, near, top };
26511
26667
  });
@@ -26617,7 +26773,7 @@ function renderEventLine(container, parsed, palette, isDark, onClickItem, export
26617
26773
  for (const p of placed) {
26618
26774
  if (p.kind === "era") {
26619
26775
  const col = p.color;
26620
- const half = Math.min(46, 16 + (p.members.length - 1) * 9);
26776
+ const half = Math.max(16, p.spanHalf);
26621
26777
  const spineLeft = x0 - 20;
26622
26778
  const spineRight = x1 + 20;
26623
26779
  const bx0 = Math.max(spineLeft, p.x - half);
@@ -26628,6 +26784,11 @@ function renderEventLine(container, parsed, palette, isDark, onClickItem, export
26628
26784
  "d",
26629
26785
  `M${bx0},${spineY} L${bx0},${barY} L${bx1},${barY} L${bx1},${spineY}`
26630
26786
  ).attr("fill", "none").attr("stroke", col).attr("stroke-width", 1.5).attr("stroke-linecap", "round").attr("stroke-linejoin", "round");
26787
+ const breakCx = (bx0 + bx1) / 2;
26788
+ eg.append("line").attr("x1", breakCx - BREAK_GAP / 2).attr("y1", spineY).attr("x2", breakCx + BREAK_GAP / 2).attr("y2", spineY).attr("stroke", palette.bg).attr("stroke-width", 4).attr("stroke-linecap", "butt");
26789
+ for (const d of axisBreakPaths(breakCx, spineY)) {
26790
+ eg.append("path").attr("d", d).attr("fill", "none").attr("stroke", col).attr("stroke-width", 1.25).attr("stroke-linecap", "round").attr("stroke-linejoin", "round").attr("stroke-opacity", 0.85);
26791
+ }
26631
26792
  if (onClickItem) {
26632
26793
  const ln = p.lineNumber;
26633
26794
  eg.style("cursor", "pointer").on("click", () => onClickItem(ln));
@@ -26661,13 +26822,23 @@ function renderEventLine(container, parsed, palette, isDark, onClickItem, export
26661
26822
  }
26662
26823
  const clampX = (v) => Math.max(4, Math.min(contentW - 4, v));
26663
26824
  const cap = eraSide === "above" ? 1 : -1;
26664
- for (const r of runs) {
26665
- if (r.collapsed) continue;
26825
+ const drawn = runs.filter((r) => !r.collapsed).map((r) => ({
26826
+ run: r,
26827
+ x0: clampX(r.firstX - ERA_BRACKET_PAD),
26828
+ x1: clampX(r.lastX + ERA_BRACKET_PAD)
26829
+ })).sort((a, b) => a.run.firstX - b.run.firstX);
26830
+ for (let i = 1; i < drawn.length; i++) {
26831
+ const prev = drawn[i - 1];
26832
+ const cur = drawn[i];
26833
+ if (prev.x1 <= cur.x0) continue;
26834
+ const mid = (prev.run.lastX + cur.run.firstX) / 2;
26835
+ prev.x1 = Math.max(prev.run.lastX, Math.min(prev.x1, mid - ERA_SEAM_GAP));
26836
+ cur.x0 = Math.min(cur.run.firstX, Math.max(cur.x0, mid + ERA_SEAM_GAP));
26837
+ }
26838
+ for (const { run: r, x0: x02, x1: x12 } of drawn) {
26666
26839
  const neutral = !r.era.color;
26667
26840
  const col = neutral ? palette.text : resolveColor(r.era.color, palette) ?? palette.text;
26668
26841
  const op = neutral ? 0.5 : 0.85;
26669
- const x02 = clampX(r.firstX - 14);
26670
- const x12 = clampX(r.lastX + 14);
26671
26842
  const y = eraBaseY;
26672
26843
  const eg = svg.append("g").attr("data-era", r.era.name).attr("data-era-collapsed", String(r.collapsed)).attr("data-line-number", r.era.lineNumber);
26673
26844
  eg.append("path").attr(
@@ -26693,6 +26864,22 @@ function renderEventLineForExport(container, parsed, palette, isDark, exportDims
26693
26864
  tagOverride
26694
26865
  );
26695
26866
  }
26867
+ function axisBreakPaths(cx, cy) {
26868
+ const HUMPS = 2;
26869
+ const STEPS = 14;
26870
+ const wave = (x0) => {
26871
+ let d = "";
26872
+ for (let i = 0; i <= STEPS; i++) {
26873
+ const t = i / STEPS;
26874
+ const y = cy - BREAK_HALF_H + t * 2 * BREAK_HALF_H;
26875
+ const x = x0 + BREAK_AMP * Math.sin(t * Math.PI * HUMPS);
26876
+ d += `${i === 0 ? "M" : "L"}${x.toFixed(2)},${y.toFixed(2)}`;
26877
+ if (i < STEPS) d += " ";
26878
+ }
26879
+ return d;
26880
+ };
26881
+ return [wave(cx - BREAK_GAP / 2), wave(cx + BREAK_GAP / 2)];
26882
+ }
26696
26883
  function wrapDescription(lines, charsPerLine) {
26697
26884
  const out = [];
26698
26885
  for (const line11 of lines) {
@@ -26722,7 +26909,7 @@ function renderBody(cardG, lines, bodyColor, palette, startBaseline = CARD_BODY_
26722
26909
  y += DESC_LINE_H;
26723
26910
  }
26724
26911
  }
26725
- var d3Selection6, CARD_W, H_MARGIN, TITLE_AREA, LEGEND_BAND, LEADER_ABOVE, LEADER_BELOW, DESC_FONT, DESC_LINE_H, CARD_PAD, CARD_BODY_TOP, DOT_R, MIN_SPACING, LANE_GAP, NEUTRAL_TAG, CARD_INSET, FAN_GAP, DATE_OFFSET, ERA_BLOCK, ERA_BRACKET_CAP, ERA_LEG, ERA_LABEL_FONT, ERA_MEMBER_MAX;
26912
+ var d3Selection6, CARD_W, H_MARGIN, TITLE_AREA, LEGEND_BAND, LEADER_ABOVE, LEADER_BELOW, DESC_FONT, DESC_LINE_H, CARD_PAD, CARD_BODY_TOP, DOT_R, MIN_SPACING, LANE_GAP, NEUTRAL_TAG, CARD_INSET, FAN_GAP, DATE_OFFSET, ERA_BLOCK, ERA_BRACKET_CAP, ERA_BRACKET_PAD, ERA_SEAM_GAP, BREAK_HALF_H, BREAK_AMP, BREAK_GAP, ERA_LEG, ERA_LABEL_FONT;
26726
26913
  var init_renderer = __esm({
26727
26914
  "src/event-line/renderer.ts"() {
26728
26915
  "use strict";
@@ -26757,9 +26944,13 @@ var init_renderer = __esm({
26757
26944
  DATE_OFFSET = 28;
26758
26945
  ERA_BLOCK = 30;
26759
26946
  ERA_BRACKET_CAP = 8;
26947
+ ERA_BRACKET_PAD = 14;
26948
+ ERA_SEAM_GAP = 3;
26949
+ BREAK_HALF_H = 6;
26950
+ BREAK_AMP = 2.2;
26951
+ BREAK_GAP = 5;
26760
26952
  ERA_LEG = 13;
26761
26953
  ERA_LABEL_FONT = 11.5;
26762
- ERA_MEMBER_MAX = 6;
26763
26954
  }
26764
26955
  });
26765
26956
 
@@ -52917,6 +53108,7 @@ function renderJourneyMap(container, parsed, palette, isDark, options) {
52917
53108
  y,
52918
53109
  score,
52919
53110
  palette,
53111
+ isDark,
52920
53112
  SCORE_LABEL_R
52921
53113
  );
52922
53114
  if (!exportDims) {
@@ -52948,7 +53140,14 @@ function renderJourneyMap(container, parsed, palette, isDark, options) {
52948
53140
  const allSteps = parsed.phases.length > 0 ? parsed.phases.flatMap((p) => p.steps) : parsed.steps;
52949
53141
  for (const pt of layout.curvePoints) {
52950
53142
  const step = allSteps[pt.stepIndex];
52951
- const faceG = renderScoreFace(curveG, pt.x, pt.y, pt.score, palette);
53143
+ const faceG = renderScoreFace(
53144
+ curveG,
53145
+ pt.x,
53146
+ pt.y,
53147
+ pt.score,
53148
+ palette,
53149
+ isDark
53150
+ );
52952
53151
  addEmotionLabel(faceG, pt, palette);
52953
53152
  if (step) {
52954
53153
  faceG.attr("data-line-number", step.lineNumber);
@@ -52974,7 +53173,14 @@ function renderJourneyMap(container, parsed, palette, isDark, options) {
52974
53173
  const pt = layout.curvePoints[0];
52975
53174
  const allSteps = parsed.phases.length > 0 ? parsed.phases.flatMap((p) => p.steps) : parsed.steps;
52976
53175
  const step = allSteps[pt.stepIndex];
52977
- const faceG = renderScoreFace(curveG, pt.x, pt.y, pt.score, palette);
53176
+ const faceG = renderScoreFace(
53177
+ curveG,
53178
+ pt.x,
53179
+ pt.y,
53180
+ pt.score,
53181
+ palette,
53182
+ isDark
53183
+ );
52978
53184
  addEmotionLabel(faceG, pt, palette);
52979
53185
  if (step) {
52980
53186
  faceG.attr("data-line-number", step.lineNumber);
@@ -53071,6 +53277,7 @@ function renderJourneyMap(container, parsed, palette, isDark, options) {
53071
53277
  faceCy,
53072
53278
  step.score,
53073
53279
  palette,
53280
+ isDark,
53074
53281
  COLLAPSED_FACE_R
53075
53282
  );
53076
53283
  faceG.attr("data-line-number", step.lineNumber);
@@ -53174,7 +53381,7 @@ function renderJourneyMap(container, parsed, palette, isDark, options) {
53174
53381
  const fcy = parseFloat(el.attr("data-cy") ?? "0");
53175
53382
  el.attr(
53176
53383
  "transform",
53177
- `translate(${fcx},${fcy}) scale(1.5) translate(${-fcx},${-fcy})`
53384
+ `translate(${fcx},${fcy}) scale(${FACE_HOVER_SCALE}) translate(${-fcx},${-fcy})`
53178
53385
  );
53179
53386
  } else {
53180
53387
  el.attr("transform", null);
@@ -53220,12 +53427,12 @@ function renderJourneyMap(container, parsed, palette, isDark, options) {
53220
53427
  PADDING2,
53221
53428
  Math.min(fcx - bw / 2, layout.totalWidth - PADDING2 - bw)
53222
53429
  );
53223
- const by = Math.max(PADDING2, fcy - FACE_RADIUS - THOUGHT_GAP - bh);
53430
+ const by = Math.max(PADDING2, fcy - FACE_HOVER_R - THOUGHT_GAP - bh);
53224
53431
  const scoreColor = scoreToColor(score, palette);
53225
53432
  const tintedBg = mix(scoreColor, palette.surface, 20);
53226
53433
  const g = overlayG.append("g").attr("class", "journey-thought-hover");
53227
53434
  g.append("rect").attr("x", bx).attr("y", by).attr("width", bw).attr("height", bh).attr("rx", CARD_RADIUS).attr("fill", tintedBg).attr("stroke", scoreColor).attr("stroke-width", CARD_STROKE_WIDTH2);
53228
- g.append("line").attr("x1", fcx).attr("y1", by + bh).attr("x2", fcx).attr("y2", fcy - FACE_RADIUS - 1).attr("stroke", scoreColor).attr("stroke-width", CARD_STROKE_WIDTH2);
53435
+ g.append("line").attr("x1", fcx).attr("y1", by + bh).attr("x2", fcx).attr("y2", fcy - FACE_HOVER_R - 1).attr("stroke", scoreColor).attr("stroke-width", CARD_STROKE_WIDTH2);
53229
53436
  const centerX = bx + bw / 2;
53230
53437
  for (let i = 0; i < lines.length; i++) {
53231
53438
  g.append("text").attr("x", centerX).attr("y", by + THOUGHT_PAD_Y + (i + 1) * THOUGHT_LINE_H - 2).attr("text-anchor", "middle").attr("font-size", THOUGHT_FONT).attr("font-style", "italic").attr("fill", palette.textMuted).text(lines[i]);
@@ -53468,24 +53675,23 @@ function renderPersonaSilhouette(parent, cx, cy, color, palette, scale = 1) {
53468
53675
  `M ${cx} ${cy - 12 * s} C ${cx + 10 * s} ${cy - 12 * s}, ${cx + 9 * s} ${cy + 2 * s}, ${cx + 6 * s} ${cy + 6 * s} Q ${cx} ${cy + 9 * s}, ${cx - 6 * s} ${cy + 6 * s} C ${cx - 9 * s} ${cy + 2 * s}, ${cx - 10 * s} ${cy - 12 * s}, ${cx} ${cy - 12 * s} Z`
53469
53676
  ).attr("fill", fill2).attr("stroke", stroke2).attr("stroke-width", 1.2);
53470
53677
  }
53471
- function renderScoreFace(parent, cx, cy, score, palette, radius) {
53678
+ function renderScoreFace(parent, cx, cy, score, palette, isDark, radius) {
53472
53679
  const r = radius ?? FACE_RADIUS;
53473
53680
  const color = scoreToColor(score, palette);
53474
53681
  const g = parent.append("g").attr("class", "journey-face").attr("data-cx", cx).attr("data-cy", cy);
53475
- g.append("circle").attr("cx", cx).attr("cy", cy).attr("r", r).attr("fill", color).attr("stroke", palette.bg).attr("stroke-width", 1.5);
53476
- const eyeColor = contrastText(
53477
- color,
53478
- palette.textOnFillLight,
53479
- palette.textOnFillDark
53480
- );
53682
+ const faceFill = shapeFill(palette, color, isDark);
53683
+ g.append("circle").attr("cx", cx).attr("cy", cy).attr("r", r + 1).attr("fill", palette.bg);
53684
+ g.append("circle").attr("cx", cx).attr("cy", cy).attr("r", r).attr("fill", faceFill).attr("stroke", color).attr("stroke-width", 2);
53685
+ const eyeColor = color;
53481
53686
  const eyeY = cy - r * 0.15;
53482
53687
  const eyeSpacing = r * 0.32;
53483
53688
  const eyeR = r * 0.12;
53484
53689
  g.append("circle").attr("cx", cx - eyeSpacing).attr("cy", eyeY).attr("r", eyeR).attr("fill", eyeColor);
53485
53690
  g.append("circle").attr("cx", cx + eyeSpacing).attr("cy", eyeY).attr("r", eyeR).attr("fill", eyeColor);
53486
- const mouthY = cy + r * 0.25;
53487
- const mouthW = r * 0.45;
53488
- const curve = (score - 3) / 2 * r * 0.35;
53691
+ const mouthW = r * 0.46;
53692
+ const curve = (score - 3) / 2 * r * 0.42;
53693
+ const apexY = cy + r * 0.32;
53694
+ const mouthY = apexY - curve / 2;
53489
53695
  g.append("path").attr(
53490
53696
  "d",
53491
53697
  `M ${cx - mouthW} ${mouthY} Q ${cx} ${mouthY + curve} ${cx + mouthW} ${mouthY}`
@@ -53556,7 +53762,7 @@ function renderJourneyMapForExport(content, theme, palette) {
53556
53762
  }
53557
53763
  return svgEl.outerHTML;
53558
53764
  }
53559
- var d3, d3Shape10, DIAGRAM_PADDING13, PADDING2, CARD_PADDING_X3, CARD_PADDING_Y3, CARD_HEADER_HEIGHT3, CARD_STROKE_WIDTH2, CARD_META_LINE_HEIGHT3, CARD_GAP_INTERNAL, COLUMN_RADIUS2, COLUMN_HEADER_HEIGHT2, COLUMN_PADDING3, FONT_SIZE_TITLE, FONT_SIZE_PHASE, FONT_SIZE_STEP, FONT_SIZE_META, GRID_LINE_OPACITY, CURVE_STROKE_WIDTH, FACE_RADIUS, DIM_HOVER, TITLE_LINE_HEIGHT, EMOTION_LABEL_MAX_WIDTH, EMOTION_LABEL_FONT_SIZE, ICON_THUMBS_DOWN, ICON_THUMBS_UP, ICON_THOUGHT;
53765
+ var d3, d3Shape10, DIAGRAM_PADDING13, PADDING2, CARD_PADDING_X3, CARD_PADDING_Y3, CARD_HEADER_HEIGHT3, CARD_STROKE_WIDTH2, CARD_META_LINE_HEIGHT3, CARD_GAP_INTERNAL, COLUMN_RADIUS2, COLUMN_HEADER_HEIGHT2, COLUMN_PADDING3, FONT_SIZE_TITLE, FONT_SIZE_PHASE, FONT_SIZE_STEP, FONT_SIZE_META, GRID_LINE_OPACITY, CURVE_STROKE_WIDTH, FACE_RADIUS, FACE_HOVER_SCALE, FACE_HOVER_R, DIM_HOVER, TITLE_LINE_HEIGHT, EMOTION_LABEL_MAX_WIDTH, EMOTION_LABEL_FONT_SIZE, ICON_THUMBS_DOWN, ICON_THUMBS_UP, ICON_THOUGHT;
53560
53766
  var init_renderer17 = __esm({
53561
53767
  "src/journey-map/renderer.ts"() {
53562
53768
  "use strict";
@@ -53592,6 +53798,8 @@ var init_renderer17 = __esm({
53592
53798
  GRID_LINE_OPACITY = 0.15;
53593
53799
  CURVE_STROKE_WIDTH = 2.5;
53594
53800
  FACE_RADIUS = 14;
53801
+ FACE_HOVER_SCALE = 1.5;
53802
+ FACE_HOVER_R = (FACE_RADIUS + 1) * FACE_HOVER_SCALE;
53595
53803
  DIM_HOVER = 0.25;
53596
53804
  TITLE_LINE_HEIGHT = 16;
53597
53805
  EMOTION_LABEL_MAX_WIDTH = 180;
@@ -69023,7 +69231,7 @@ pre.dgmo, code.language-dgmo, pre > code.language-dgmo,
69023
69231
 
69024
69232
  // src/auto/index.ts
69025
69233
  init_safe_href();
69026
- var VERSION = "0.39.0";
69234
+ var VERSION = "0.40.0";
69027
69235
  var DEFAULTS = {
69028
69236
  theme: "auto",
69029
69237
  palette: "slate",