@juspay/svelte-ui-components 2.44.0 → 2.45.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.
- package/dist/Card/Card.svelte +96 -9
- package/dist/Card/properties.d.ts +23 -0
- package/package.json +1 -1
package/dist/Card/Card.svelte
CHANGED
|
@@ -1,11 +1,22 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { CardProperties } from './properties';
|
|
3
3
|
|
|
4
|
-
let {
|
|
4
|
+
let {
|
|
5
|
+
children,
|
|
6
|
+
title,
|
|
7
|
+
description,
|
|
8
|
+
classes,
|
|
9
|
+
testId,
|
|
10
|
+
onclick,
|
|
11
|
+
headerRight,
|
|
12
|
+
footer,
|
|
13
|
+
stretch = false,
|
|
14
|
+
scrollable = false
|
|
15
|
+
}: CardProperties = $props();
|
|
5
16
|
|
|
6
17
|
const isInteractive = $derived(typeof onclick === 'function');
|
|
7
18
|
|
|
8
|
-
|
|
19
|
+
const handleKeydown = (event: KeyboardEvent): void => {
|
|
9
20
|
if (event.key === 'Enter' || event.key === ' ') {
|
|
10
21
|
if (event.key === ' ') {
|
|
11
22
|
event.preventDefault();
|
|
@@ -14,32 +25,55 @@
|
|
|
14
25
|
event.currentTarget.click();
|
|
15
26
|
}
|
|
16
27
|
}
|
|
17
|
-
}
|
|
28
|
+
};
|
|
18
29
|
</script>
|
|
19
30
|
|
|
20
31
|
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
|
|
21
32
|
<div
|
|
22
33
|
class="card {classes ?? ''}"
|
|
23
34
|
class:card-interactive={isInteractive}
|
|
35
|
+
class:card-stretch={stretch}
|
|
36
|
+
class:card-has-scroll={scrollable}
|
|
24
37
|
data-pw={typeof testId === 'string' ? testId : null}
|
|
25
38
|
role={isInteractive ? 'button' : null}
|
|
26
39
|
tabindex={isInteractive ? 0 : null}
|
|
27
40
|
onclick={isInteractive ? onclick : null}
|
|
28
41
|
onkeydown={isInteractive ? handleKeydown : null}
|
|
29
42
|
>
|
|
30
|
-
{#if typeof title === 'string' && title.length > 0}
|
|
31
|
-
<div class="card-header">
|
|
32
|
-
<div class="card-
|
|
33
|
-
|
|
34
|
-
|
|
43
|
+
{#if (typeof title === 'string' && title.length > 0) || typeof headerRight === 'function'}
|
|
44
|
+
<div class="card-header" class:card-header-split={typeof headerRight === 'function'}>
|
|
45
|
+
<div class="card-header-main">
|
|
46
|
+
{#if typeof title === 'string' && title.length > 0}
|
|
47
|
+
<div class="card-title">{title}</div>
|
|
48
|
+
{/if}
|
|
49
|
+
{#if typeof description === 'string' && description.length > 0}
|
|
50
|
+
<div class="card-description">{description}</div>
|
|
51
|
+
{/if}
|
|
52
|
+
</div>
|
|
53
|
+
{#if typeof headerRight === 'function'}
|
|
54
|
+
<div class="card-header-right">
|
|
55
|
+
{@render headerRight()}
|
|
56
|
+
</div>
|
|
35
57
|
{/if}
|
|
36
58
|
</div>
|
|
37
59
|
{/if}
|
|
38
60
|
{#if typeof children === 'function'}
|
|
39
|
-
|
|
61
|
+
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
|
|
62
|
+
<div
|
|
63
|
+
class="card-content"
|
|
64
|
+
class:card-content-scrollable={scrollable}
|
|
65
|
+
role={scrollable ? 'region' : null}
|
|
66
|
+
aria-label={scrollable ? 'Scrollable card content' : null}
|
|
67
|
+
tabindex={scrollable ? 0 : null}
|
|
68
|
+
>
|
|
40
69
|
{@render children()}
|
|
41
70
|
</div>
|
|
42
71
|
{/if}
|
|
72
|
+
{#if typeof footer === 'function'}
|
|
73
|
+
<footer class="card-footer">
|
|
74
|
+
{@render footer()}
|
|
75
|
+
</footer>
|
|
76
|
+
{/if}
|
|
43
77
|
</div>
|
|
44
78
|
|
|
45
79
|
<style>
|
|
@@ -68,11 +102,50 @@
|
|
|
68
102
|
outline-offset: var(--card-focus-outline-offset, 2px);
|
|
69
103
|
}
|
|
70
104
|
|
|
105
|
+
/* stretch: fill parent height */
|
|
106
|
+
.card-stretch {
|
|
107
|
+
height: var(--card-stretch-height, 100%);
|
|
108
|
+
display: flex;
|
|
109
|
+
flex-direction: column;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/* when stretch is on, content area should grow to fill remaining space */
|
|
113
|
+
.card-stretch .card-content {
|
|
114
|
+
flex: var(--card-content-flex, 1);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/* when scrollable=true the child sets overflow-y:auto, so the card must not clip it */
|
|
118
|
+
.card-has-scroll {
|
|
119
|
+
overflow: visible;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/* header row layout — base block flow; flex only applied when headerRight is present */
|
|
71
123
|
.card-header {
|
|
72
124
|
padding: var(--card-header-padding, 16px 16px 0);
|
|
73
125
|
border-bottom: var(--card-header-border-bottom, none);
|
|
74
126
|
}
|
|
75
127
|
|
|
128
|
+
/* flex layout activated only when headerRight snippet is provided */
|
|
129
|
+
.card-header-split {
|
|
130
|
+
display: flex;
|
|
131
|
+
align-items: var(--card-header-align-items, flex-start);
|
|
132
|
+
justify-content: space-between;
|
|
133
|
+
gap: var(--card-header-gap, 8px);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.card-header-main {
|
|
137
|
+
display: flex;
|
|
138
|
+
flex-direction: column;
|
|
139
|
+
flex: 1;
|
|
140
|
+
min-width: 0;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.card-header-right {
|
|
144
|
+
display: flex;
|
|
145
|
+
align-items: var(--card-header-right-align-items, center);
|
|
146
|
+
flex-shrink: 0;
|
|
147
|
+
}
|
|
148
|
+
|
|
76
149
|
.card-title {
|
|
77
150
|
font-size: var(--card-title-font-size, 16px);
|
|
78
151
|
font-weight: var(--card-title-font-weight, 600);
|
|
@@ -89,4 +162,18 @@
|
|
|
89
162
|
.card-content {
|
|
90
163
|
padding: var(--card-content-padding, 16px);
|
|
91
164
|
}
|
|
165
|
+
|
|
166
|
+
/* scrollable content area */
|
|
167
|
+
.card-content-scrollable {
|
|
168
|
+
overflow-y: auto;
|
|
169
|
+
max-height: var(--card-content-max-height, 400px);
|
|
170
|
+
scrollbar-width: thin;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/* footer */
|
|
174
|
+
.card-footer {
|
|
175
|
+
padding: var(--card-footer-padding, 12px 16px);
|
|
176
|
+
border-top: var(--card-footer-border-top, none);
|
|
177
|
+
background: var(--card-footer-background, inherit);
|
|
178
|
+
}
|
|
92
179
|
</style>
|
|
@@ -18,4 +18,27 @@ export type OptionalCardProperties = {
|
|
|
18
18
|
* so existing consumers see zero behaviour change.
|
|
19
19
|
*/
|
|
20
20
|
onclick?: (event: MouseEvent) => void;
|
|
21
|
+
/**
|
|
22
|
+
* Snippet rendered at the top-right of the header row, alongside title/description.
|
|
23
|
+
* When omitted the header row is unchanged (title block takes full width).
|
|
24
|
+
*/
|
|
25
|
+
headerRight?: Snippet;
|
|
26
|
+
/**
|
|
27
|
+
* Snippet rendered in a `<footer class="card-footer">` element below the content area.
|
|
28
|
+
* When omitted no footer element is rendered.
|
|
29
|
+
*/
|
|
30
|
+
footer?: Snippet;
|
|
31
|
+
/**
|
|
32
|
+
* When true, the root `.card` element gets `height: 100%` and becomes a flex column
|
|
33
|
+
* so the content area grows to fill the remaining space. Defaults to false.
|
|
34
|
+
*/
|
|
35
|
+
stretch?: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* When true, the `.card-content` area becomes vertically scrollable with a
|
|
38
|
+
* configurable `max-height` (default 400px via `--card-content-max-height`).
|
|
39
|
+
* The content div receives `role="region"`, `aria-label="Scrollable card content"`,
|
|
40
|
+
* and `tabindex="0"` so keyboard users can focus and scroll the overflowing region.
|
|
41
|
+
* Defaults to false.
|
|
42
|
+
*/
|
|
43
|
+
scrollable?: boolean;
|
|
21
44
|
};
|