@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.
- package/dist/BarChart/BarChart.svelte +29 -5
- package/dist/BarChart/properties.d.ts +8 -0
- package/dist/DeltaIndicator/DeltaIndicator.svelte +8 -0
- package/dist/DualAxisBarChart/DualAxisBarChart.svelte +10 -2
- package/dist/DualAxisBarChart/properties.d.ts +7 -0
- package/dist/FunnelChart/FunnelChart.svelte +10 -2
- package/dist/FunnelChart/properties.d.ts +7 -0
- package/dist/Icon/Icon.svelte +8 -2
- package/dist/LineChart/LineChart.svelte +2 -1
- package/dist/Menu/Menu.svelte +6 -2
- package/dist/Modal/Modal.svelte +24 -6
- package/dist/PieChart/PieChart.svelte +5 -0
- package/dist/PieChart/properties.d.ts +7 -0
- package/dist/SankeyChart/SankeyChart.svelte +2 -2
- package/dist/StatCard/StatCard.svelte +45 -5
- package/dist/Table/Table.svelte +9 -0
- package/dist/Toast/Toast.svelte +2 -2
- package/dist/_chart/ChartTooltip.svelte +38 -1
- package/dist/_chart/types.d.ts +8 -0
- package/dist/_chart/types.js +8 -0
- package/package.json +1 -1
|
@@ -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
|
-
|
|
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
|
|
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
|
-
|
|
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,
|
|
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
|
|
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
|
|
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. */
|
package/dist/Icon/Icon.svelte
CHANGED
|
@@ -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
|
-
|
|
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-
|
|
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 =
|
|
49
|
+
maxHeight = DEFAULT_CHART_MAX_HEIGHT,
|
|
49
50
|
tooltipSnippet,
|
|
50
51
|
empty,
|
|
51
52
|
highlightedIndex = null,
|
package/dist/Menu/Menu.svelte
CHANGED
|
@@ -249,7 +249,10 @@
|
|
|
249
249
|
>
|
|
250
250
|
{#if typeof item.icon === 'string'}
|
|
251
251
|
<span class="menu-item-icon">
|
|
252
|
-
|
|
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
|
}
|
package/dist/Modal/Modal.svelte
CHANGED
|
@@ -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
|
-
|
|
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
|
-
<
|
|
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
|
-
|
|
413
|
-
|
|
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 =
|
|
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
|
-
<
|
|
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
|
-
/*
|
|
266
|
-
|
|
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:
|
|
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
|
-
|
|
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);
|
package/dist/Table/Table.svelte
CHANGED
|
@@ -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'
|
package/dist/Toast/Toast.svelte
CHANGED
|
@@ -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
|
|
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}
|
package/dist/_chart/types.d.ts
CHANGED
|
@@ -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;
|
package/dist/_chart/types.js
CHANGED
|
@@ -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;
|