@juspay/svelte-ui-components 2.72.0 → 2.73.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.
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { StatCardProperties } from './properties';
|
|
3
|
+
|
|
4
|
+
let {
|
|
5
|
+
title,
|
|
6
|
+
value,
|
|
7
|
+
delta,
|
|
8
|
+
deltaPositive,
|
|
9
|
+
subtitle,
|
|
10
|
+
footer,
|
|
11
|
+
valueSnippet,
|
|
12
|
+
testId,
|
|
13
|
+
classes,
|
|
14
|
+
onclick
|
|
15
|
+
}: StatCardProperties = $props();
|
|
16
|
+
|
|
17
|
+
const isInteractive = $derived(typeof onclick === 'function');
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* When `deltaPositive` is explicitly provided use it; otherwise infer from
|
|
21
|
+
* the leading character of `delta` — '+' → positive, '-' → negative,
|
|
22
|
+
* anything else (e.g. '0%') → undefined (neutral, no colour applied).
|
|
23
|
+
*/
|
|
24
|
+
const resolvedDeltaPositive = $derived(
|
|
25
|
+
typeof deltaPositive === 'boolean'
|
|
26
|
+
? deltaPositive
|
|
27
|
+
: typeof delta === 'string' && delta.trim().length > 0
|
|
28
|
+
? delta.trimStart().startsWith('+')
|
|
29
|
+
? true
|
|
30
|
+
: delta.trimStart().startsWith('-')
|
|
31
|
+
? false
|
|
32
|
+
: null
|
|
33
|
+
: null
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
const hasDelta = $derived(typeof delta === 'string' && delta.trim().length > 0);
|
|
37
|
+
|
|
38
|
+
const handleKeydown = (event: KeyboardEvent): void => {
|
|
39
|
+
if (event.key === 'Enter' || event.key === ' ') {
|
|
40
|
+
if (event.key === ' ') {
|
|
41
|
+
event.preventDefault();
|
|
42
|
+
}
|
|
43
|
+
if (event.currentTarget instanceof HTMLElement) {
|
|
44
|
+
event.currentTarget.click();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
</script>
|
|
49
|
+
|
|
50
|
+
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
|
|
51
|
+
<div
|
|
52
|
+
class="statcard {classes ?? ''}"
|
|
53
|
+
class:statcard-interactive={isInteractive}
|
|
54
|
+
data-pw={typeof testId === 'string' ? testId : null}
|
|
55
|
+
role={isInteractive ? 'button' : null}
|
|
56
|
+
tabindex={isInteractive ? 0 : null}
|
|
57
|
+
onclick={isInteractive ? onclick : null}
|
|
58
|
+
onkeydown={isInteractive ? handleKeydown : null}
|
|
59
|
+
>
|
|
60
|
+
{#if typeof title === 'string' && title.length > 0}
|
|
61
|
+
<div class="statcard-title">{title}</div>
|
|
62
|
+
{/if}
|
|
63
|
+
|
|
64
|
+
<div class="statcard-value-row">
|
|
65
|
+
{#if typeof valueSnippet === 'function'}
|
|
66
|
+
<div class="statcard-value">{@render valueSnippet()}</div>
|
|
67
|
+
{:else if typeof value === 'string' && value.length > 0}
|
|
68
|
+
<div class="statcard-value">{value}</div>
|
|
69
|
+
{/if}
|
|
70
|
+
|
|
71
|
+
{#if hasDelta}
|
|
72
|
+
<div
|
|
73
|
+
class="statcard-delta"
|
|
74
|
+
class:statcard-delta-positive={resolvedDeltaPositive === true}
|
|
75
|
+
class:statcard-delta-negative={resolvedDeltaPositive === false}
|
|
76
|
+
>
|
|
77
|
+
{delta}
|
|
78
|
+
</div>
|
|
79
|
+
{/if}
|
|
80
|
+
</div>
|
|
81
|
+
|
|
82
|
+
{#if typeof subtitle === 'string' && subtitle.length > 0}
|
|
83
|
+
<div class="statcard-subtitle">{subtitle}</div>
|
|
84
|
+
{/if}
|
|
85
|
+
|
|
86
|
+
{#if typeof footer === 'function'}
|
|
87
|
+
<div class="statcard-footer">{@render footer()}</div>
|
|
88
|
+
{/if}
|
|
89
|
+
</div>
|
|
90
|
+
|
|
91
|
+
<style>
|
|
92
|
+
.statcard {
|
|
93
|
+
display: flex;
|
|
94
|
+
flex-direction: column;
|
|
95
|
+
gap: var(--statcard-gap, 4px);
|
|
96
|
+
padding: var(--statcard-padding, 16px);
|
|
97
|
+
background: var(--statcard-background, #ffffff);
|
|
98
|
+
border: var(--statcard-border, 1px solid #e5e7eb);
|
|
99
|
+
border-radius: var(--statcard-border-radius, 8px);
|
|
100
|
+
box-shadow: var(--statcard-box-shadow, none);
|
|
101
|
+
width: var(--statcard-width, auto);
|
|
102
|
+
min-width: var(--statcard-min-width, 0);
|
|
103
|
+
max-width: var(--statcard-max-width, none);
|
|
104
|
+
height: var(--statcard-height, auto);
|
|
105
|
+
color: var(--statcard-color, inherit);
|
|
106
|
+
cursor: var(--statcard-cursor, default);
|
|
107
|
+
box-sizing: border-box;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.statcard-interactive {
|
|
111
|
+
cursor: var(--statcard-cursor, pointer);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.statcard-interactive:focus-visible {
|
|
115
|
+
outline: var(--statcard-focus-outline, 2px solid currentColor);
|
|
116
|
+
outline-offset: var(--statcard-focus-outline-offset, 2px);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.statcard-title {
|
|
120
|
+
font-size: var(--statcard-title-font-size, 12px);
|
|
121
|
+
font-weight: var(--statcard-title-font-weight, 500);
|
|
122
|
+
color: var(--statcard-title-color, #6b7280);
|
|
123
|
+
line-height: var(--statcard-title-line-height, 1.4);
|
|
124
|
+
white-space: var(--statcard-title-white-space, nowrap);
|
|
125
|
+
overflow: hidden;
|
|
126
|
+
text-overflow: ellipsis;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.statcard-value-row {
|
|
130
|
+
display: flex;
|
|
131
|
+
align-items: var(--statcard-value-row-align, baseline);
|
|
132
|
+
gap: var(--statcard-value-row-gap, 8px);
|
|
133
|
+
flex-wrap: wrap;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.statcard-value {
|
|
137
|
+
font-size: var(--statcard-value-font-size, 24px);
|
|
138
|
+
font-weight: var(--statcard-value-font-weight, 600);
|
|
139
|
+
color: var(--statcard-value-color, inherit);
|
|
140
|
+
line-height: var(--statcard-value-line-height, 1.2);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.statcard-delta {
|
|
144
|
+
font-size: var(--statcard-delta-font-size, 13px);
|
|
145
|
+
font-weight: var(--statcard-delta-font-weight, 500);
|
|
146
|
+
color: var(--statcard-delta-color, #6b7280);
|
|
147
|
+
line-height: var(--statcard-delta-line-height, 1.4);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.statcard-delta-positive {
|
|
151
|
+
color: var(--statcard-delta-positive-color, #16a34a);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.statcard-delta-negative {
|
|
155
|
+
color: var(--statcard-delta-negative-color, #dc2626);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.statcard-subtitle {
|
|
159
|
+
font-size: var(--statcard-subtitle-font-size, 12px);
|
|
160
|
+
font-weight: var(--statcard-subtitle-font-weight, 400);
|
|
161
|
+
color: var(--statcard-subtitle-color, #9ca3af);
|
|
162
|
+
line-height: var(--statcard-subtitle-line-height, 1.4);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.statcard-footer {
|
|
166
|
+
margin-top: var(--statcard-footer-margin-top, 8px);
|
|
167
|
+
padding-top: var(--statcard-footer-padding-top, 8px);
|
|
168
|
+
border-top: var(--statcard-footer-border-top, 1px solid #e5e7eb);
|
|
169
|
+
}
|
|
170
|
+
</style>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
export type StatCardProperties = OptionalStatCardProperties & StatCardEventProperties;
|
|
3
|
+
export type MandatoryStatCardProperties = Record<string, never>;
|
|
4
|
+
export type OptionalStatCardProperties = {
|
|
5
|
+
/** Card heading label. */
|
|
6
|
+
title?: string;
|
|
7
|
+
/** Pre-formatted metric value string (e.g. "₹1.23Cr", "98.4%"). */
|
|
8
|
+
value?: string;
|
|
9
|
+
/** Pre-formatted delta string (e.g. "+12.5%", "-3.2%"). Auto-infers `deltaPositive` from leading sign when `deltaPositive` is not provided. */
|
|
10
|
+
delta?: string;
|
|
11
|
+
/** Overrides automatic sign-based inference for delta colour. `true` = positive (green), `false` = negative (red). */
|
|
12
|
+
deltaPositive?: boolean;
|
|
13
|
+
/** Secondary label rendered below the value row. */
|
|
14
|
+
subtitle?: string;
|
|
15
|
+
/** Snippet rendered in the card footer area. */
|
|
16
|
+
footer?: Snippet;
|
|
17
|
+
/** Replaces the string `value` with a custom snippet for advanced value rendering. */
|
|
18
|
+
valueSnippet?: Snippet;
|
|
19
|
+
/** Renders as `data-pw` on the root element for Playwright test selection. */
|
|
20
|
+
testId?: string;
|
|
21
|
+
/** Extra CSS class names appended to the root element. */
|
|
22
|
+
classes?: string;
|
|
23
|
+
};
|
|
24
|
+
export type StatCardEventProperties = {
|
|
25
|
+
/** Makes the card interactive: adds `role="button"`, `tabindex=0`, and wires click/Enter/Space. */
|
|
26
|
+
onclick?: (event: MouseEvent) => void;
|
|
27
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/index.d.ts
CHANGED
|
@@ -66,6 +66,7 @@ export { default as BarChart } from './BarChart/BarChart.svelte';
|
|
|
66
66
|
export { default as PieChart } from './PieChart/PieChart.svelte';
|
|
67
67
|
export { default as SankeyChart } from './SankeyChart/SankeyChart.svelte';
|
|
68
68
|
export { default as LottiePlayer } from './LottiePlayer/LottiePlayer.svelte';
|
|
69
|
+
export { default as StatCard } from './StatCard/StatCard.svelte';
|
|
69
70
|
export type * from './Button/properties';
|
|
70
71
|
export type * from './Modal/properties';
|
|
71
72
|
export type * from './Input/properties';
|
|
@@ -128,5 +129,6 @@ export type * from './BarChart/properties';
|
|
|
128
129
|
export type * from './PieChart/properties';
|
|
129
130
|
export type * from './SankeyChart/properties';
|
|
130
131
|
export type * from './LottiePlayer/properties';
|
|
132
|
+
export type * from './StatCard/properties';
|
|
131
133
|
export { validateInput } from './utils';
|
|
132
134
|
export { formatNumberIndian } from './_chart/format';
|
package/dist/index.js
CHANGED
|
@@ -66,5 +66,6 @@ export { default as BarChart } from './BarChart/BarChart.svelte';
|
|
|
66
66
|
export { default as PieChart } from './PieChart/PieChart.svelte';
|
|
67
67
|
export { default as SankeyChart } from './SankeyChart/SankeyChart.svelte';
|
|
68
68
|
export { default as LottiePlayer } from './LottiePlayer/LottiePlayer.svelte';
|
|
69
|
+
export { default as StatCard } from './StatCard/StatCard.svelte';
|
|
69
70
|
export { validateInput } from './utils';
|
|
70
71
|
export { formatNumberIndian } from './_chart/format';
|