@juspay/svelte-ui-components 2.80.4 → 2.80.6

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.
@@ -18,7 +18,7 @@
18
18
  import { formatNumber } from '../_chart/format';
19
19
  import { roundedRectPath } from '../_chart/paths';
20
20
  import type { LegendItem, BarRect } from '../_chart/types';
21
- import { DEFAULT_CHART_CORNER_RADIUS } from '../_chart/types';
21
+ import { DEFAULT_CHART_CORNER_RADIUS, DEFAULT_CHART_MAX_HEIGHT } from '../_chart/types';
22
22
  import { SvelteMap } from 'svelte/reactivity';
23
23
 
24
24
  // ── Per-instance uid prefix for <defs> ids (A1-3) ─────────────
@@ -55,6 +55,8 @@
55
55
  barPadding = 0.2,
56
56
  barRadius = DEFAULT_CHART_CORNER_RADIUS,
57
57
  aspectRatio = 16 / 9,
58
+ maxHeight = DEFAULT_CHART_MAX_HEIGHT,
59
+ minHeight = 0,
58
60
  xAxisLabel,
59
61
  yAxisLabel,
60
62
  yDomain,
@@ -108,7 +110,17 @@
108
110
 
109
111
  let format = $derived(valueFormat ?? formatNumber);
110
112
  let isVertical = $derived(orientation === 'vertical');
111
- let dims = $derived(computeChartDimensions(chartWidth, chartHeight));
113
+ // When an axis is hidden its gutter (Y = 50px for tick labels, X = 40px) is dead
114
+ // space that squeezes the plot into the centre. Collapse the tick-label gutter but
115
+ // keep a symmetric breathing-room inset so the edge bars (and their value labels)
116
+ // don't sit flush against the container edges.
117
+ let dims = $derived(
118
+ computeChartDimensions(chartWidth, chartHeight, {
119
+ left: showYAxis ? 50 : 28,
120
+ right: 28,
121
+ bottom: showXAxis ? 40 : 8
122
+ })
123
+ );
112
124
 
113
125
  let isMulti = $derived(Array.isArray(series) && series.length > 0);
114
126
 
@@ -606,7 +618,13 @@
606
618
  : ''}
607
619
  >
608
620
  <div style={scrollable ? `min-width: ${minScrollWidth}px;` : ''}>
609
- <ChartContainer bind:width={chartWidth} bind:height={chartHeight} {aspectRatio}>
621
+ <ChartContainer
622
+ bind:width={chartWidth}
623
+ bind:height={chartHeight}
624
+ {aspectRatio}
625
+ {maxHeight}
626
+ {minHeight}
627
+ >
610
628
  <!-- A1-2 / A1-3: SVG <defs> for pattern and gradient fills -->
611
629
  {#if defsEntries.length > 0}
612
630
  <defs>
@@ -755,7 +773,12 @@
755
773
  onclick={() => handleClick(bar)}
756
774
  />
757
775
  {/if}
758
- {#if showValues && !isStackedMode}
776
+ <!-- Suppress the horizontal value label when its sub-band is thinner
777
+ than the ~11px label, so cramped multi-series charts hide labels
778
+ instead of overlapping them into an unreadable cluster. Consumers
779
+ restore labels by giving the chart more height (aspectRatio /
780
+ scrollable / minBandWidth). -->
781
+ {#if showValues && !isStackedMode && (isVertical || bar.height >= 13)}
759
782
  <text
760
783
  class="bar-value"
761
784
  x={isVertical ? bar.x + bar.width / 2 : bar.x + bar.width + 4}
@@ -812,7 +835,8 @@
812
835
  }
813
836
  .bar-value {
814
837
  fill: var(--barchart-value-color, #333);
815
- font-size: var(--barchart-value-font-size, 11px);
838
+ font-size: var(--barchart-value-font-size, 14px);
839
+ font-weight: var(--barchart-value-font-weight, 600);
816
840
  font-family: var(--chart-font-family, inherit);
817
841
  pointer-events: none;
818
842
  }
@@ -84,6 +84,14 @@ export type OptionalBarChartProperties = {
84
84
  */
85
85
  barRadius?: number;
86
86
  aspectRatio?: number;
87
+ /**
88
+ * Upper bound (px) on the rendered chart height. The chart height is derived from
89
+ * its width via `aspectRatio`; on wide or scrollable surfaces that can balloon the
90
+ * chart. Cap it here to keep the chart compact (defaults to `Infinity` = uncapped).
91
+ */
92
+ maxHeight?: number;
93
+ /** Lower bound (px) on the rendered chart height (defaults to `0`). */
94
+ minHeight?: number;
87
95
  xAxisLabel?: string;
88
96
  yAxisLabel?: string;
89
97
  yDomain?: [number, number];
@@ -68,6 +68,14 @@
68
68
  color: var(--delta-indicator-neutral-color, #8a8a8a);
69
69
  }
70
70
 
71
+ /* The tone color is set on the wrapper; the text span must inherit it explicitly.
72
+ A consumer's global `span { color }` rule (higher weight than inheritance) would
73
+ otherwise repaint just the number a neutral text color — leaving only the arrow
74
+ tinted and making up/down deltas read as colorless. */
75
+ .delta-indicator-text {
76
+ color: inherit;
77
+ }
78
+
71
79
  .delta-indicator-arrow {
72
80
  display: inline-flex;
73
81
  width: var(--delta-indicator-arrow-size, 9px);
@@ -14,7 +14,7 @@
14
14
  import { formatNumber } from '../_chart/format';
15
15
  import { roundedRectPath, linePath } from '../_chart/paths';
16
16
  import type { LegendItem, TooltipData, LinearScale, BandScale, Point } from '../_chart/types';
17
- import { DEFAULT_CHART_CORNER_RADIUS } from '../_chart/types';
17
+ import { DEFAULT_CHART_CORNER_RADIUS, DEFAULT_CHART_MAX_HEIGHT } from '../_chart/types';
18
18
 
19
19
  // ── Per-instance uid for SVG <defs> ids ────────────────────────
20
20
  const uid = Math.random().toString(36).slice(2, 9);
@@ -31,6 +31,8 @@
31
31
  barRadius = DEFAULT_CHART_CORNER_RADIUS,
32
32
  barPadding = 0.25,
33
33
  aspectRatio = 16 / 9,
34
+ maxHeight = DEFAULT_CHART_MAX_HEIGHT,
35
+ minHeight = 0,
34
36
  minBarHeight = 2,
35
37
  margin,
36
38
  tooltipPortal = false,
@@ -341,7 +343,13 @@
341
343
  <Legend items={legendItems} position="top" />
342
344
  {/if}
343
345
 
344
- <ChartContainer bind:width={chartWidth} bind:height={chartHeight} {aspectRatio}>
346
+ <ChartContainer
347
+ bind:width={chartWidth}
348
+ bind:height={chartHeight}
349
+ {aspectRatio}
350
+ {maxHeight}
351
+ {minHeight}
352
+ >
345
353
  <g transform="translate({dims.margin.left}, {dims.margin.top})">
346
354
  <!-- Left Y-axis (index 0) -->
347
355
  <Axis
@@ -91,6 +91,13 @@ export type OptionalDualAxisBarChartProperties = {
91
91
  * Passed to `ChartContainer`'s ResizeObserver sizing. Default `16/9`.
92
92
  */
93
93
  aspectRatio?: number;
94
+ /**
95
+ * Upper bound (px) on the rendered chart height, so the aspect-ratio-derived height
96
+ * can't balloon on wide surfaces. Defaults to `Infinity` (uncapped).
97
+ */
98
+ maxHeight?: number;
99
+ /** Lower bound (px) on the rendered chart height (defaults to `0`). */
100
+ minHeight?: number;
94
101
  /**
95
102
  * Custom tooltip content. Receives a `DualAxisTooltipContext` and replaces the
96
103
  * default multi-series tooltip.
@@ -4,7 +4,7 @@
4
4
  import ChartTooltip from '../_chart/ChartTooltip.svelte';
5
5
  import { getColor } from '../_chart/colors';
6
6
  import { formatNumber, formatPercent } from '../_chart/format';
7
- import { DEFAULT_CHART_CORNER_RADIUS } from '../_chart/types';
7
+ import { DEFAULT_CHART_CORNER_RADIUS, DEFAULT_CHART_MAX_HEIGHT } from '../_chart/types';
8
8
 
9
9
  // ── Props ──────────────────────────────────────────────────────
10
10
 
@@ -17,6 +17,8 @@
17
17
  showValueLabels = true,
18
18
  valueFormat,
19
19
  aspectRatio = 16 / 9,
20
+ maxHeight = DEFAULT_CHART_MAX_HEIGHT,
21
+ minHeight = 0,
20
22
  radius = DEFAULT_CHART_CORNER_RADIUS,
21
23
  testId,
22
24
  classes,
@@ -219,7 +221,13 @@
219
221
  {#if isEmpty && typeof empty === 'function'}
220
222
  <div class="chart-empty">{@render empty()}</div>
221
223
  {:else}
222
- <ChartContainer bind:width={chartWidth} bind:height={chartHeight} {aspectRatio}>
224
+ <ChartContainer
225
+ bind:width={chartWidth}
226
+ bind:height={chartHeight}
227
+ {aspectRatio}
228
+ {maxHeight}
229
+ {minHeight}
230
+ >
223
231
  <g transform="translate({MARGIN_LEFT}, {MARGIN_TOP})">
224
232
  <!-- Stage bars and category labels -->
225
233
  {#each data as stage, index (index)}
@@ -55,6 +55,13 @@ export type OptionalFunnelChartProperties = {
55
55
  * Passed directly to `ChartContainer`. Default is `16 / 9`.
56
56
  */
57
57
  aspectRatio?: number;
58
+ /**
59
+ * Upper bound (px) on the rendered chart height, so the aspect-ratio-derived height
60
+ * can't balloon on wide surfaces. Defaults to `Infinity` (uncapped).
61
+ */
62
+ maxHeight?: number;
63
+ /** Lower bound (px) on the rendered chart height (defaults to `0`). */
64
+ minHeight?: number;
58
65
  /** Value for the `data-pw` attribute on the chart root element. */
59
66
  testId?: string;
60
67
  /** CSS class string applied to the chart root element. Useful for CSS-variable theming. */
@@ -1,4 +1,5 @@
1
1
  <script lang="ts">
2
+ import Img from '../Img/Img.svelte';
2
3
  import type { IconProperties } from './properties';
3
4
 
4
5
  let { icon, svg, text, onclick, onkeydown, classes }: IconProperties = $props();
@@ -9,7 +10,9 @@
9
10
  <!-- eslint-disable svelte/no-at-html-tags -->
10
11
  <span class="icon-svg">{@html svg}</span>
11
12
  {:else if icon}
12
- <img src={icon} alt="" />
13
+ <!-- Inline the SVG so currentColor strokes/fills inherit the surrounding text
14
+ colour; non-SVG URLs fall back to the plain <img> render automatically. -->
15
+ <Img inlineSvg src={icon} alt="" fallback="" />
13
16
  {/if}
14
17
  {#if typeof text === 'string' && text.length > 0}
15
18
  <div class="icon-text">{text}</div>
@@ -24,7 +27,10 @@
24
27
  align-items: center;
25
28
  cursor: pointer;
26
29
  }
27
- .icon-container img {
30
+ /* Direct child only: the @html branch's svg lives inside .icon-svg and keeps
31
+ its own 100% sizing rule below. */
32
+ .icon-container > :global(img),
33
+ .icon-container > :global(svg) {
28
34
  height: var(--icon-height, 20px);
29
35
  width: var(--icon-width, 20px);
30
36
  padding: var(--icon-padding, 4px);
@@ -1,5 +1,6 @@
1
1
  <script lang="ts">
2
2
  import type { LineChartProperties, LineChartTooltipContext } from './properties';
3
+ import { DEFAULT_CHART_MAX_HEIGHT } from '../_chart/types';
3
4
  import type { ChartHighlightAPI } from '../_chart/highlight';
4
5
  import { onMount } from 'svelte';
5
6
  import ChartContainer from '../_chart/ChartContainer.svelte';
@@ -45,7 +46,7 @@
45
46
  yTickFormat,
46
47
  aspectRatio = 16 / 9,
47
48
  minHeight = 0,
48
- maxHeight = Infinity,
49
+ maxHeight = DEFAULT_CHART_MAX_HEIGHT,
49
50
  tooltipSnippet,
50
51
  empty,
51
52
  highlightedIndex = null,
@@ -249,7 +249,10 @@
249
249
  >
250
250
  {#if typeof item.icon === 'string'}
251
251
  <span class="menu-item-icon">
252
- <Img src={item.icon} alt="" />
252
+ <!-- Inline the SVG so currentColor strokes/fills inherit the item's
253
+ text colour (danger items tint their icon red, dark theme works);
254
+ non-SVG URLs fall back to the plain <img> render automatically. -->
255
+ <Img inlineSvg src={item.icon} alt="" fallback="" />
253
256
  </span>
254
257
  {/if}
255
258
  <span class="menu-item-label">{item.label}</span>
@@ -347,7 +350,8 @@
347
350
  flex-shrink: 0;
348
351
  }
349
352
 
350
- .menu-item-icon :global(img) {
353
+ .menu-item-icon :global(img),
354
+ .menu-item-icon :global(svg) {
351
355
  width: 100%;
352
356
  height: 100%;
353
357
  }
@@ -5,6 +5,7 @@
5
5
  import OverlayAnimation from '../Animations/OverlayAnimation.svelte';
6
6
  import { createDebouncer } from '../utils';
7
7
  import Button from '../Button/Button.svelte';
8
+ import Img from '../Img/Img.svelte';
8
9
 
9
10
  let overlayDiv: HTMLDivElement | null = $state(null);
10
11
  let backPressed = $state(false);
@@ -162,7 +163,15 @@
162
163
  tabindex="0"
163
164
  data-pw={leftImageTestId}
164
165
  >
165
- <img class="header-left-img" src={header.leftImage} alt="" />
166
+ <!-- Inline SVGs so currentColor icons inherit the header text
167
+ colour; non-SVG URLs fall back to a plain <img>. -->
168
+ <Img
169
+ inlineSvg
170
+ src={header.leftImage}
171
+ alt=""
172
+ fallback=""
173
+ classes="header-left-img"
174
+ />
166
175
  </div>
167
176
  {/if}
168
177
  {#if typeof header.text === 'string' && header.text.length > 0}
@@ -178,7 +187,13 @@
178
187
  onkeydown={handleRightImageKeyDown}
179
188
  data-pw={header.buttonTestId}
180
189
  >
181
- <img class="header-right-img" src={header.rightImage} alt="" />
190
+ <Img
191
+ inlineSvg
192
+ src={header.rightImage}
193
+ alt=""
194
+ fallback=""
195
+ classes="header-right-img"
196
+ />
182
197
  </div>
183
198
  {/if}
184
199
  </div>
@@ -409,19 +424,22 @@
409
424
  letter-spacing: var(--modal-header-text-letter-spacing);
410
425
  }
411
426
 
412
- .header-left-img,
413
- .header-right-img {
427
+ /* The header images render through the Img component (inline svg or img), so
428
+ these classes ride on Img's element — match them via :global under the
429
+ scoped .header to keep the sizing contract. */
430
+ .header :global(.header-left-img),
431
+ .header :global(.header-right-img) {
414
432
  padding-top: var(--header-img-top-padding, 5px);
415
433
  cursor: pointer;
416
434
  }
417
435
 
418
- .header-left-img {
436
+ .header :global(.header-left-img) {
419
437
  margin: var(--header-left-image-margin, 0px 18px 0px 0px);
420
438
  width: var(--header-left-image-width, 25px);
421
439
  height: var(--header-left-image-height, 25px);
422
440
  }
423
441
 
424
- .header-right-img {
442
+ .header :global(.header-right-img) {
425
443
  width: var(--header-right-image-width, 25px);
426
444
  height: var(--header-right-image-height, 25px);
427
445
  padding: var(--header-right-image-padding);
@@ -1,5 +1,6 @@
1
1
  <script lang="ts">
2
2
  import { onMount } from 'svelte';
3
+ import { DEFAULT_CHART_MAX_HEIGHT } from '../_chart/types';
3
4
  import type { PieChartProperties } from './properties';
4
5
  import ChartContainer from '../_chart/ChartContainer.svelte';
5
6
  import ChartTooltip from '../_chart/ChartTooltip.svelte';
@@ -23,6 +24,8 @@
23
24
  showLegend = false,
24
25
  startAngle = -Math.PI / 2,
25
26
  aspectRatio,
27
+ maxHeight = DEFAULT_CHART_MAX_HEIGHT,
28
+ minHeight = 0,
26
29
  valueFormat,
27
30
  tooltipSnippet,
28
31
  center,
@@ -221,6 +224,8 @@
221
224
  bind:width={chartWidth}
222
225
  bind:height={chartHeight}
223
226
  aspectRatio={effectiveAspectRatio}
227
+ {maxHeight}
228
+ {minHeight}
224
229
  >
225
230
  <g transform="translate({cx}, {cy})">
226
231
  {#each slices as slice (slice.index)}
@@ -18,6 +18,13 @@ export type OptionalPieChartProperties = {
18
18
  showLegend?: boolean;
19
19
  startAngle?: number;
20
20
  aspectRatio?: number;
21
+ /**
22
+ * Upper bound (px) on the rendered chart height, so the aspect-ratio-derived height
23
+ * can't balloon on wide surfaces. Defaults to `Infinity` (uncapped).
24
+ */
25
+ maxHeight?: number;
26
+ /** Lower bound (px) on the rendered chart height (defaults to `0`). */
27
+ minHeight?: number;
21
28
  valueFormat?: (value: number) => string;
22
29
  tooltipSnippet?: Snippet<[PieChartSlice, number]>;
23
30
  center?: Snippet;
@@ -5,7 +5,7 @@
5
5
  import { computeSankeyLayout } from '../_chart/geometry';
6
6
  import { getColor } from '../_chart/colors';
7
7
  import { formatNumber } from '../_chart/format';
8
- import { DEFAULT_CHART_CORNER_RADIUS } from '../_chart/types';
8
+ import { DEFAULT_CHART_CORNER_RADIUS, DEFAULT_CHART_MAX_HEIGHT } from '../_chart/types';
9
9
  import { SvelteMap, SvelteSet } from 'svelte/reactivity';
10
10
 
11
11
  // ── Props ──────────────────────────────────────────────────────
@@ -20,7 +20,7 @@
20
20
  showLabels = true,
21
21
  aspectRatio = 16 / 9,
22
22
  radius = DEFAULT_CHART_CORNER_RADIUS,
23
- maxHeight = Infinity,
23
+ maxHeight = DEFAULT_CHART_MAX_HEIGHT,
24
24
  valueFormat,
25
25
  tooltipSnippet,
26
26
  empty,
@@ -100,7 +100,16 @@
100
100
  position={tooltip.position ?? 'top'}
101
101
  testId={tooltip.testId}
102
102
  >
103
- <div class="statcard-title statcard-title-tooltip">{title}</div>
103
+ <span class="statcard-title-tooltip-trigger">
104
+ <span class="statcard-title statcard-title-tooltip">{title}</span>
105
+ <span class="statcard-tooltip-icon" aria-hidden="true">
106
+ <svg viewBox="0 0 16 16" fill="none">
107
+ <circle cx="8" cy="8" r="6.5" stroke="currentColor" stroke-width="1.2" />
108
+ <rect x="7.25" y="6.9" width="1.5" height="4.1" rx="0.75" fill="currentColor" />
109
+ <circle cx="8" cy="4.8" r="0.9" fill="currentColor" />
110
+ </svg>
111
+ </span>
112
+ </span>
104
113
  </Tooltip>
105
114
  {:else}
106
115
  <div class="statcard-title">{title}</div>
@@ -262,10 +271,15 @@
262
271
  flex-shrink: 0;
263
272
  }
264
273
 
265
- /* Transparent wrapper: keeps the checkbox in the event path (to stop bubbling to
266
- the card action) without altering the header layout. */
274
+ /* Wrapper keeps the checkbox in the event path (to stop bubbling to the card
275
+ action). `margin-left: auto` pushes it to the header's right edge so the title
276
+ stays left and the checkbox reads as a right-aligned control. (A previous
277
+ `display: contents` here removed the box, which silently defeated the flex
278
+ alignment.) */
267
279
  .statcard-header-checkbox {
268
- display: contents;
280
+ display: flex;
281
+ align-items: center;
282
+ margin-left: auto;
269
283
  }
270
284
 
271
285
  .statcard-title {
@@ -278,12 +292,38 @@
278
292
  text-overflow: ellipsis;
279
293
  }
280
294
 
295
+ .statcard-title-tooltip-trigger {
296
+ display: inline-flex;
297
+ align-items: center;
298
+ gap: var(--statcard-tooltip-icon-gap, 4px);
299
+ min-width: 0;
300
+ }
301
+
281
302
  .statcard-title-tooltip {
282
303
  cursor: default;
283
- text-decoration: underline dotted;
304
+ /* Default surface (Euler) uses the ⓘ icon as the tooltip affordance, so the
305
+ title carries no underline. The Shopify theme flips both tokens — dotted
306
+ underline on, icon off — via its own stylesheet. */
307
+ text-decoration: var(--statcard-title-tooltip-decoration, none);
284
308
  text-underline-offset: 2px;
285
309
  }
286
310
 
311
+ .statcard-tooltip-icon {
312
+ display: var(--statcard-tooltip-icon-display, inline-flex);
313
+ align-items: center;
314
+ justify-content: center;
315
+ width: var(--statcard-tooltip-icon-size, 14px);
316
+ height: var(--statcard-tooltip-icon-size, 14px);
317
+ flex-shrink: 0;
318
+ color: var(--statcard-tooltip-icon-color, currentColor);
319
+ cursor: default;
320
+ }
321
+
322
+ .statcard-tooltip-icon svg {
323
+ width: 100%;
324
+ height: 100%;
325
+ }
326
+
287
327
  .statcard-value-row {
288
328
  display: flex;
289
329
  align-items: var(--statcard-value-row-align, baseline);
@@ -121,6 +121,15 @@
121
121
  if (typeof valueA === 'number' && typeof valueB === 'number') {
122
122
  return direction === 'asc' ? valueA - valueB : valueB - valueA;
123
123
  } else if (typeof valueA === 'string' && typeof valueB === 'string') {
124
+ // Separator-formatted numeric strings (e.g. "1,11,600") must sort by their
125
+ // numeric value, not lexicographically; anything unparseable falls back to
126
+ // locale comparison. Empty strings stay in the locale branch so they are not
127
+ // coerced to 0.
128
+ const numericA = valueA.trim() === '' ? NaN : Number(valueA.replace(/,/g, ''));
129
+ const numericB = valueB.trim() === '' ? NaN : Number(valueB.replace(/,/g, ''));
130
+ if (Number.isFinite(numericA) && Number.isFinite(numericB)) {
131
+ return direction === 'asc' ? numericA - numericB : numericB - numericA;
132
+ }
124
133
  return direction === 'asc' ? valueA.localeCompare(valueB) : valueB.localeCompare(valueA);
125
134
  } else if (typeof valueA === 'boolean' && typeof valueB === 'boolean') {
126
135
  return direction === 'asc'
@@ -120,7 +120,7 @@
120
120
  >
121
121
  {#if typeof leftIcon === 'string' && leftIcon.length > 0}
122
122
  <div class="toast-icon-wrapper">
123
- <Img src={leftIcon} alt="" />
123
+ <Img inlineSvg src={leftIcon} alt="" fallback="" />
124
124
  </div>
125
125
  {/if}
126
126
 
@@ -149,7 +149,7 @@
149
149
  }}
150
150
  data-pw={closeIconTestId}
151
151
  >
152
- <Img src={rightIcon} alt="Close" />
152
+ <Img inlineSvg src={rightIcon} alt="Close" fallback="" />
153
153
  </div>
154
154
  {/if}
155
155
  </div>
@@ -2,10 +2,47 @@
2
2
  import type { ChartTooltipProperties } from './types';
3
3
 
4
4
  let { data, mouseX = 0, mouseY = 0, customSnippet, classes }: ChartTooltipProperties = $props();
5
+
6
+ const OFFSET = 12;
7
+
8
+ let tooltipEl = $state<HTMLDivElement | null>(null);
9
+ let tooltipWidth = $state(0);
10
+ let tooltipHeight = $state(0);
11
+
12
+ // Clamp against the positioned chart container so the tooltip never spills past
13
+ // (and gets clipped by) an overflow:hidden edge. Re-read on each measure/move.
14
+ const containerWidth = $derived(tooltipEl?.offsetParent?.clientWidth ?? Number.POSITIVE_INFINITY);
15
+ const containerHeight = $derived(
16
+ tooltipEl?.offsetParent?.clientHeight ?? Number.POSITIVE_INFINITY
17
+ );
18
+
19
+ // Horizontal: flip to the left of the cursor when it would overflow the right edge.
20
+ const left = $derived.by(() => {
21
+ let value = mouseX + OFFSET;
22
+ if (value + tooltipWidth > containerWidth) {
23
+ value = mouseX - tooltipWidth - OFFSET;
24
+ }
25
+ return Math.max(0, value);
26
+ });
27
+
28
+ // Vertical: keep the tooltip within the container's top and bottom edges.
29
+ const top = $derived.by(() => {
30
+ let value = mouseY - OFFSET;
31
+ if (value + tooltipHeight > containerHeight) {
32
+ value = containerHeight - tooltipHeight;
33
+ }
34
+ return Math.max(0, value);
35
+ });
5
36
  </script>
6
37
 
7
38
  {#if data !== null}
8
- <div class="chart-tooltip {classes ?? ''}" style="left: {mouseX + 12}px; top: {mouseY - 12}px;">
39
+ <div
40
+ bind:this={tooltipEl}
41
+ bind:clientWidth={tooltipWidth}
42
+ bind:clientHeight={tooltipHeight}
43
+ class="chart-tooltip {classes ?? ''}"
44
+ style="left: {left}px; top: {top}px;"
45
+ >
9
46
  {#if typeof customSnippet === 'function'}
10
47
  {@render customSnippet(data)}
11
48
  {:else}
@@ -10,6 +10,14 @@ import type { BarChartDataPoint } from '../BarChart/properties';
10
10
  * *changed* `--radius` should pass the corresponding radius prop explicitly.
11
11
  */
12
12
  export declare const DEFAULT_CHART_CORNER_RADIUS = 4;
13
+ /**
14
+ * Default upper bound (px) on a chart's rendered height. Chart height is derived
15
+ * from width via `aspectRatio`, so on a wide surface (e.g. a full-width dashboard
16
+ * panel) a 16/9 chart can balloon past 700px. This default keeps charts from ever
17
+ * rendering absurdly tall; a call site that genuinely needs a taller chart passes
18
+ * an explicit `maxHeight` to override it.
19
+ */
20
+ export declare const DEFAULT_CHART_MAX_HEIGHT = 420;
13
21
  export type Margin = {
14
22
  top: number;
15
23
  right: number;
@@ -9,3 +9,11 @@
9
9
  * *changed* `--radius` should pass the corresponding radius prop explicitly.
10
10
  */
11
11
  export const DEFAULT_CHART_CORNER_RADIUS = 4;
12
+ /**
13
+ * Default upper bound (px) on a chart's rendered height. Chart height is derived
14
+ * from width via `aspectRatio`, so on a wide surface (e.g. a full-width dashboard
15
+ * panel) a 16/9 chart can balloon past 700px. This default keeps charts from ever
16
+ * rendering absurdly tall; a call site that genuinely needs a taller chart passes
17
+ * an explicit `maxHeight` to override it.
18
+ */
19
+ export const DEFAULT_CHART_MAX_HEIGHT = 420;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@juspay/svelte-ui-components",
3
- "version": "2.80.4",
3
+ "version": "2.80.6",
4
4
  "description": "A themeable Svelte 5 UI component library with CSS custom property driven styling",
5
5
  "keywords": [
6
6
  "svelte",