@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,4 @@
1
+ import type { StatCardProperties } from './properties';
2
+ declare const StatCard: import("svelte").Component<StatCardProperties, {}, "">;
3
+ type StatCard = ReturnType<typeof StatCard>;
4
+ export default StatCard;
@@ -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';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@juspay/svelte-ui-components",
3
- "version": "2.72.0",
3
+ "version": "2.73.0",
4
4
  "description": "A themeable Svelte 5 UI component library with CSS custom property driven styling",
5
5
  "keywords": [
6
6
  "svelte",