@juspay/svelte-ui-components 2.28.2 → 2.29.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/Banner/Banner.svelte +34 -7
- package/dist/Banner/properties.d.ts +2 -0
- package/dist/Breadcrumb/Breadcrumb.svelte +58 -0
- package/dist/Breadcrumb/Breadcrumb.svelte.d.ts +4 -0
- package/dist/Breadcrumb/properties.d.ts +19 -0
- package/dist/Breadcrumb/properties.js +1 -0
- package/dist/Calendar/Calendar.svelte +10 -4
- package/dist/Calendar/properties.d.ts +2 -0
- package/dist/DateRangePicker/DateRangePicker.svelte +627 -0
- package/dist/DateRangePicker/DateRangePicker.svelte.d.ts +4 -0
- package/dist/DateRangePicker/properties.d.ts +74 -0
- package/dist/DateRangePicker/properties.js +1 -0
- package/dist/EmptyState/EmptyState.svelte +3 -1
- package/dist/EmptyState/properties.d.ts +1 -1
- package/dist/FileInput/FileInput.svelte +176 -0
- package/dist/FileInput/FileInput.svelte.d.ts +4 -0
- package/dist/FileInput/properties.d.ts +18 -0
- package/dist/FileInput/properties.js +1 -0
- package/dist/Modal/Modal.svelte +5 -4
- package/dist/Pagination/Pagination.svelte +56 -11
- package/dist/Pagination/properties.d.ts +15 -0
- package/dist/Pill/Pill.svelte +10 -0
- package/dist/Pill/properties.d.ts +7 -0
- package/dist/Select/Select.svelte +77 -30
- package/dist/Select/Select.svelte.d.ts +1 -1
- package/dist/Select/properties.d.ts +12 -1
- package/dist/Sheet/Sheet.svelte +16 -0
- package/dist/Sheet/properties.d.ts +4 -0
- package/dist/Table/Table.svelte +28 -6
- package/dist/Table/properties.d.ts +6 -0
- package/dist/Tabs/Tabs.svelte +52 -8
- package/dist/index.d.ts +6 -0
- package/dist/index.js +3 -0
- package/package.json +1 -1
|
@@ -5,18 +5,26 @@
|
|
|
5
5
|
import chevronDownSvg from '../assets/chevron-down.svg?raw';
|
|
6
6
|
|
|
7
7
|
let {
|
|
8
|
-
items,
|
|
8
|
+
items: rawItems,
|
|
9
9
|
value = $bindable([]),
|
|
10
10
|
multiple = false,
|
|
11
11
|
searchable = false,
|
|
12
12
|
placeholder = '',
|
|
13
13
|
disabled = false,
|
|
14
|
+
bottomContent,
|
|
15
|
+
optionIndicator,
|
|
14
16
|
testId,
|
|
17
|
+
itemTestId,
|
|
15
18
|
onchange,
|
|
16
|
-
classes
|
|
19
|
+
classes,
|
|
20
|
+
open = $bindable(false)
|
|
17
21
|
}: SelectProperties = $props();
|
|
18
22
|
|
|
19
|
-
|
|
23
|
+
function normalizeItems(source: SelectItem[] | string[]): SelectItem[] {
|
|
24
|
+
return source.map((entry) => (typeof entry === 'string' ? { id: entry, label: entry } : entry));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
let items: SelectItem[] = $derived(normalizeItems(rawItems));
|
|
20
28
|
let query = $state('');
|
|
21
29
|
let highlightedIndex = $state(-1);
|
|
22
30
|
let containerEl: HTMLDivElement | null = $state(null);
|
|
@@ -48,13 +56,13 @@
|
|
|
48
56
|
highlightedIndex >= 0 ? `${listboxId}-option-${highlightedIndex}` : null
|
|
49
57
|
);
|
|
50
58
|
|
|
51
|
-
let searchPlaceholder = $derived(
|
|
59
|
+
let searchPlaceholder = $derived(open && displayText.length > 0 ? displayText : placeholder);
|
|
52
60
|
|
|
53
|
-
async function
|
|
54
|
-
if (disabled ||
|
|
61
|
+
async function openDropdown(): Promise<void> {
|
|
62
|
+
if (disabled || open) {
|
|
55
63
|
return;
|
|
56
64
|
}
|
|
57
|
-
|
|
65
|
+
open = true;
|
|
58
66
|
highlightedIndex = -1;
|
|
59
67
|
query = '';
|
|
60
68
|
if (searchable) {
|
|
@@ -66,7 +74,7 @@
|
|
|
66
74
|
}
|
|
67
75
|
|
|
68
76
|
function close(): void {
|
|
69
|
-
|
|
77
|
+
open = false;
|
|
70
78
|
query = '';
|
|
71
79
|
highlightedIndex = -1;
|
|
72
80
|
}
|
|
@@ -119,17 +127,17 @@
|
|
|
119
127
|
|
|
120
128
|
function handleTriggerClick(event: MouseEvent): void {
|
|
121
129
|
if (event.target instanceof HTMLInputElement) {
|
|
122
|
-
if (!
|
|
123
|
-
|
|
130
|
+
if (!open) {
|
|
131
|
+
openDropdown();
|
|
124
132
|
}
|
|
125
133
|
return;
|
|
126
134
|
}
|
|
127
135
|
if (multiple && searchable) {
|
|
128
|
-
|
|
129
|
-
} else if (
|
|
136
|
+
openDropdown();
|
|
137
|
+
} else if (open) {
|
|
130
138
|
close();
|
|
131
139
|
} else {
|
|
132
|
-
|
|
140
|
+
openDropdown();
|
|
133
141
|
}
|
|
134
142
|
}
|
|
135
143
|
|
|
@@ -140,28 +148,28 @@
|
|
|
140
148
|
switch (event.key) {
|
|
141
149
|
case 'Enter':
|
|
142
150
|
event.preventDefault();
|
|
143
|
-
if (
|
|
151
|
+
if (open) {
|
|
144
152
|
selectHighlighted();
|
|
145
153
|
} else {
|
|
146
|
-
|
|
154
|
+
openDropdown();
|
|
147
155
|
}
|
|
148
156
|
break;
|
|
149
157
|
case ' ':
|
|
150
158
|
if (!(event.target instanceof HTMLInputElement)) {
|
|
151
159
|
event.preventDefault();
|
|
152
|
-
if (
|
|
160
|
+
if (open) {
|
|
153
161
|
selectHighlighted();
|
|
154
162
|
} else {
|
|
155
|
-
|
|
163
|
+
openDropdown();
|
|
156
164
|
}
|
|
157
165
|
}
|
|
158
166
|
break;
|
|
159
167
|
case 'ArrowDown':
|
|
160
168
|
event.preventDefault();
|
|
161
|
-
if (
|
|
169
|
+
if (open) {
|
|
162
170
|
moveHighlight(1);
|
|
163
171
|
} else {
|
|
164
|
-
|
|
172
|
+
openDropdown();
|
|
165
173
|
}
|
|
166
174
|
break;
|
|
167
175
|
case 'ArrowUp':
|
|
@@ -169,7 +177,7 @@
|
|
|
169
177
|
moveHighlight(-1);
|
|
170
178
|
break;
|
|
171
179
|
case 'Escape':
|
|
172
|
-
if (
|
|
180
|
+
if (open) {
|
|
173
181
|
close();
|
|
174
182
|
if (!searchable && triggerEl !== null) {
|
|
175
183
|
triggerEl.focus();
|
|
@@ -185,7 +193,7 @@
|
|
|
185
193
|
}
|
|
186
194
|
break;
|
|
187
195
|
case 'Tab':
|
|
188
|
-
if (
|
|
196
|
+
if (open) {
|
|
189
197
|
close();
|
|
190
198
|
}
|
|
191
199
|
break;
|
|
@@ -197,15 +205,15 @@
|
|
|
197
205
|
return;
|
|
198
206
|
}
|
|
199
207
|
query = event.target.value;
|
|
200
|
-
if (!
|
|
201
|
-
|
|
208
|
+
if (!open) {
|
|
209
|
+
open = true;
|
|
202
210
|
}
|
|
203
211
|
highlightedIndex = -1;
|
|
204
212
|
}
|
|
205
213
|
|
|
206
214
|
function handleSearchFocus(): void {
|
|
207
|
-
if (!
|
|
208
|
-
|
|
215
|
+
if (!open) {
|
|
216
|
+
openDropdown();
|
|
209
217
|
}
|
|
210
218
|
}
|
|
211
219
|
|
|
@@ -229,7 +237,7 @@
|
|
|
229
237
|
|
|
230
238
|
<div
|
|
231
239
|
class="select {classes ?? ''}"
|
|
232
|
-
class:open
|
|
240
|
+
class:open
|
|
233
241
|
class:disabled
|
|
234
242
|
bind:this={containerEl}
|
|
235
243
|
{...typeof testId === 'string' ? { 'data-pw': testId } : {}}
|
|
@@ -240,7 +248,7 @@
|
|
|
240
248
|
onclick={handleTriggerClick}
|
|
241
249
|
onkeydown={handleKeydown}
|
|
242
250
|
role="combobox"
|
|
243
|
-
aria-expanded={
|
|
251
|
+
aria-expanded={open}
|
|
244
252
|
aria-haspopup="listbox"
|
|
245
253
|
aria-controls={listboxId}
|
|
246
254
|
{...highlightedOptionId !== null ? { 'aria-activedescendant': highlightedOptionId } : {}}
|
|
@@ -276,7 +284,7 @@
|
|
|
276
284
|
<input
|
|
277
285
|
class="select-search"
|
|
278
286
|
type="text"
|
|
279
|
-
value={
|
|
287
|
+
value={open ? query : displayText}
|
|
280
288
|
oninput={handleSearchInput}
|
|
281
289
|
onfocus={handleSearchFocus}
|
|
282
290
|
bind:this={searchInputEl}
|
|
@@ -294,28 +302,49 @@
|
|
|
294
302
|
<span class="select-arrow">{@html chevronDownSvg}</span>
|
|
295
303
|
</div>
|
|
296
304
|
|
|
297
|
-
{#if
|
|
305
|
+
{#if open && !disabled}
|
|
298
306
|
<div class="select-dropdown" role="listbox" id={listboxId} aria-multiselectable={multiple}>
|
|
299
307
|
{#if filteredItems.length === 0}
|
|
300
308
|
<div class="select-empty">No results</div>
|
|
301
309
|
{:else}
|
|
302
310
|
{#each filteredItems as item, index (item.id)}
|
|
303
|
-
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
|
304
311
|
<div
|
|
305
312
|
class="select-option"
|
|
313
|
+
class:multi={multiple}
|
|
306
314
|
class:selected={value.includes(item.id)}
|
|
307
315
|
class:highlighted={index === highlightedIndex}
|
|
308
316
|
role="option"
|
|
309
317
|
id={`${listboxId}-option-${index}`}
|
|
310
318
|
aria-selected={value.includes(item.id)}
|
|
311
319
|
tabindex="-1"
|
|
320
|
+
{...item.testId
|
|
321
|
+
? { 'data-pw': item.testId }
|
|
322
|
+
: typeof itemTestId === 'string'
|
|
323
|
+
? { 'data-pw': `${itemTestId}-${item.id}` }
|
|
324
|
+
: typeof testId === 'string'
|
|
325
|
+
? { 'data-pw': `${testId}-${item.id}` }
|
|
326
|
+
: {}}
|
|
312
327
|
onclick={() => selectItem(item.id)}
|
|
313
328
|
onmouseenter={() => (highlightedIndex = index)}
|
|
314
329
|
>
|
|
330
|
+
{#if multiple}
|
|
331
|
+
{#if typeof optionIndicator === 'function'}
|
|
332
|
+
{@render optionIndicator({ checked: value.includes(item.id) })}
|
|
333
|
+
{:else}
|
|
334
|
+
<span class="select-option-indicator" aria-hidden="true"
|
|
335
|
+
>{value.includes(item.id) ? '☑' : '☐'}</span
|
|
336
|
+
>
|
|
337
|
+
{/if}
|
|
338
|
+
{/if}
|
|
315
339
|
{item.label}
|
|
316
340
|
</div>
|
|
317
341
|
{/each}
|
|
318
342
|
{/if}
|
|
343
|
+
{#if typeof bottomContent === 'function'}
|
|
344
|
+
<div class="select-bottom-content">
|
|
345
|
+
{@render bottomContent()}
|
|
346
|
+
</div>
|
|
347
|
+
{/if}
|
|
319
348
|
</div>
|
|
320
349
|
{/if}
|
|
321
350
|
</div>
|
|
@@ -436,6 +465,12 @@
|
|
|
436
465
|
transition: background 0.1s;
|
|
437
466
|
}
|
|
438
467
|
|
|
468
|
+
.select-option.multi {
|
|
469
|
+
display: flex;
|
|
470
|
+
align-items: center;
|
|
471
|
+
gap: var(--select-option-gap, 0);
|
|
472
|
+
}
|
|
473
|
+
|
|
439
474
|
.select-option:hover,
|
|
440
475
|
.select-option.highlighted {
|
|
441
476
|
background: var(--select-option-hover-background, #f0f0f0);
|
|
@@ -454,6 +489,13 @@
|
|
|
454
489
|
);
|
|
455
490
|
}
|
|
456
491
|
|
|
492
|
+
.select-option-indicator {
|
|
493
|
+
display: inline-flex;
|
|
494
|
+
align-items: center;
|
|
495
|
+
color: var(--select-option-indicator-color, currentColor);
|
|
496
|
+
flex-shrink: 0;
|
|
497
|
+
}
|
|
498
|
+
|
|
457
499
|
.select-empty {
|
|
458
500
|
padding: var(--select-empty-padding, 8px 12px);
|
|
459
501
|
color: var(--select-empty-color, #999999);
|
|
@@ -461,6 +503,11 @@
|
|
|
461
503
|
font-size: var(--select-empty-font-size, inherit);
|
|
462
504
|
}
|
|
463
505
|
|
|
506
|
+
.select-bottom-content {
|
|
507
|
+
border-top: var(--select-bottom-content-border, none);
|
|
508
|
+
padding: var(--select-bottom-content-padding, 8px 12px);
|
|
509
|
+
}
|
|
510
|
+
|
|
464
511
|
.select-trigger :global(.pill) {
|
|
465
512
|
--pill-background: var(--select-pill-background, #e0e0e0);
|
|
466
513
|
--pill-color: var(--select-pill-color, #333333);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { SelectProperties } from './properties';
|
|
2
|
-
declare const Select: import("svelte").Component<SelectProperties, {}, "value">;
|
|
2
|
+
declare const Select: import("svelte").Component<SelectProperties, {}, "value" | "open">;
|
|
3
3
|
type Select = ReturnType<typeof Select>;
|
|
4
4
|
export default Select;
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
1
2
|
export type SelectProperties = MandatorySelectProperties & OptionalSelectProperties & SelectEventProperties;
|
|
2
3
|
export type SelectItem = {
|
|
3
4
|
id: string;
|
|
4
5
|
label: string;
|
|
6
|
+
/** Optional per-option test id, emitted as `data-pw` on the option element. */
|
|
7
|
+
testId?: string;
|
|
5
8
|
};
|
|
6
9
|
export type MandatorySelectProperties = {
|
|
7
|
-
items: SelectItem[];
|
|
10
|
+
items: SelectItem[] | string[];
|
|
8
11
|
};
|
|
9
12
|
export type OptionalSelectProperties = {
|
|
10
13
|
value?: string[];
|
|
@@ -12,8 +15,16 @@ export type OptionalSelectProperties = {
|
|
|
12
15
|
searchable?: boolean;
|
|
13
16
|
placeholder?: string;
|
|
14
17
|
disabled?: boolean;
|
|
18
|
+
bottomContent?: Snippet;
|
|
19
|
+
optionIndicator?: Snippet<[{
|
|
20
|
+
checked: boolean;
|
|
21
|
+
}]>;
|
|
15
22
|
testId?: string;
|
|
23
|
+
/** Fallback per-option test id prefix. Each option emits `data-pw="{itemTestId}-{id}"` when its own `item.testId` is not set. */
|
|
24
|
+
itemTestId?: string;
|
|
16
25
|
classes?: string;
|
|
26
|
+
/** Bindable. Controls whether the dropdown is open; the component writes back on open/close so parents can `bind:open` to observe or drive it. Unbound, the component manages its own state. */
|
|
27
|
+
open?: boolean;
|
|
17
28
|
};
|
|
18
29
|
export type SelectEventProperties = {
|
|
19
30
|
onchange?: (value: string[]) => void;
|
package/dist/Sheet/Sheet.svelte
CHANGED
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
content,
|
|
15
15
|
footer,
|
|
16
16
|
onclose,
|
|
17
|
+
onafteropen,
|
|
18
|
+
onafterclose,
|
|
17
19
|
classes
|
|
18
20
|
}: SheetProperties = $props();
|
|
19
21
|
|
|
@@ -90,6 +92,18 @@
|
|
|
90
92
|
}
|
|
91
93
|
};
|
|
92
94
|
}
|
|
95
|
+
|
|
96
|
+
function handleIntroEnd() {
|
|
97
|
+
if (typeof onafteropen === 'function') {
|
|
98
|
+
onafteropen();
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function handleOutroEnd() {
|
|
103
|
+
if (typeof onafterclose === 'function') {
|
|
104
|
+
onafterclose();
|
|
105
|
+
}
|
|
106
|
+
}
|
|
93
107
|
</script>
|
|
94
108
|
|
|
95
109
|
{#if open}
|
|
@@ -112,6 +126,8 @@
|
|
|
112
126
|
aria-label={title ?? 'Sheet'}
|
|
113
127
|
tabindex="-1"
|
|
114
128
|
transition:fly|global={flyParams}
|
|
129
|
+
onintroend={handleIntroEnd}
|
|
130
|
+
onoutroend={handleOutroEnd}
|
|
115
131
|
>
|
|
116
132
|
{#if typeof title === 'string' || showCloseButton}
|
|
117
133
|
<div class="sheet-header">
|
|
@@ -16,4 +16,8 @@ export type OptionalSheetProperties = {
|
|
|
16
16
|
};
|
|
17
17
|
export type SheetEventProperties = {
|
|
18
18
|
onclose?: () => void;
|
|
19
|
+
/** Called once after the open transition has fully completed. */
|
|
20
|
+
onafteropen?: () => void;
|
|
21
|
+
/** Called once after the close transition has fully completed. */
|
|
22
|
+
onafterclose?: () => void;
|
|
19
23
|
};
|
package/dist/Table/Table.svelte
CHANGED
|
@@ -24,7 +24,10 @@
|
|
|
24
24
|
empty,
|
|
25
25
|
onRowClick,
|
|
26
26
|
onSort,
|
|
27
|
-
classes
|
|
27
|
+
classes,
|
|
28
|
+
paginatorSlot,
|
|
29
|
+
getRowTestId,
|
|
30
|
+
getCellTestId
|
|
28
31
|
}: TableProperties = $props();
|
|
29
32
|
|
|
30
33
|
let sortColumn = $state<number | null>(null);
|
|
@@ -48,9 +51,9 @@
|
|
|
48
51
|
const colIndex = sortColumn;
|
|
49
52
|
const direction = sortDirection;
|
|
50
53
|
|
|
51
|
-
return [...tableData].sort((
|
|
52
|
-
const valueA =
|
|
53
|
-
const valueB =
|
|
54
|
+
return [...tableData].sort((rowA, rowB) => {
|
|
55
|
+
const valueA = rowA[colIndex];
|
|
56
|
+
const valueB = rowB[colIndex];
|
|
54
57
|
|
|
55
58
|
if (typeof valueA === 'number' && typeof valueB === 'number') {
|
|
56
59
|
return direction === 'asc' ? valueA - valueB : valueB - valueA;
|
|
@@ -171,12 +174,20 @@
|
|
|
171
174
|
<tr
|
|
172
175
|
class="table-row"
|
|
173
176
|
class:table-row-clickable={isRowClickable}
|
|
177
|
+
data-pw={typeof getRowTestId === 'function' ? getRowTestId(row, rowIndex) : null}
|
|
174
178
|
onclick={isRowClickable ? () => handleRowClick(rowIndex, row) : null}
|
|
175
|
-
onkeydown={isRowClickable
|
|
179
|
+
onkeydown={isRowClickable
|
|
180
|
+
? (keyboardEvent) => handleRowKeydown(keyboardEvent, rowIndex, row)
|
|
181
|
+
: null}
|
|
176
182
|
tabindex={isRowClickable ? 0 : null}
|
|
177
183
|
>
|
|
178
184
|
{#each row as cellValue, colIndex (colIndex)}
|
|
179
|
-
<td
|
|
185
|
+
<td
|
|
186
|
+
class="table-content"
|
|
187
|
+
data-pw={typeof getCellTestId === 'function'
|
|
188
|
+
? getCellTestId(row, cellValue, rowIndex)
|
|
189
|
+
: null}
|
|
190
|
+
>
|
|
180
191
|
<div class={isContentScrollable ? 'scrollable-content' : ''}>
|
|
181
192
|
{#if typeof cell === 'function'}
|
|
182
193
|
{@render cell(cellValue, rowIndex, colIndex)}
|
|
@@ -191,6 +202,11 @@
|
|
|
191
202
|
{/if}
|
|
192
203
|
</tbody>
|
|
193
204
|
</table>
|
|
205
|
+
{#if typeof paginatorSlot === 'function'}
|
|
206
|
+
<div class="table-footer">
|
|
207
|
+
{@render paginatorSlot()}
|
|
208
|
+
</div>
|
|
209
|
+
{/if}
|
|
194
210
|
</div>
|
|
195
211
|
{/if}
|
|
196
212
|
|
|
@@ -341,6 +357,12 @@
|
|
|
341
357
|
color: var(--table-empty-color, #9ca3af);
|
|
342
358
|
}
|
|
343
359
|
|
|
360
|
+
.table-footer {
|
|
361
|
+
border-top: var(--table-footer-border, 1px solid #e5e7eb);
|
|
362
|
+
padding: var(--table-footer-padding, 8px 16px);
|
|
363
|
+
background-color: var(--table-footer-background, transparent);
|
|
364
|
+
}
|
|
365
|
+
|
|
344
366
|
.sr-only {
|
|
345
367
|
position: absolute;
|
|
346
368
|
width: 1px;
|
|
@@ -19,6 +19,12 @@ export type OptionalTableProperties = {
|
|
|
19
19
|
cell?: Snippet<[JSONValue, number, number]>;
|
|
20
20
|
empty?: Snippet;
|
|
21
21
|
classes?: string;
|
|
22
|
+
/** Snippet rendered in a footer region below the table (e.g. a paginator). */
|
|
23
|
+
paginatorSlot?: Snippet;
|
|
24
|
+
/** Return a data-pw value for the given row. */
|
|
25
|
+
getRowTestId?: (row: JSONValue[], rowIndex: number) => string;
|
|
26
|
+
/** Return a data-pw value for the given cell. */
|
|
27
|
+
getCellTestId?: (row: JSONValue[], column: JSONValue, rowIndex: number) => string;
|
|
22
28
|
};
|
|
23
29
|
export type TableEventProperties = {
|
|
24
30
|
onRowClick?: (rowIndex: number, rowData: JSONValue[]) => void;
|
package/dist/Tabs/Tabs.svelte
CHANGED
|
@@ -44,6 +44,11 @@
|
|
|
44
44
|
let canScrollLeft = $state(false);
|
|
45
45
|
let canScrollRight = $state(false);
|
|
46
46
|
|
|
47
|
+
// Sliding indicator state
|
|
48
|
+
let indicatorLeft = $state(0);
|
|
49
|
+
let indicatorWidth = $state(0);
|
|
50
|
+
let indicatorReady = $state(false);
|
|
51
|
+
|
|
47
52
|
function updateOverflow(): void {
|
|
48
53
|
if (scrollContainer === null) {
|
|
49
54
|
return;
|
|
@@ -53,6 +58,22 @@
|
|
|
53
58
|
canScrollRight = scrollLeft + clientWidth < scrollWidth - 1;
|
|
54
59
|
}
|
|
55
60
|
|
|
61
|
+
function updateIndicator(): void {
|
|
62
|
+
if (scrollContainer === null) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const activeEl = scrollContainer.querySelector<HTMLElement>('.tabs-item.active');
|
|
66
|
+
if (activeEl === null) {
|
|
67
|
+
indicatorReady = false;
|
|
68
|
+
indicatorLeft = 0;
|
|
69
|
+
indicatorWidth = 0;
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
indicatorLeft = activeEl.offsetLeft;
|
|
73
|
+
indicatorWidth = activeEl.offsetWidth;
|
|
74
|
+
indicatorReady = true;
|
|
75
|
+
}
|
|
76
|
+
|
|
56
77
|
function scroll(direction: 'left' | 'right'): void {
|
|
57
78
|
if (scrollContainer === null) {
|
|
58
79
|
return;
|
|
@@ -73,7 +94,10 @@
|
|
|
73
94
|
if (typeof rawItem !== 'object') {
|
|
74
95
|
return;
|
|
75
96
|
}
|
|
76
|
-
const tabItem = toTabItem(rawItem)
|
|
97
|
+
const tabItem = toTabItem(rawItem);
|
|
98
|
+
if (tabItem === null) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
77
101
|
if (tabItem.key === activeKey) {
|
|
78
102
|
return;
|
|
79
103
|
}
|
|
@@ -101,8 +125,17 @@
|
|
|
101
125
|
function initOverflow(node: HTMLDivElement): { destroy: () => void } {
|
|
102
126
|
scrollContainer = node;
|
|
103
127
|
updateOverflow();
|
|
104
|
-
|
|
105
|
-
observer
|
|
128
|
+
updateIndicator();
|
|
129
|
+
const observer = new MutationObserver(() => {
|
|
130
|
+
updateOverflow();
|
|
131
|
+
updateIndicator();
|
|
132
|
+
});
|
|
133
|
+
observer.observe(node, {
|
|
134
|
+
childList: true,
|
|
135
|
+
subtree: true,
|
|
136
|
+
attributes: true,
|
|
137
|
+
attributeFilter: ['class']
|
|
138
|
+
});
|
|
106
139
|
return {
|
|
107
140
|
destroy() {
|
|
108
141
|
observer.disconnect();
|
|
@@ -153,11 +186,15 @@
|
|
|
153
186
|
{:else}
|
|
154
187
|
{label}
|
|
155
188
|
{/if}
|
|
156
|
-
{#if isActiveItem(index)}
|
|
157
|
-
<span class="tabs-indicator"></span>
|
|
158
|
-
{/if}
|
|
159
189
|
</div>
|
|
160
190
|
{/each}
|
|
191
|
+
{#if indicatorReady}
|
|
192
|
+
<span
|
|
193
|
+
class="tabs-indicator"
|
|
194
|
+
aria-hidden="true"
|
|
195
|
+
style="left: {indicatorLeft}px; width: {indicatorWidth}px;"
|
|
196
|
+
></span>
|
|
197
|
+
{/if}
|
|
161
198
|
</div>
|
|
162
199
|
{#if canScrollRight}
|
|
163
200
|
<button
|
|
@@ -199,6 +236,7 @@
|
|
|
199
236
|
gap: var(--tabs-bar-gap, 0px);
|
|
200
237
|
overflow-x: auto;
|
|
201
238
|
scrollbar-width: none;
|
|
239
|
+
position: relative;
|
|
202
240
|
}
|
|
203
241
|
|
|
204
242
|
.tabs-bar::-webkit-scrollbar {
|
|
@@ -294,10 +332,16 @@
|
|
|
294
332
|
.tabs-indicator {
|
|
295
333
|
position: absolute;
|
|
296
334
|
bottom: 0;
|
|
297
|
-
left: 0;
|
|
298
|
-
right: 0;
|
|
299
335
|
height: var(--tabs-indicator-height, 2px);
|
|
300
336
|
background-color: var(--tabs-indicator-color, #1a73e8);
|
|
301
337
|
border-radius: var(--tabs-indicator-border-radius, 2px 2px 0 0);
|
|
338
|
+
transition: var(--tabs-indicator-transition, left 0.3s ease, width 0.3s ease);
|
|
339
|
+
pointer-events: none;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
@media (prefers-reduced-motion: reduce) {
|
|
343
|
+
.tabs-indicator {
|
|
344
|
+
transition: none;
|
|
345
|
+
}
|
|
302
346
|
}
|
|
303
347
|
</style>
|
package/dist/index.d.ts
CHANGED
|
@@ -56,6 +56,9 @@ export { default as EmptyState } from './EmptyState/EmptyState.svelte';
|
|
|
56
56
|
export { default as Combobox } from './Combobox/Combobox.svelte';
|
|
57
57
|
export { default as ColorPicker } from './ColorPicker/ColorPicker.svelte';
|
|
58
58
|
export { default as SplitInput } from './SplitInput/SplitInput.svelte';
|
|
59
|
+
export { default as FileInput } from './FileInput/FileInput.svelte';
|
|
60
|
+
export { default as DateRangePicker } from './DateRangePicker/DateRangePicker.svelte';
|
|
61
|
+
export { default as Breadcrumb } from './Breadcrumb/Breadcrumb.svelte';
|
|
59
62
|
export type * from './Button/properties';
|
|
60
63
|
export type * from './Modal/properties';
|
|
61
64
|
export type * from './Input/properties';
|
|
@@ -108,4 +111,7 @@ export type * from './EmptyState/properties';
|
|
|
108
111
|
export type * from './Combobox/properties';
|
|
109
112
|
export type * from './ColorPicker/properties';
|
|
110
113
|
export type * from './SplitInput/properties';
|
|
114
|
+
export type * from './FileInput/properties';
|
|
115
|
+
export type * from './DateRangePicker/properties';
|
|
116
|
+
export type * from './Breadcrumb/properties';
|
|
111
117
|
export { validateInput } from './utils';
|
package/dist/index.js
CHANGED
|
@@ -56,4 +56,7 @@ export { default as EmptyState } from './EmptyState/EmptyState.svelte';
|
|
|
56
56
|
export { default as Combobox } from './Combobox/Combobox.svelte';
|
|
57
57
|
export { default as ColorPicker } from './ColorPicker/ColorPicker.svelte';
|
|
58
58
|
export { default as SplitInput } from './SplitInput/SplitInput.svelte';
|
|
59
|
+
export { default as FileInput } from './FileInput/FileInput.svelte';
|
|
60
|
+
export { default as DateRangePicker } from './DateRangePicker/DateRangePicker.svelte';
|
|
61
|
+
export { default as Breadcrumb } from './Breadcrumb/Breadcrumb.svelte';
|
|
59
62
|
export { validateInput } from './utils';
|