@juspay/svelte-ui-components 2.103.0 → 2.104.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.
|
@@ -36,7 +36,8 @@
|
|
|
36
36
|
nodeColorResolver,
|
|
37
37
|
minLinkWidth = 1,
|
|
38
38
|
dataLabelOffsetX = 0,
|
|
39
|
-
disableDimOnHover = false
|
|
39
|
+
disableDimOnHover = false,
|
|
40
|
+
firstColumnLabelSide = 'left'
|
|
40
41
|
}: SankeyChartProperties = $props();
|
|
41
42
|
|
|
42
43
|
// ── State ──────────────────────────────────────────────────────
|
|
@@ -54,20 +55,44 @@
|
|
|
54
55
|
let format = $derived(valueFormat ?? formatNumber);
|
|
55
56
|
let isEmpty = $derived(nodes.length === 0);
|
|
56
57
|
const MARGIN = 40;
|
|
57
|
-
// A 12px label's rendered line box measures ~16px (≈1.33em) across common
|
|
58
|
-
// font stacks; two label centres closer than this overlap visibly.
|
|
59
|
-
const LABEL_LINE_PX = 16;
|
|
60
58
|
|
|
61
59
|
// Real text measurement via the shared canvas-backed helper (exact on the
|
|
62
60
|
// client, 0.6em/char heuristic under SSR/tests). Character estimates used
|
|
63
61
|
// to both over-reserve the right label gutter (dead canvas) and under-budget
|
|
64
62
|
// uppercase-heavy labels (text sliding under the next column's bars).
|
|
63
|
+
// Weight and family are part of the spec: a 700-weight label is measurably
|
|
64
|
+
// wider than a 400 one, and the app's rendered font rarely matches the
|
|
65
|
+
// measurement default — budgets must be computed at the rendered style or
|
|
66
|
+
// borderline labels truncate (or overflow) for no visible reason.
|
|
67
|
+
// Family only enters the spec once the document's fonts have loaded: measuring
|
|
68
|
+
// a not-yet-loaded webfont silently measures its fallback (usually wider) and
|
|
69
|
+
// the width cache would pin that stale value under the loaded font's key.
|
|
70
|
+
// Until then the measurement default applies — same behaviour as before.
|
|
71
|
+
// One-shot promise subscription at init (browser only) — nothing to tear
|
|
72
|
+
// down, and the $state write re-derives every measurement consumer.
|
|
73
|
+
let fontsLoaded = $state(typeof document !== 'undefined' && document.fonts?.status === 'loaded');
|
|
74
|
+
if (typeof document !== 'undefined' && document.fonts?.status !== 'loaded') {
|
|
75
|
+
document.fonts?.ready.then(() => {
|
|
76
|
+
fontsLoaded = true;
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
let chartFontFamily = $derived(
|
|
80
|
+
fontsLoaded && containerEl ? getComputedStyle(containerEl).fontFamily : null
|
|
81
|
+
);
|
|
65
82
|
let labelFont = $derived({
|
|
66
|
-
size: containerEl ? readCssVarPx(containerEl, '--sankey-label-font-size', 12) : 12
|
|
83
|
+
size: containerEl ? readCssVarPx(containerEl, '--sankey-label-font-size', 12) : 12,
|
|
84
|
+
weight: containerEl ? readCssVarPx(containerEl, '--sankey-label-font-weight', 400) : 400,
|
|
85
|
+
family: chartFontFamily
|
|
67
86
|
});
|
|
68
87
|
let colLabelFont = $derived({
|
|
69
|
-
size: containerEl ? readCssVarPx(containerEl, '--sankey-col-label-font-size', 11) : 11
|
|
88
|
+
size: containerEl ? readCssVarPx(containerEl, '--sankey-col-label-font-size', 11) : 11,
|
|
89
|
+
weight: containerEl ? readCssVarPx(containerEl, '--sankey-col-label-font-weight', 400) : 400,
|
|
90
|
+
family: chartFontFamily
|
|
70
91
|
});
|
|
92
|
+
// A label's rendered line box measures ≈1.33em across common font stacks;
|
|
93
|
+
// two label centres closer than this overlap visibly. Derived from the
|
|
94
|
+
// tokened size so consumers that scale labels keep honest de-collision.
|
|
95
|
+
let labelLinePx = $derived(Math.ceil(labelFont.size * 1.33));
|
|
71
96
|
|
|
72
97
|
// Final-column labels render to the RIGHT of their node; the bare 40px margin is
|
|
73
98
|
// nowhere near enough for real funnel labels ("PARTIALLY_FAILED (1,234)"), so they
|
|
@@ -101,8 +126,11 @@
|
|
|
101
126
|
// the room falls below an ellipsis, vanish entirely. Mirror the sink gutter:
|
|
102
127
|
// reserve a capped left gutter sized from the source-node labels (sources are what
|
|
103
128
|
// land in the first column) and shift the diagram right by it.
|
|
129
|
+
// With `firstColumnLabelSide: 'right'` the labels render over the outgoing
|
|
130
|
+
// ribbons like every other column, so no gutter is reserved at all and the
|
|
131
|
+
// diagram gains that width.
|
|
104
132
|
let firstColumnLabelGutter = $derived.by(() => {
|
|
105
|
-
if (!showLabels || nodes.length === 0 || chartWidth <= 0) {
|
|
133
|
+
if (firstColumnLabelSide === 'right' || !showLabels || nodes.length === 0 || chartWidth <= 0) {
|
|
106
134
|
return 0;
|
|
107
135
|
}
|
|
108
136
|
const targetIds = new Set(links.map((link) => link.target));
|
|
@@ -184,7 +212,7 @@
|
|
|
184
212
|
// SVG's left edge is that gutter plus the base margin, minus the inset —
|
|
185
213
|
// symmetric with the last column's sink-gutter budget below.
|
|
186
214
|
const available =
|
|
187
|
-
column === 0
|
|
215
|
+
column === 0 && firstColumnLabelSide === 'left'
|
|
188
216
|
? Math.max(0, firstColumnLabelGutter + MARGIN - 6 - dataLabelOffsetX)
|
|
189
217
|
: column === columnCount - 1
|
|
190
218
|
? Math.max(0, lastColumnLabelGutter + MARGIN - 6 - dataLabelOffsetX)
|
|
@@ -222,7 +250,7 @@
|
|
|
222
250
|
continue;
|
|
223
251
|
}
|
|
224
252
|
const centerGap = node.y + node.height / 2 - (lastKept.y + lastKept.height / 2);
|
|
225
|
-
if (centerGap <
|
|
253
|
+
if (centerGap < labelLinePx) {
|
|
226
254
|
if (node.value > lastKept.value) {
|
|
227
255
|
hidden.add(lastKept.id);
|
|
228
256
|
lastKept = node;
|
|
@@ -490,11 +518,11 @@
|
|
|
490
518
|
<text
|
|
491
519
|
class="sankey-label"
|
|
492
520
|
class:node-dimmed={dimmed}
|
|
493
|
-
x={node.column === 0
|
|
521
|
+
x={node.column === 0 && firstColumnLabelSide === 'left'
|
|
494
522
|
? node.x - 6 - dataLabelOffsetX
|
|
495
523
|
: node.x + node.width + 6 + dataLabelOffsetX}
|
|
496
524
|
y={node.y + node.height / 2}
|
|
497
|
-
text-anchor={node.column === 0 ? 'end' : 'start'}
|
|
525
|
+
text-anchor={node.column === 0 && firstColumnLabelSide === 'left' ? 'end' : 'start'}
|
|
498
526
|
dominant-baseline="middle"
|
|
499
527
|
>{truncateLabel(
|
|
500
528
|
showValues ? `${node.label} (${format(node.value)})` : node.label,
|
|
@@ -537,13 +565,22 @@
|
|
|
537
565
|
.sankey-label {
|
|
538
566
|
fill: var(--sankey-label-color, #333);
|
|
539
567
|
font-size: var(--sankey-label-font-size, 12px);
|
|
568
|
+
font-weight: var(--sankey-label-font-weight, 400);
|
|
540
569
|
font-family: var(--chart-font-family, inherit);
|
|
570
|
+
/* Highcharts-style text outline: node labels render over link ribbons, so
|
|
571
|
+
a halo in the chart's background colour keeps them legible at any flow
|
|
572
|
+
density. Off (transparent / 0) by default. */
|
|
573
|
+
paint-order: stroke;
|
|
574
|
+
stroke: var(--sankey-label-halo-color, transparent);
|
|
575
|
+
stroke-width: var(--sankey-label-halo-width, 0);
|
|
576
|
+
stroke-linejoin: round;
|
|
541
577
|
pointer-events: none;
|
|
542
578
|
transition: opacity var(--chart-transition-duration, 0.2s) ease;
|
|
543
579
|
}
|
|
544
580
|
.sankey-col-label {
|
|
545
581
|
fill: var(--sankey-col-label-color, #666);
|
|
546
582
|
font-size: var(--sankey-col-label-font-size, 11px);
|
|
583
|
+
font-weight: var(--sankey-col-label-font-weight, 400);
|
|
547
584
|
font-family: var(--chart-font-family, inherit);
|
|
548
585
|
pointer-events: none;
|
|
549
586
|
}
|
|
@@ -84,6 +84,14 @@ export type OptionalSankeyChartProperties = {
|
|
|
84
84
|
* to read the overall structure. Defaults to `false` (standard dim-on-hover behaviour).
|
|
85
85
|
*/
|
|
86
86
|
disableDimOnHover?: boolean;
|
|
87
|
+
/**
|
|
88
|
+
* Which side of a first-column node its label renders on. `'left'` (default) anchors the
|
|
89
|
+
* label into a reserved left gutter outside the diagram. `'right'` renders it like every
|
|
90
|
+
* other column — to the right of the bar, over the outgoing ribbons (pair with the
|
|
91
|
+
* `--sankey-label-halo-*` tokens for legibility); no left gutter is reserved, so the
|
|
92
|
+
* diagram gains that width.
|
|
93
|
+
*/
|
|
94
|
+
firstColumnLabelSide?: 'left' | 'right';
|
|
87
95
|
};
|
|
88
96
|
export type SankeyChartEventProperties = {
|
|
89
97
|
onnodeclick?: (event: {
|
package/dist/_chart/measure.d.ts
CHANGED