@juspay/svelte-ui-components 2.14.1 → 2.18.1
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/Button/Button.svelte +14 -0
- package/dist/Button/properties.d.ts +2 -0
- package/dist/Card/Card.svelte +51 -0
- package/dist/Card/Card.svelte.d.ts +4 -0
- package/dist/Card/properties.d.ts +10 -0
- package/dist/Card/properties.js +1 -0
- package/dist/ColorPicker/ColorPicker.svelte +583 -0
- package/dist/ColorPicker/ColorPicker.svelte.d.ts +4 -0
- package/dist/ColorPicker/properties.d.ts +15 -0
- package/dist/ColorPicker/properties.js +1 -0
- package/dist/Combobox/Combobox.svelte +432 -0
- package/dist/Combobox/Combobox.svelte.d.ts +6 -0
- package/dist/Combobox/properties.d.ts +42 -0
- package/dist/Combobox/properties.js +1 -0
- package/dist/EmptyState/EmptyState.svelte +66 -0
- package/dist/EmptyState/EmptyState.svelte.d.ts +4 -0
- package/dist/EmptyState/properties.d.ts +11 -0
- package/dist/EmptyState/properties.js +1 -0
- package/dist/Icon/Icon.svelte +22 -2
- package/dist/Icon/properties.d.ts +3 -4
- package/dist/Input/Input.svelte +30 -5
- package/dist/Input/Input.svelte.d.ts +1 -0
- package/dist/Input/properties.d.ts +11 -2
- package/dist/ListItem/ListItem.svelte +9 -3
- package/dist/ListItem/properties.d.ts +3 -0
- package/dist/Menu/Menu.svelte +17 -6
- package/dist/Menu/properties.d.ts +4 -0
- package/dist/Slider/Slider.svelte +9 -6
- package/dist/SplitInput/SplitInput.svelte +225 -0
- package/dist/SplitInput/SplitInput.svelte.d.ts +7 -0
- package/dist/SplitInput/properties.d.ts +20 -0
- package/dist/SplitInput/properties.js +1 -0
- package/dist/Toolbar/Toolbar.svelte +6 -2
- package/dist/assets/swap-vertical.svg +6 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +5 -0
- package/dist/types.d.ts +15 -1
- package/dist/utils.d.ts +10 -1
- package/dist/utils.js +118 -0
- package/package.json +1 -1
package/dist/Input/Input.svelte
CHANGED
|
@@ -17,6 +17,8 @@
|
|
|
17
17
|
addFocusColor = false,
|
|
18
18
|
maxLength = 1000,
|
|
19
19
|
minLength = 0,
|
|
20
|
+
min,
|
|
21
|
+
max,
|
|
20
22
|
actionInput = false,
|
|
21
23
|
useTextArea = false,
|
|
22
24
|
autoComplete = 'on',
|
|
@@ -26,12 +28,18 @@
|
|
|
26
28
|
textViewPresentation = [],
|
|
27
29
|
onFocus = () => {},
|
|
28
30
|
onFocusout = () => {},
|
|
31
|
+
onBlur = () => {},
|
|
29
32
|
onInput = () => {},
|
|
30
33
|
onPaste = () => {},
|
|
31
34
|
onStateChange = () => {},
|
|
32
35
|
onClick = () => {},
|
|
33
36
|
onKeyDown = () => {},
|
|
34
|
-
classes
|
|
37
|
+
classes,
|
|
38
|
+
role,
|
|
39
|
+
ariaExpanded,
|
|
40
|
+
ariaAutocomplete,
|
|
41
|
+
ariaControls,
|
|
42
|
+
ariaActivedescendant
|
|
35
43
|
}: InputProperties = $props();
|
|
36
44
|
|
|
37
45
|
export function focus() {
|
|
@@ -51,6 +59,10 @@
|
|
|
51
59
|
}
|
|
52
60
|
}
|
|
53
61
|
|
|
62
|
+
export function getInputRef(): HTMLInputElement | HTMLTextAreaElement | null {
|
|
63
|
+
return inputElement;
|
|
64
|
+
}
|
|
65
|
+
|
|
54
66
|
let inputElement: HTMLInputElement | HTMLTextAreaElement | null = $state(null);
|
|
55
67
|
|
|
56
68
|
let validationState = $derived.by(() => {
|
|
@@ -64,7 +76,7 @@
|
|
|
64
76
|
if (
|
|
65
77
|
valueValidation === 'InProgress' &&
|
|
66
78
|
value.length > 0 &&
|
|
67
|
-
inputElement &&
|
|
79
|
+
inputElement !== null &&
|
|
68
80
|
inputElement !== document.activeElement
|
|
69
81
|
) {
|
|
70
82
|
return 'Invalid';
|
|
@@ -171,6 +183,7 @@
|
|
|
171
183
|
validationState = 'Invalid';
|
|
172
184
|
}
|
|
173
185
|
onFocusout(event);
|
|
186
|
+
onBlur(event);
|
|
174
187
|
}
|
|
175
188
|
|
|
176
189
|
let _validationStateForCallback = $derived.by(() => {
|
|
@@ -197,6 +210,11 @@
|
|
|
197
210
|
{placeholder}
|
|
198
211
|
autocomplete={autoComplete}
|
|
199
212
|
{name}
|
|
213
|
+
{role}
|
|
214
|
+
aria-expanded={ariaExpanded}
|
|
215
|
+
aria-autocomplete={ariaAutocomplete}
|
|
216
|
+
aria-controls={ariaControls}
|
|
217
|
+
aria-activedescendant={ariaActivedescendant}
|
|
200
218
|
onfocus={onFocus}
|
|
201
219
|
onfocusout={_onFocusOut}
|
|
202
220
|
oninput={handleOnInput}
|
|
@@ -217,6 +235,11 @@
|
|
|
217
235
|
{placeholder}
|
|
218
236
|
autocomplete={autoComplete}
|
|
219
237
|
{name}
|
|
238
|
+
{role}
|
|
239
|
+
aria-expanded={ariaExpanded}
|
|
240
|
+
aria-autocomplete={ariaAutocomplete}
|
|
241
|
+
aria-controls={ariaControls}
|
|
242
|
+
aria-activedescendant={ariaActivedescendant}
|
|
220
243
|
onfocus={onFocus}
|
|
221
244
|
onfocusout={_onFocusOut}
|
|
222
245
|
oninput={handleOnInput}
|
|
@@ -229,6 +252,8 @@
|
|
|
229
252
|
bind:this={inputElement}
|
|
230
253
|
maxlength={dataType === 'tel' ? null : maxLength}
|
|
231
254
|
minlength={minLength}
|
|
255
|
+
{min}
|
|
256
|
+
{max}
|
|
232
257
|
/>
|
|
233
258
|
{/if}
|
|
234
259
|
|
|
@@ -293,9 +318,9 @@
|
|
|
293
318
|
.input-container {
|
|
294
319
|
display: flex;
|
|
295
320
|
flex-direction: column;
|
|
296
|
-
margin: var(--input-container-margin);
|
|
297
|
-
padding: var(--input-container-padding);
|
|
298
|
-
width: var(--input-container-width);
|
|
321
|
+
margin: var(--input-container-margin, 0);
|
|
322
|
+
padding: var(--input-container-padding, 0);
|
|
323
|
+
width: var(--input-container-width, fit-content);
|
|
299
324
|
}
|
|
300
325
|
|
|
301
326
|
.label {
|
|
@@ -2,6 +2,7 @@ import type { InputProperties } from './properties';
|
|
|
2
2
|
declare const Input: import("svelte").Component<InputProperties, {
|
|
3
3
|
focus: () => void;
|
|
4
4
|
blur: () => void;
|
|
5
|
+
getInputRef: () => HTMLInputElement | HTMLTextAreaElement | null;
|
|
5
6
|
}, "value">;
|
|
6
7
|
type Input = ReturnType<typeof Input>;
|
|
7
8
|
export default Input;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { CustomValidator, InputDataType, TextTransformer, ValidationState } from '../types';
|
|
2
|
+
import type { HTMLInputAttributes } from 'svelte/elements';
|
|
2
3
|
export type InputProperties = OptionalInputProperties & InputEventProperties & MandatoryInputProperties;
|
|
3
4
|
export type MandatoryInputProperties = {
|
|
4
5
|
value: string;
|
|
@@ -16,19 +17,27 @@ export type OptionalInputProperties = {
|
|
|
16
17
|
addFocusColor?: boolean;
|
|
17
18
|
maxLength?: number;
|
|
18
19
|
minLength?: number;
|
|
20
|
+
min?: number;
|
|
21
|
+
max?: number;
|
|
19
22
|
actionInput?: boolean;
|
|
20
23
|
useTextArea?: boolean;
|
|
21
|
-
autoComplete?:
|
|
24
|
+
autoComplete?: HTMLInputAttributes['autocomplete'];
|
|
22
25
|
name?: string;
|
|
23
26
|
textTransformers?: TextTransformer[];
|
|
24
27
|
textViewPresentation?: TextTransformer[];
|
|
25
28
|
testId?: string;
|
|
26
29
|
classes?: string;
|
|
30
|
+
role?: string;
|
|
31
|
+
ariaExpanded?: boolean;
|
|
32
|
+
ariaAutocomplete?: 'none' | 'inline' | 'list' | 'both';
|
|
33
|
+
ariaControls?: string | null;
|
|
34
|
+
ariaActivedescendant?: string | null;
|
|
27
35
|
};
|
|
28
36
|
export type InputEventProperties = {
|
|
29
37
|
onInput?: (value: string, event: Event) => void;
|
|
30
38
|
onFocus?: (event: FocusEvent) => void;
|
|
31
39
|
onFocusout?: (event: FocusEvent) => void;
|
|
40
|
+
onBlur?: (event: FocusEvent) => void;
|
|
32
41
|
onPaste?: (event: ClipboardEvent) => void;
|
|
33
42
|
onClick?: (event: MouseEvent) => void;
|
|
34
43
|
onStateChange?: (state: ValidationState) => void;
|
|
@@ -30,7 +30,10 @@
|
|
|
30
30
|
onitemClick,
|
|
31
31
|
ontopSectionClick,
|
|
32
32
|
onkeydown,
|
|
33
|
-
classes
|
|
33
|
+
classes,
|
|
34
|
+
role: itemRole,
|
|
35
|
+
ariaSelected,
|
|
36
|
+
id
|
|
34
37
|
}: ListItemProperties = $props();
|
|
35
38
|
|
|
36
39
|
function handleLeftImageClick(event: MouseEvent): void {
|
|
@@ -59,13 +62,16 @@
|
|
|
59
62
|
{#if showLoader}
|
|
60
63
|
<div class="item-loader"></div>
|
|
61
64
|
{/if}
|
|
65
|
+
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
|
|
62
66
|
<div
|
|
63
67
|
class="item"
|
|
64
68
|
class:prevent-focus={preventFocus}
|
|
65
69
|
onclick={handleItemClick}
|
|
66
70
|
{onkeydown}
|
|
67
|
-
role=
|
|
68
|
-
tabindex=
|
|
71
|
+
role={itemRole ?? 'button'}
|
|
72
|
+
tabindex={itemRole === 'option' ? -1 : 0}
|
|
73
|
+
aria-selected={ariaSelected}
|
|
74
|
+
{id}
|
|
69
75
|
data-pw={testId}
|
|
70
76
|
>
|
|
71
77
|
<div
|
|
@@ -20,6 +20,9 @@ export type ListItemProperties = ListItemEventProperties & {
|
|
|
20
20
|
rightContent?: Snippet;
|
|
21
21
|
bottomContent?: Snippet;
|
|
22
22
|
classes?: string;
|
|
23
|
+
role?: string;
|
|
24
|
+
ariaSelected?: boolean;
|
|
25
|
+
id?: string;
|
|
23
26
|
};
|
|
24
27
|
export type ListItemEventProperties = {
|
|
25
28
|
onleftImageClick?: (event: MouseEvent) => void;
|
package/dist/Menu/Menu.svelte
CHANGED
|
@@ -12,9 +12,14 @@
|
|
|
12
12
|
onselect,
|
|
13
13
|
onopen,
|
|
14
14
|
onclose,
|
|
15
|
-
classes
|
|
15
|
+
classes,
|
|
16
|
+
role: menuRole = 'menu',
|
|
17
|
+
ariaLabel: menuAriaLabel,
|
|
18
|
+
id: menuId
|
|
16
19
|
}: MenuProperties = $props();
|
|
17
20
|
|
|
21
|
+
let itemRole = $derived(menuRole === 'listbox' ? 'option' : 'menuitem');
|
|
22
|
+
|
|
18
23
|
let menuContainerEl: HTMLDivElement | null = $state(null);
|
|
19
24
|
let menuListEl: HTMLDivElement | null = $state(null);
|
|
20
25
|
let triggerEl: HTMLDivElement | null = $state(null);
|
|
@@ -70,7 +75,7 @@
|
|
|
70
75
|
return;
|
|
71
76
|
}
|
|
72
77
|
const focusableItems = menuListEl.querySelectorAll(
|
|
73
|
-
|
|
78
|
+
`[role="${itemRole}"]:not([aria-disabled="true"])`
|
|
74
79
|
);
|
|
75
80
|
const item = focusableItems.item(index);
|
|
76
81
|
if (index >= 0 && index < focusableItems.length && item instanceof HTMLElement) {
|
|
@@ -212,7 +217,9 @@
|
|
|
212
217
|
<div
|
|
213
218
|
class="menu-dropdown"
|
|
214
219
|
bind:this={menuListEl}
|
|
215
|
-
role=
|
|
220
|
+
role={menuRole}
|
|
221
|
+
id={menuId}
|
|
222
|
+
aria-label={menuAriaLabel}
|
|
216
223
|
tabindex="-1"
|
|
217
224
|
onkeydown={handleMenuKeydown}
|
|
218
225
|
>
|
|
@@ -220,14 +227,18 @@
|
|
|
220
227
|
{#if item.separator === true}
|
|
221
228
|
<div class="menu-separator" role="separator"></div>
|
|
222
229
|
{:else}
|
|
223
|
-
<!-- svelte-ignore
|
|
230
|
+
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
|
|
224
231
|
<div
|
|
225
232
|
class="menu-item"
|
|
226
233
|
class:menu-item-danger={item.danger === true}
|
|
227
234
|
class:menu-item-disabled={item.disabled === true}
|
|
228
|
-
role=
|
|
229
|
-
|
|
235
|
+
role={itemRole}
|
|
236
|
+
id={item.id}
|
|
237
|
+
tabindex={item.disabled === true || menuRole === 'listbox' ? -1 : 0}
|
|
230
238
|
aria-disabled={item.disabled === true ? 'true' : null}
|
|
239
|
+
aria-selected={menuRole === 'listbox' && focusedIndex === getSelectableIndex(item)
|
|
240
|
+
? true
|
|
241
|
+
: null}
|
|
231
242
|
onclick={() => selectItem(item)}
|
|
232
243
|
onfocus={() => {
|
|
233
244
|
if (item.disabled !== true) {
|
|
@@ -6,6 +6,7 @@ export type MenuItem = {
|
|
|
6
6
|
disabled?: boolean;
|
|
7
7
|
danger?: boolean;
|
|
8
8
|
separator?: boolean;
|
|
9
|
+
id?: string;
|
|
9
10
|
};
|
|
10
11
|
export type MenuProperties = MandatoryMenuProperties & OptionalMenuProperties & MenuEventProperties;
|
|
11
12
|
export type MandatoryMenuProperties = {
|
|
@@ -16,6 +17,9 @@ export type OptionalMenuProperties = {
|
|
|
16
17
|
testId?: string;
|
|
17
18
|
trigger?: Snippet;
|
|
18
19
|
classes?: string;
|
|
20
|
+
role?: 'menu' | 'listbox';
|
|
21
|
+
ariaLabel?: string;
|
|
22
|
+
id?: string;
|
|
19
23
|
};
|
|
20
24
|
export type MenuEventProperties = {
|
|
21
25
|
onselect?: (item: MenuItem) => void;
|
|
@@ -70,12 +70,15 @@
|
|
|
70
70
|
width: 100%;
|
|
71
71
|
height: var(--slider-track-height, 6px);
|
|
72
72
|
border-radius: var(--slider-track-border-radius, 3px);
|
|
73
|
-
background:
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
73
|
+
background: var(
|
|
74
|
+
--slider-track,
|
|
75
|
+
linear-gradient(
|
|
76
|
+
to right,
|
|
77
|
+
var(--slider-track-active-color, #2196f3) 0%,
|
|
78
|
+
var(--slider-track-active-color, #2196f3) var(--slider-fill-percent, 0%),
|
|
79
|
+
var(--slider-track-background, #e0e0e0) var(--slider-fill-percent, 0%),
|
|
80
|
+
var(--slider-track-background, #e0e0e0) 100%
|
|
81
|
+
)
|
|
79
82
|
);
|
|
80
83
|
outline: none;
|
|
81
84
|
transition: var(--slider-transition, background 0.2s ease);
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import Input from '../Input/Input.svelte';
|
|
3
|
+
import type { FieldConfig, SplitInputProperties } from './properties';
|
|
4
|
+
|
|
5
|
+
let {
|
|
6
|
+
values = $bindable([]),
|
|
7
|
+
fields,
|
|
8
|
+
length = 4,
|
|
9
|
+
disabled = false,
|
|
10
|
+
autoAdvance = false,
|
|
11
|
+
separator,
|
|
12
|
+
testId,
|
|
13
|
+
classes,
|
|
14
|
+
onchange,
|
|
15
|
+
oninput,
|
|
16
|
+
oncomplete
|
|
17
|
+
}: SplitInputProperties = $props();
|
|
18
|
+
|
|
19
|
+
let fieldCount = $derived(typeof fields !== 'undefined' ? fields.length : length);
|
|
20
|
+
|
|
21
|
+
let fieldConfigs: FieldConfig[] = $derived(
|
|
22
|
+
typeof fields !== 'undefined'
|
|
23
|
+
? fields
|
|
24
|
+
: Array.from({ length: fieldCount }, () => ({
|
|
25
|
+
dataType: 'tel' as const,
|
|
26
|
+
maxLength: 1
|
|
27
|
+
}))
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
let inputRefs: (ReturnType<typeof Input> | null)[] = $state(
|
|
31
|
+
Array.from({ length: 20 }, () => null)
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
// ── Value helpers ───────────────────────────────────────────────
|
|
35
|
+
|
|
36
|
+
function getFieldValue(index: number): string {
|
|
37
|
+
return values.at(index) ?? '';
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function commitValues() {
|
|
41
|
+
const filled = values.filter((v) => v.length > 0);
|
|
42
|
+
oninput?.([...values]);
|
|
43
|
+
onchange?.([...values]);
|
|
44
|
+
if (filled.length === fieldCount) {
|
|
45
|
+
oncomplete?.([...values]);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// ── Focus management ────────────────────────────────────────────
|
|
50
|
+
|
|
51
|
+
function focusField(index: number) {
|
|
52
|
+
if (index >= 0 && index < fieldCount) {
|
|
53
|
+
inputRefs.at(index)?.focus();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// ── Input handler ───────────────────────────────────────────────
|
|
58
|
+
|
|
59
|
+
function handleFieldInput(index: number, inputValue: string) {
|
|
60
|
+
const config = fieldConfigs.at(index);
|
|
61
|
+
if (typeof config === 'undefined') {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const maxLen = config.maxLength ?? 1000;
|
|
65
|
+
|
|
66
|
+
if (autoAdvance && maxLen === 1 && inputValue.length > 1) {
|
|
67
|
+
const chars = inputValue.replace(/\s/g, '');
|
|
68
|
+
for (let i = 0; i < fieldCount; i++) {
|
|
69
|
+
values[i] = chars.charAt(i);
|
|
70
|
+
}
|
|
71
|
+
focusField(Math.min(chars.length, fieldCount) - 1);
|
|
72
|
+
} else {
|
|
73
|
+
values[index] = inputValue;
|
|
74
|
+
if (autoAdvance && maxLen === 1 && inputValue.length > 0 && index < fieldCount - 1) {
|
|
75
|
+
focusField(index + 1);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
commitValues();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// ── Keyboard handler ────────────────────────────────────────────
|
|
82
|
+
|
|
83
|
+
function handleKeyDown(e: KeyboardEvent, index: number) {
|
|
84
|
+
if (e.key === 'Backspace') {
|
|
85
|
+
const current = getFieldValue(index);
|
|
86
|
+
if (current.length === 0 && index > 0) {
|
|
87
|
+
values[index - 1] = '';
|
|
88
|
+
focusField(index - 1);
|
|
89
|
+
commitValues();
|
|
90
|
+
}
|
|
91
|
+
} else if (e.key === 'ArrowLeft' && index > 0) {
|
|
92
|
+
focusField(index - 1);
|
|
93
|
+
} else if (e.key === 'ArrowRight' && index < fieldCount - 1) {
|
|
94
|
+
focusField(index + 1);
|
|
95
|
+
} else if (e.key === 'Tab') {
|
|
96
|
+
if (e.shiftKey && index > 0) {
|
|
97
|
+
e.preventDefault();
|
|
98
|
+
focusField(index - 1);
|
|
99
|
+
} else if (e.shiftKey === false && index < fieldCount - 1) {
|
|
100
|
+
e.preventDefault();
|
|
101
|
+
focusField(index + 1);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// ── Paste handler ───────────────────────────────────────────────
|
|
107
|
+
|
|
108
|
+
function handlePaste(e: ClipboardEvent, index: number) {
|
|
109
|
+
if (e.clipboardData === null) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
e.preventDefault();
|
|
113
|
+
const pasted = e.clipboardData.getData('text').trim();
|
|
114
|
+
|
|
115
|
+
if (autoAdvance) {
|
|
116
|
+
const chars = pasted.replace(/\s/g, '');
|
|
117
|
+
for (let i = index; i < fieldCount; i++) {
|
|
118
|
+
const charIdx = i - index;
|
|
119
|
+
if (charIdx >= chars.length) {
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
values[i] = chars.charAt(charIdx);
|
|
123
|
+
}
|
|
124
|
+
focusField(Math.min(index + chars.length, fieldCount) - 1);
|
|
125
|
+
} else {
|
|
126
|
+
values[index] = pasted;
|
|
127
|
+
}
|
|
128
|
+
commitValues();
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// ── Exported methods ────────────────────────────────────────────
|
|
132
|
+
|
|
133
|
+
export function clear() {
|
|
134
|
+
for (let i = 0; i < fieldCount; i++) {
|
|
135
|
+
values[i] = '';
|
|
136
|
+
}
|
|
137
|
+
oninput?.([...values]);
|
|
138
|
+
onchange?.([...values]);
|
|
139
|
+
focusField(0);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export function focus() {
|
|
143
|
+
focusField(0);
|
|
144
|
+
}
|
|
145
|
+
</script>
|
|
146
|
+
|
|
147
|
+
<div class="field-group {classes ?? ''}" data-pw={testId}>
|
|
148
|
+
{#each fieldConfigs as config, index (index)}
|
|
149
|
+
{#if typeof separator === 'string' && index > 0}
|
|
150
|
+
<span class="field-group-separator">{separator}</span>
|
|
151
|
+
{/if}
|
|
152
|
+
<div class="field-group-item">
|
|
153
|
+
<Input
|
|
154
|
+
value={getFieldValue(index)}
|
|
155
|
+
dataType={config.dataType ?? 'text'}
|
|
156
|
+
maxLength={config.maxLength ?? 1000}
|
|
157
|
+
min={config.min}
|
|
158
|
+
max={config.max}
|
|
159
|
+
placeholder={config.placeholder}
|
|
160
|
+
validationPattern={config.validationPattern ?? null}
|
|
161
|
+
validators={config.validators ?? []}
|
|
162
|
+
disable={disabled}
|
|
163
|
+
actionInput={true}
|
|
164
|
+
classes="field-group-input"
|
|
165
|
+
onInput={(v) => handleFieldInput(index, v)}
|
|
166
|
+
onKeyDown={(e) => handleKeyDown(e, index)}
|
|
167
|
+
onPaste={(e) => handlePaste(e, index)}
|
|
168
|
+
bind:this={inputRefs[index]}
|
|
169
|
+
/>
|
|
170
|
+
{#if typeof config.label === 'string'}
|
|
171
|
+
<span class="field-group-label">{config.label}</span>
|
|
172
|
+
{/if}
|
|
173
|
+
</div>
|
|
174
|
+
{/each}
|
|
175
|
+
</div>
|
|
176
|
+
|
|
177
|
+
<style>
|
|
178
|
+
.field-group {
|
|
179
|
+
display: flex;
|
|
180
|
+
align-items: flex-start;
|
|
181
|
+
gap: var(--field-group-gap, 8px);
|
|
182
|
+
width: var(--field-group-width, fit-content);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.field-group-item {
|
|
186
|
+
display: flex;
|
|
187
|
+
flex-direction: column;
|
|
188
|
+
align-items: center;
|
|
189
|
+
gap: var(--field-group-label-gap, 3px);
|
|
190
|
+
flex: 1;
|
|
191
|
+
min-width: 0;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.field-group-item :global(.field-group-input) {
|
|
195
|
+
--input-border: var(--field-group-border, 1px solid #d1d5db);
|
|
196
|
+
--input-radius: var(--field-group-border-radius, 6px);
|
|
197
|
+
--input-focus-border: var(--field-group-focus-border, 1px solid #3b82f6);
|
|
198
|
+
--input-width: var(--field-group-input-width, 100%);
|
|
199
|
+
--input-height: var(--field-group-input-height, 36px);
|
|
200
|
+
--input-text-align: var(--field-group-text-align, center);
|
|
201
|
+
--input-font-size: var(--field-group-font-size, 14px);
|
|
202
|
+
--input-font-weight: var(--field-group-font-weight, 500);
|
|
203
|
+
--input-font-family: var(--field-group-font-family);
|
|
204
|
+
--input-padding: var(--field-group-input-padding, 0 6px);
|
|
205
|
+
--input-margin: 0;
|
|
206
|
+
--input-box-shadow: none;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
.field-group-label {
|
|
210
|
+
font-size: var(--field-group-label-font-size, 10px);
|
|
211
|
+
font-weight: var(--field-group-label-font-weight, 500);
|
|
212
|
+
color: var(--field-group-label-color, #9ca3af);
|
|
213
|
+
text-transform: uppercase;
|
|
214
|
+
letter-spacing: 0.05em;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
.field-group-separator {
|
|
218
|
+
display: flex;
|
|
219
|
+
align-items: center;
|
|
220
|
+
height: var(--field-group-input-height, 36px);
|
|
221
|
+
font-size: var(--field-group-separator-font-size, 16px);
|
|
222
|
+
color: var(--field-group-separator-color, #9ca3af);
|
|
223
|
+
flex-shrink: 0;
|
|
224
|
+
}
|
|
225
|
+
</style>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { SplitInputProperties } from './properties';
|
|
2
|
+
declare const SplitInput: import("svelte").Component<SplitInputProperties, {
|
|
3
|
+
clear: () => void;
|
|
4
|
+
focus: () => void;
|
|
5
|
+
}, "values">;
|
|
6
|
+
type SplitInput = ReturnType<typeof SplitInput>;
|
|
7
|
+
export default SplitInput;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { OptionalInputProperties } from '../Input/properties';
|
|
2
|
+
export type FieldConfig = Pick<OptionalInputProperties, 'dataType' | 'maxLength' | 'min' | 'max' | 'placeholder' | 'validationPattern' | 'validators' | 'label'>;
|
|
3
|
+
export type SplitInputProperties = MandatorySplitInputProperties & OptionalSplitInputProperties & SplitInputEventProperties;
|
|
4
|
+
export type MandatorySplitInputProperties = {
|
|
5
|
+
values: string[];
|
|
6
|
+
};
|
|
7
|
+
export type OptionalSplitInputProperties = {
|
|
8
|
+
fields?: FieldConfig[];
|
|
9
|
+
length?: number;
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
autoAdvance?: boolean;
|
|
12
|
+
separator?: string;
|
|
13
|
+
testId?: string;
|
|
14
|
+
classes?: string;
|
|
15
|
+
};
|
|
16
|
+
export type SplitInputEventProperties = {
|
|
17
|
+
onchange?: (values: string[]) => void;
|
|
18
|
+
oninput?: (values: string[]) => void;
|
|
19
|
+
oncomplete?: (values: string[]) => void;
|
|
20
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
</div>
|
|
40
40
|
{/if}
|
|
41
41
|
</div>
|
|
42
|
-
<div class="additional-content">
|
|
42
|
+
<div class="additional-content" class:hidden={!(typeof additionalContent === 'function')}>
|
|
43
43
|
{#if typeof additionalContent === 'function'}
|
|
44
44
|
{@render additionalContent()}
|
|
45
45
|
{/if}
|
|
@@ -82,6 +82,10 @@
|
|
|
82
82
|
visibility: var(--toolbar-additional-content-visibility, visible);
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
+
.hidden {
|
|
86
|
+
display: none;
|
|
87
|
+
}
|
|
88
|
+
|
|
85
89
|
.back {
|
|
86
90
|
height: var(--toolbar-back-button-height, 20px);
|
|
87
91
|
width: var(--toolbar-back-button-width, 20px);
|
|
@@ -100,6 +104,6 @@
|
|
|
100
104
|
}
|
|
101
105
|
|
|
102
106
|
.text {
|
|
103
|
-
font-size: 18px;
|
|
107
|
+
font-size: var(--toolbar-text-font-size, 18px);
|
|
104
108
|
}
|
|
105
109
|
</style>
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path d="M7 4v16" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
3
|
+
<path d="M3 8l4-4 4 4" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
4
|
+
<path d="M17 20V4" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
5
|
+
<path d="M13 16l4 4 4-4" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
6
|
+
</svg>
|
package/dist/index.d.ts
CHANGED
|
@@ -51,6 +51,11 @@ export { default as ThemeSwitcher } from './ThemeSwitcher/ThemeSwitcher.svelte';
|
|
|
51
51
|
export { default as Book } from './Book/Book.svelte';
|
|
52
52
|
export { default as Browser } from './Browser/Browser.svelte';
|
|
53
53
|
export { default as Phone } from './Phone/Phone.svelte';
|
|
54
|
+
export { default as Card } from './Card/Card.svelte';
|
|
55
|
+
export { default as EmptyState } from './EmptyState/EmptyState.svelte';
|
|
56
|
+
export { default as Combobox } from './Combobox/Combobox.svelte';
|
|
57
|
+
export { default as ColorPicker } from './ColorPicker/ColorPicker.svelte';
|
|
58
|
+
export { default as SplitInput } from './SplitInput/SplitInput.svelte';
|
|
54
59
|
export type * from './Button/properties';
|
|
55
60
|
export type * from './Modal/properties';
|
|
56
61
|
export type * from './Input/properties';
|
|
@@ -98,4 +103,9 @@ export type * from './Book/properties';
|
|
|
98
103
|
export type * from './Browser/properties';
|
|
99
104
|
export type * from './Phone/properties';
|
|
100
105
|
export type * from './Loader/properties';
|
|
106
|
+
export type * from './Card/properties';
|
|
107
|
+
export type * from './EmptyState/properties';
|
|
108
|
+
export type * from './Combobox/properties';
|
|
109
|
+
export type * from './ColorPicker/properties';
|
|
110
|
+
export type * from './SplitInput/properties';
|
|
101
111
|
export { validateInput } from './utils';
|
package/dist/index.js
CHANGED
|
@@ -51,4 +51,9 @@ export { default as ThemeSwitcher } from './ThemeSwitcher/ThemeSwitcher.svelte';
|
|
|
51
51
|
export { default as Book } from './Book/Book.svelte';
|
|
52
52
|
export { default as Browser } from './Browser/Browser.svelte';
|
|
53
53
|
export { default as Phone } from './Phone/Phone.svelte';
|
|
54
|
+
export { default as Card } from './Card/Card.svelte';
|
|
55
|
+
export { default as EmptyState } from './EmptyState/EmptyState.svelte';
|
|
56
|
+
export { default as Combobox } from './Combobox/Combobox.svelte';
|
|
57
|
+
export { default as ColorPicker } from './ColorPicker/ColorPicker.svelte';
|
|
58
|
+
export { default as SplitInput } from './SplitInput/SplitInput.svelte';
|
|
54
59
|
export { validateInput } from './utils';
|
package/dist/types.d.ts
CHANGED
|
@@ -5,7 +5,6 @@ import type { FlyParams } from 'svelte/transition';
|
|
|
5
5
|
*/
|
|
6
6
|
export type InputDataType = 'text' | 'tel' | 'password' | 'email' | 'number';
|
|
7
7
|
export type ModalTransition = 'IN' | 'ALL';
|
|
8
|
-
export type AutoCompleteType = 'tel' | 'name' | 'email' | 'one-time-code' | 'postal-code' | 'street-address' | 'on' | 'address-level1';
|
|
9
8
|
/**
|
|
10
9
|
* @name CustomValidator
|
|
11
10
|
* @description Function type for taking input parameter and returning a boolean denoting if the value is valid or not
|
|
@@ -26,3 +25,18 @@ export type FlyAnimationConfig = {
|
|
|
26
25
|
in: FlyParams;
|
|
27
26
|
out: FlyParams;
|
|
28
27
|
};
|
|
28
|
+
export type Rgb = {
|
|
29
|
+
r: number;
|
|
30
|
+
g: number;
|
|
31
|
+
b: number;
|
|
32
|
+
};
|
|
33
|
+
export type Hsv = {
|
|
34
|
+
h: number;
|
|
35
|
+
s: number;
|
|
36
|
+
v: number;
|
|
37
|
+
};
|
|
38
|
+
export type Hsl = {
|
|
39
|
+
h: number;
|
|
40
|
+
s: number;
|
|
41
|
+
l: number;
|
|
42
|
+
};
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CustomValidator, InputDataType, ValidationState } from './types';
|
|
1
|
+
import type { CustomValidator, Hsv, Hsl, InputDataType, Rgb, ValidationState } from './types';
|
|
2
2
|
/**
|
|
3
3
|
* @description A common function to validate value provided inside the input component
|
|
4
4
|
* @param inputValue String value coming from input field
|
|
@@ -16,4 +16,13 @@ export declare function validateInput(inputValue: string, dataType: InputDataTyp
|
|
|
16
16
|
*/
|
|
17
17
|
export declare function getStorageItem(key: string): string | null;
|
|
18
18
|
export declare function setStorageItem(key: string, value: string): void;
|
|
19
|
+
export declare function hexToRgb(hex: string): Rgb | null;
|
|
20
|
+
export declare function rgbToHsv(r: number, g: number, b: number): Hsv;
|
|
21
|
+
export declare function hsvToRgb(h: number, s: number, v: number): Rgb;
|
|
22
|
+
export declare function hsvToHex(h: number, s: number, v: number): string;
|
|
23
|
+
export declare function hexToHsv(hex: string): Hsv | null;
|
|
24
|
+
export declare function hsvToHsl(h: number, s: number, v: number): Hsl;
|
|
25
|
+
export declare function hslToHsv(hDeg: number, sPct: number, lPct: number): Hsv;
|
|
26
|
+
export declare function isValidHex(hex: string): boolean;
|
|
27
|
+
export declare function clampInt(v: string, min: number, max: number): number;
|
|
19
28
|
export declare function createDebouncer(delay: number): <T extends unknown[]>(callback: (...args: T) => void, ...args: T) => void;
|