@juspay/svelte-ui-components 2.107.0 → 2.107.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.
@@ -145,30 +145,49 @@ export function computeSankeyLayout(nodes, links, width, height, nodeWidth = 16,
145
145
  }
146
146
  const colWidth = maxCol === 0 ? 0 : (width - nodeWidth) / maxCol;
147
147
  const columnPadding = new Map();
148
- // Initialize y positions
148
+ // Global px-per-value scale (d3-sankey's `ky`): the tightest column — least
149
+ // height left after node gaps — sets one scale for the whole diagram, so a
150
+ // given value renders the same height in every column. The previous layout
151
+ // stretched every column to fill the full plot height, which gave each
152
+ // column its own scale; link widths (sized at the source column's scale)
153
+ // then overflowed target nodes laid out at a smaller scale, and the ribbon
154
+ // stacks spilled below the bottom node row.
155
+ let pxPerValue = Number.POSITIVE_INFINITY;
156
+ for (const ids of columnGroups.values()) {
157
+ const totalValue = ids.reduce((s, id) => s + (nodeValues.get(id) ?? 0), 0);
158
+ const availableHeight = height - (ids.length - 1) * nodePadding;
159
+ if (totalValue > 0 && availableHeight > 0) {
160
+ pxPerValue = Math.min(pxPerValue, availableHeight / totalValue);
161
+ }
162
+ }
163
+ if (!Number.isFinite(pxPerValue)) {
164
+ // All-zero data: nothing carries volume, every bar collapses to the minimum.
165
+ pxPerValue = 0;
166
+ }
167
+ const linkRenderWidth = (value) => Math.max(minLinkWidth, value * pxPerValue);
168
+ // Initialize y positions. A node must be at least as tall as its thicker
169
+ // side's rendered link stack: every ribbon is clamped to minLinkWidth, so a
170
+ // node fanning into many near-zero links would otherwise be shorter than the
171
+ // inflated stack attached to it.
149
172
  const nodeY = new Map();
150
173
  const nodeH = new Map();
151
174
  for (const [col, ids] of columnGroups) {
152
- const totalValue = ids.reduce((s, id) => s + (nodeValues.get(id) ?? 0), 0);
153
175
  const gapCount = ids.length - 1;
154
- const availableHeight = height - gapCount * nodePadding;
155
176
  const renderedHeights = ids.map((id) => {
156
- const val = nodeValues.get(id) ?? 0;
157
- const h = totalValue > 0 ? (val / totalValue) * availableHeight : availableHeight / ids.length;
158
- return Math.max(minLinkWidth, h);
177
+ const outStack = (outgoing.get(id) ?? []).reduce((s, link) => s + linkRenderWidth(link.value), 0);
178
+ const inStack = (incoming.get(id) ?? []).reduce((s, link) => s + linkRenderWidth(link.value), 0);
179
+ return Math.max(minLinkWidth, (nodeValues.get(id) ?? 0) * pxPerValue, outStack, inStack);
159
180
  });
160
181
  const sumRendered = renderedHeights.reduce((s, h) => s + h, 0);
161
182
  const paddingBudget = gapCount > 0 ? (height - sumRendered) / gapCount : 0;
162
183
  const effectivePadding = Math.max(0, Math.min(nodePadding, paddingBudget));
163
- const scale = sumRendered > height && sumRendered > 0 ? height / sumRendered : 1;
164
184
  columnPadding.set(col, effectivePadding);
165
185
  let y = 0;
166
186
  for (let index = 0; index < ids.length; index++) {
167
187
  const id = ids[index];
168
- const renderedH = renderedHeights[index] * scale;
169
188
  nodeY.set(id, y);
170
- nodeH.set(id, renderedH);
171
- y += renderedH + effectivePadding;
189
+ nodeH.set(id, renderedHeights[index]);
190
+ y += renderedHeights[index] + effectivePadding;
172
191
  }
173
192
  }
174
193
  // Iterative relaxation (upstream pass)
@@ -245,11 +264,11 @@ export function computeSankeyLayout(nodes, links, width, height, nodeWidth = 16,
245
264
  }));
246
265
  const nodeById = new Map(computedNodes.map((n) => [n.id, n]));
247
266
  const linkKey = (l) => `${l.source}${l.target}`;
267
+ // Link widths use the same global scale as node heights, so each node's link
268
+ // stack fills its bar exactly and never runs past its bottom edge.
248
269
  const linkWidths = new Map();
249
270
  for (const l of links) {
250
- const sVal = nodeValues.get(l.source) ?? 1;
251
- const sourceH = nodeH.get(l.source) ?? 0;
252
- linkWidths.set(linkKey(l), Math.max(minLinkWidth, (l.value / Math.max(sVal, 1)) * sourceH));
271
+ linkWidths.set(linkKey(l), linkRenderWidth(l.value));
253
272
  }
254
273
  const linkSy = new Map();
255
274
  const linkTy = new Map();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@juspay/svelte-ui-components",
3
- "version": "2.107.0",
3
+ "version": "2.107.1",
4
4
  "description": "A themeable Svelte 5 UI component library with CSS custom property driven styling",
5
5
  "keywords": [
6
6
  "svelte",