@ogabrielluiz/patchflow 0.1.3 → 0.1.5

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/index.js CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  SIGNAL_OPERATORS,
3
3
  __commonJS,
4
4
  __toESM
5
- } from "./chunk-4VUBNFI4.js";
5
+ } from "./chunk-YONEHQMI.js";
6
6
 
7
7
  // node_modules/@dagrejs/graphlib/lib/graph.js
8
8
  var require_graph = __commonJS({
@@ -4042,7 +4042,7 @@ function selfLoopArcPath(source, target, blockBottom, arcOffset) {
4042
4042
  var MIN_WIDTH = 140;
4043
4043
  var MIN_HEIGHT = 90;
4044
4044
  function getBlockDimensions(block, portCount) {
4045
- const labelWidth = block.label.length * 8;
4045
+ const labelWidth = block.label.length * 11;
4046
4046
  const subLabelWidth = block.subLabel ? block.subLabel.length * 7 : 0;
4047
4047
  const paramWidths = block.params.map((p) => `${p.key}: ${p.value}`.length * 7);
4048
4048
  const longestParam = paramWidths.length > 0 ? Math.max(...paramWidths) : 0;
@@ -4284,19 +4284,46 @@ function layout(graph, options = {}) {
4284
4284
  const feedbackSpace = hasFeedback ? diagramBottom - maxY + feedbackArcOffset + 30 + 16 : 0;
4285
4285
  const width = maxX + margin;
4286
4286
  const height = maxY + margin + feedbackSpace;
4287
+ const warnings = checkHeightInvariant({
4288
+ blocks: layoutBlocks,
4289
+ height,
4290
+ hasFeedback,
4291
+ feedbackBottom: diagramBottom + feedbackArcOffset
4292
+ });
4287
4293
  return {
4288
4294
  blocks: layoutBlocks,
4289
4295
  connections: layoutConnections,
4290
4296
  width,
4291
4297
  height,
4292
- signalTypeStats: graph.signalTypeStats
4298
+ signalTypeStats: graph.signalTypeStats,
4299
+ warnings
4293
4300
  };
4294
4301
  }
4302
+ function checkHeightInvariant(args) {
4303
+ const { blocks, height, hasFeedback, feedbackBottom } = args;
4304
+ const warnings = [];
4305
+ const blockBottomMax = blocks.length > 0 ? Math.max(...blocks.map((b) => b.y + b.height)) : 0;
4306
+ const contentBottom = hasFeedback ? Math.max(blockBottomMax, feedbackBottom) : blockBottomMax;
4307
+ if (height < contentBottom) {
4308
+ warnings.push(
4309
+ `layout: computed height (${height.toFixed(1)}) is below content bottom (${contentBottom.toFixed(1)}); legend/notes may overlap block content`
4310
+ );
4311
+ }
4312
+ return warnings;
4313
+ }
4295
4314
 
4296
4315
  // src/renderer.ts
4297
4316
  function genId() {
4298
4317
  return "pf-" + Math.random().toString(16).slice(2, 8);
4299
4318
  }
4319
+ function fitLabel(label, maxWidth, charWidth) {
4320
+ if (maxWidth <= 0 || charWidth <= 0) return label;
4321
+ const maxChars = Math.floor(maxWidth / charWidth);
4322
+ if (maxChars <= 0) return label;
4323
+ if (label.length <= maxChars) return label;
4324
+ if (maxChars === 1) return "\u2026";
4325
+ return label.slice(0, maxChars - 1) + "\u2026";
4326
+ }
4300
4327
  function buildDesc(layoutResult) {
4301
4328
  const blockCount = layoutResult.blocks.length;
4302
4329
  const connCount = layoutResult.connections.length;
@@ -4342,11 +4369,11 @@ function buildPanels(theme, idPrefix, blocks) {
4342
4369
  const parts = [];
4343
4370
  for (const block of blocks) {
4344
4371
  const moduleName = sanitizeForSvg(block.parentModule || block.label);
4345
- const label = sanitizeForSvg(block.label);
4346
4372
  const fontFamily = sanitizeForSvg(theme.label.fontFamily);
4347
4373
  const insetX = block.x + 12;
4348
4374
  const insetY = block.y + 8;
4349
4375
  const insetW = block.width - 24;
4376
+ const label = sanitizeForSvg(fitLabel(block.label, insetW, 11));
4350
4377
  let group = `<g data-module="${moduleName}" filter="url(#${idPrefix}-panel-shadow)">`;
4351
4378
  group += `<rect x="${block.x}" y="${block.y}" width="${block.width}" height="${block.height}" fill="${theme.panel.fill}" stroke="${theme.panel.stroke}" stroke-width="0.75" rx="${theme.panel.cornerRadius}"/>`;
4352
4379
  group += `<line x1="${block.x}" y1="${block.y + 0.5}" x2="${block.x + block.width}" y2="${block.y + 0.5}" stroke="${theme.panel.highlight}" stroke-width="${theme.panel.bevelWidth}"/>`;
@@ -4354,7 +4381,7 @@ function buildPanels(theme, idPrefix, blocks) {
4354
4381
  group += `<rect x="${insetX}" y="${insetY}" width="${insetW}" height="28" fill="${theme.label.plateFill}" stroke="${theme.label.plateStroke}" stroke-width="0.5"/>`;
4355
4382
  group += `<text x="${block.x + block.width / 2}" y="${block.y + 22}" text-anchor="middle" font-family="${fontFamily}" font-size="14" font-weight="700" fill="${theme.label.color}" letter-spacing="3">${label}</text>`;
4356
4383
  if (block.subLabel) {
4357
- const subLabel = sanitizeForSvg(block.subLabel);
4384
+ const subLabel = sanitizeForSvg(fitLabel(block.subLabel, insetW - 8, 7));
4358
4385
  const barX = insetX;
4359
4386
  const barY = insetY + 28;
4360
4387
  const barW = insetW;
@@ -4380,7 +4407,8 @@ function buildParams(blocks, theme) {
4380
4407
  `<rect x="${px}" y="${py}" width="${pw}" height="20" fill="${theme.param.plateFill}" stroke="${theme.param.plateStroke}" stroke-width="0.5"/>`
4381
4408
  );
4382
4409
  const keyNorm = param.key.trim().toLowerCase();
4383
- const text = keyNorm === blockLabelNorm ? sanitizeForSvg(param.value) : `${sanitizeForSvg(param.key)}: ${sanitizeForSvg(param.value)}`;
4410
+ const rawText = keyNorm === blockLabelNorm ? param.value : `${param.key}: ${param.value}`;
4411
+ const text = sanitizeForSvg(fitLabel(rawText, pw - 8, 7));
4384
4412
  parts.push(
4385
4413
  `<text x="${px + pw / 2}" y="${py + 14}" text-anchor="middle" font-family="${monoFont}" font-size="10" fill="${theme.param.textColor}">${text}</text>`
4386
4414
  );
@@ -4531,7 +4559,7 @@ function buildAnnotations(theme, connections, layoutHeight) {
4531
4559
  });
4532
4560
  return parts.join("");
4533
4561
  }
4534
- function buildLegend(theme, layoutResult) {
4562
+ function buildLegend(theme, layoutResult, diagramBottom) {
4535
4563
  const order = ["audio", "cv", "pitch", "gate", "trigger", "clock"];
4536
4564
  const used = order.filter((t) => (layoutResult.signalTypeStats[t] ?? 0) > 0);
4537
4565
  if (used.length === 0) return "";
@@ -4540,7 +4568,7 @@ function buildLegend(theme, layoutResult) {
4540
4568
  const itemWidth = 70;
4541
4569
  const totalWidth = used.length * itemWidth;
4542
4570
  const legendStartX = layoutResult.width - totalWidth;
4543
- const y = layoutResult.height - 20;
4571
+ const y = diagramBottom - 20;
4544
4572
  for (let i = 0; i < used.length; i++) {
4545
4573
  const sig = used[i];
4546
4574
  const color = theme.cable.colors[sig].stroke;
@@ -4572,6 +4600,14 @@ function renderSvg(layoutResult, theme) {
4572
4600
  `<pattern id="${idPrefix}-dots" width="${spacing}" height="${spacing}" patternUnits="userSpaceOnUse"><circle cx="${spacing / 2}" cy="${spacing / 2}" r="${theme.grid.dotRadius}" fill="${theme.grid.dotColor}" opacity="${theme.grid.opacity}"/></pattern>`
4573
4601
  );
4574
4602
  }
4603
+ const labelPadX = 130;
4604
+ const vbWidth = width + labelPadX * 2;
4605
+ const topPad = 40;
4606
+ const noteCount = layoutResult.connections.filter((c) => c.annotation).length;
4607
+ const notesHeight = noteCount > 0 ? noteCount * 16 + 10 : 0;
4608
+ const bottomPad = Math.max(40, notesHeight + 10);
4609
+ const vbHeight = height + topPad + bottomPad;
4610
+ const diagramBottom = height + bottomPad;
4575
4611
  const layers = [
4576
4612
  `<g class="pf-layer-bg">${buildBackground(theme, idPrefix, width, height)}</g>`,
4577
4613
  `<g class="pf-layer-cables">${buildCables(theme, layoutResult.connections)}</g>`,
@@ -4579,17 +4615,10 @@ function renderSvg(layoutResult, theme) {
4579
4615
  `<g class="pf-layer-params">${buildParams(layoutResult.blocks, theme)}</g>`,
4580
4616
  `<g class="pf-layer-jacks">${buildJacks(theme, idPrefix, layoutResult.blocks)}</g>`,
4581
4617
  `<g class="pf-layer-labels">${buildLabels(theme, layoutResult.blocks, layoutResult.connections)}</g>`,
4582
- `<g class="pf-layer-annotations">${buildAnnotations(theme, layoutResult.connections, height)}</g>`,
4583
- `<g class="pf-layer-legend">${buildLegend(theme, layoutResult)}</g>`
4618
+ `<g class="pf-layer-annotations">${buildAnnotations(theme, layoutResult.connections, diagramBottom)}</g>`,
4619
+ `<g class="pf-layer-legend">${buildLegend(theme, layoutResult, diagramBottom)}</g>`
4584
4620
  ].join("");
4585
4621
  const style = `<style>@media print { .pf-panel, .pf-jack { filter: none; } }</style>`;
4586
- const labelPadX = 130;
4587
- const vbWidth = width + labelPadX * 2;
4588
- const topPad = 40;
4589
- const noteCount = layoutResult.connections.filter((c) => c.annotation).length;
4590
- const notesHeight = noteCount > 0 ? noteCount * 16 + 10 : 0;
4591
- const bottomPad = Math.max(40, notesHeight + 10);
4592
- const vbHeight = height + topPad + bottomPad;
4593
4622
  const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="${-labelPadX} ${-topPad} ${vbWidth} ${vbHeight}" width="100%" data-pf-min-width="${minWidth + labelPadX * 2}" role="img" aria-labelledby="${idPrefix}-title ${idPrefix}-desc"><title id="${idPrefix}-title">Patch diagram</title><desc id="${idPrefix}-desc">${desc}</desc>` + style + `<defs>${defsParts.join("")}</defs>` + layers + `</svg>`;
4594
4623
  return svg;
4595
4624
  }