@juspay/svelte-ui-components 2.121.0 → 2.123.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/Button/Button.svelte +2 -0
- package/dist/Button/properties.d.ts +5 -0
- package/dist/Card/Card.svelte +9 -3
- package/dist/Card/properties.d.ts +16 -0
- package/dist/Input/Input.svelte +15 -0
- package/dist/Input/properties.d.ts +13 -0
- package/dist/Menu/Menu.svelte +40 -14
- package/dist/Menu/properties.d.ts +28 -1
- package/dist/types.d.ts +13 -2
- package/package.json +1 -1
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
testId,
|
|
23
23
|
ariaLabel,
|
|
24
24
|
ariaExpanded,
|
|
25
|
+
ariaHaspopup,
|
|
25
26
|
ariaSelected,
|
|
26
27
|
role,
|
|
27
28
|
onclick,
|
|
@@ -88,6 +89,7 @@
|
|
|
88
89
|
role={role ?? null}
|
|
89
90
|
aria-label={ariaLabel ?? null}
|
|
90
91
|
aria-expanded={ariaExpanded ?? null}
|
|
92
|
+
aria-haspopup={ariaHaspopup ?? null}
|
|
91
93
|
aria-selected={ariaSelected ?? null}
|
|
92
94
|
aria-busy={isBusy || null}
|
|
93
95
|
type={href ? null : type}
|
|
@@ -53,6 +53,11 @@ export type OptionalButtonProperties = {
|
|
|
53
53
|
children?: Snippet;
|
|
54
54
|
ariaLabel?: string;
|
|
55
55
|
ariaExpanded?: boolean;
|
|
56
|
+
/**
|
|
57
|
+
* Native `aria-haspopup`. Needed when the button is the trigger for a menu, listbox or
|
|
58
|
+
* dialog — Menu hands exactly this to its `trigger` snippet.
|
|
59
|
+
*/
|
|
60
|
+
ariaHaspopup?: 'menu' | 'listbox' | 'tree' | 'grid' | 'dialog' | boolean;
|
|
56
61
|
ariaSelected?: boolean;
|
|
57
62
|
role?: string;
|
|
58
63
|
disabled?: boolean;
|
package/dist/Card/Card.svelte
CHANGED
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
children,
|
|
6
6
|
title,
|
|
7
7
|
description,
|
|
8
|
+
titleSnippet,
|
|
9
|
+
descriptionSnippet,
|
|
8
10
|
classes,
|
|
9
11
|
testId,
|
|
10
12
|
onclick,
|
|
@@ -64,13 +66,17 @@
|
|
|
64
66
|
onclick={onclick ?? null}
|
|
65
67
|
onkeydown={!isAnchor && isInteractive ? handleKeydown : null}
|
|
66
68
|
>
|
|
67
|
-
{#if (typeof title === 'string' && title.length > 0) || typeof headerRight === 'function'}
|
|
69
|
+
{#if (typeof title === 'string' && title.length > 0) || typeof titleSnippet === 'function' || typeof headerRight === 'function'}
|
|
68
70
|
<div class="card-header" class:card-header-split={typeof headerRight === 'function'}>
|
|
69
71
|
<div class="card-header-main">
|
|
70
|
-
{#if typeof
|
|
72
|
+
{#if typeof titleSnippet === 'function'}
|
|
73
|
+
<div class="card-title">{@render titleSnippet()}</div>
|
|
74
|
+
{:else if typeof title === 'string' && title.length > 0}
|
|
71
75
|
<div class="card-title">{title}</div>
|
|
72
76
|
{/if}
|
|
73
|
-
{#if typeof
|
|
77
|
+
{#if typeof descriptionSnippet === 'function'}
|
|
78
|
+
<div class="card-description">{@render descriptionSnippet()}</div>
|
|
79
|
+
{:else if typeof description === 'string' && description.length > 0}
|
|
74
80
|
<div class="card-description">{description}</div>
|
|
75
81
|
{/if}
|
|
76
82
|
</div>
|
|
@@ -8,6 +8,22 @@ export type OptionalCardProperties = {
|
|
|
8
8
|
children?: Snippet;
|
|
9
9
|
title?: string;
|
|
10
10
|
description?: string;
|
|
11
|
+
/**
|
|
12
|
+
* Optional snippet rendered in place of the `title` string, inside the same
|
|
13
|
+
* `.card-title` container. When provided, `title` is not rendered — the snippet
|
|
14
|
+
* takes priority — and the header row is shown even if `title` is omitted
|
|
15
|
+
* entirely. Use this when the title needs markup a string prop cannot carry:
|
|
16
|
+
* rich text, an inline icon, or a test hook such as `data-pw` /
|
|
17
|
+
* `use:testAttributes` that must sit on the title element itself.
|
|
18
|
+
*/
|
|
19
|
+
titleSnippet?: Snippet;
|
|
20
|
+
/**
|
|
21
|
+
* Optional snippet rendered in place of the `description` string, inside the
|
|
22
|
+
* same `.card-description` container. When provided, `description` is not
|
|
23
|
+
* rendered. Like `titleSnippet`, this exists for descriptions that need markup
|
|
24
|
+
* or a test hook on the element itself.
|
|
25
|
+
*/
|
|
26
|
+
descriptionSnippet?: Snippet;
|
|
11
27
|
classes?: string;
|
|
12
28
|
/** Renders as `data-pw` on the root element for Playwright test selection. */
|
|
13
29
|
testId?: string;
|
package/dist/Input/Input.svelte
CHANGED
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
infoMessage = '',
|
|
13
13
|
validators = [],
|
|
14
14
|
disable = false,
|
|
15
|
+
readonly = false,
|
|
16
|
+
spellcheck = null,
|
|
15
17
|
validationPattern = null,
|
|
16
18
|
inProgressPattern = null,
|
|
17
19
|
addFocusColor = false,
|
|
@@ -189,6 +191,15 @@
|
|
|
189
191
|
return;
|
|
190
192
|
}
|
|
191
193
|
|
|
194
|
+
// Everything below the tel branch is tel-specific digit normalisation, and
|
|
195
|
+
// onPaste was only ever invoked from inside it — so a non-tel field (notably
|
|
196
|
+
// useTextArea) had no way to observe a paste at all. Hand the event over
|
|
197
|
+
// before that branch and return, leaving tel's behaviour byte-identical.
|
|
198
|
+
if (dataType !== 'tel') {
|
|
199
|
+
onPaste(event);
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
|
|
192
203
|
if (event.clipboardData) {
|
|
193
204
|
if (dataType === 'tel') {
|
|
194
205
|
let unfilteredNumber = event.clipboardData.getData('text');
|
|
@@ -281,6 +292,8 @@
|
|
|
281
292
|
style:resize={effectiveResize}
|
|
282
293
|
rows={rows ?? null}
|
|
283
294
|
disabled={disable}
|
|
295
|
+
readonly={readonly || null}
|
|
296
|
+
{spellcheck}
|
|
284
297
|
bind:this={inputElement}
|
|
285
298
|
maxlength={dataType === 'tel' ? null : maxLength}
|
|
286
299
|
minlength={minLength}
|
|
@@ -311,6 +324,8 @@
|
|
|
311
324
|
testID={testId}
|
|
312
325
|
class:action-input={actionInput}
|
|
313
326
|
disabled={disable}
|
|
327
|
+
readonly={readonly || null}
|
|
328
|
+
{spellcheck}
|
|
314
329
|
bind:this={inputElement}
|
|
315
330
|
maxlength={dataType === 'tel' ? null : maxLength}
|
|
316
331
|
minlength={minLength}
|
|
@@ -13,6 +13,19 @@ export type OptionalInputProperties = {
|
|
|
13
13
|
infoMessage?: string | null;
|
|
14
14
|
validators?: CustomValidator[];
|
|
15
15
|
disable?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Renders the field read-only: the value can be focused, selected and copied but not
|
|
18
|
+
* edited. Deliberately distinct from `disable`, which also removes the element from
|
|
19
|
+
* the focus order and so cannot serve a select-all-to-copy affordance.
|
|
20
|
+
*/
|
|
21
|
+
readonly?: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Native `spellcheck`. Defaults to `null`, which Svelte renders as "attribute
|
|
24
|
+
* absent", so the browser default is unchanged for every existing consumer.
|
|
25
|
+
* Pass `false` for fields holding code, JSON or identifiers, where red
|
|
26
|
+
* squiggles are noise.
|
|
27
|
+
*/
|
|
28
|
+
spellcheck?: boolean | null;
|
|
16
29
|
validationPattern?: RegExp | null;
|
|
17
30
|
inProgressPattern?: RegExp | null;
|
|
18
31
|
addFocusColor?: boolean;
|
package/dist/Menu/Menu.svelte
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
open = $bindable(false),
|
|
11
11
|
testId,
|
|
12
12
|
trigger,
|
|
13
|
+
interactiveTrigger = false,
|
|
13
14
|
onselect,
|
|
14
15
|
onopen,
|
|
15
16
|
onclose,
|
|
@@ -345,20 +346,45 @@
|
|
|
345
346
|
data-pw={typeof testId === 'string' ? testId : null}
|
|
346
347
|
testID={typeof testId === 'string' ? testId : null}
|
|
347
348
|
>
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
349
|
+
<!-- Two shapes on purpose. When the snippet renders its own interactive element this
|
|
350
|
+
wrapper must NOT be a second one: two focusable nodes for one conceptual trigger
|
|
351
|
+
means two Tab stops, both announcing as a button, and interactive content nested
|
|
352
|
+
inside interactive content. The wiring is handed to the snippet instead, for it to
|
|
353
|
+
spread onto the one real control. Written as two branches rather than conditional
|
|
354
|
+
attributes so role/tabindex stay statically paired — Svelte's a11y check reads them
|
|
355
|
+
together, and a dynamic pair trips a11y_no_noninteractive_tabindex. -->
|
|
356
|
+
{#if interactiveTrigger}
|
|
357
|
+
<div class="menu-trigger" bind:this={triggerEl}>
|
|
358
|
+
{#if typeof trigger === 'function'}
|
|
359
|
+
{@render trigger({
|
|
360
|
+
onclick: toggle,
|
|
361
|
+
onkeydown: handleTriggerKeydown,
|
|
362
|
+
ariaHaspopup: 'menu',
|
|
363
|
+
ariaExpanded: open
|
|
364
|
+
})}
|
|
365
|
+
{/if}
|
|
366
|
+
</div>
|
|
367
|
+
{:else}
|
|
368
|
+
<div
|
|
369
|
+
class="menu-trigger"
|
|
370
|
+
bind:this={triggerEl}
|
|
371
|
+
onclick={toggle}
|
|
372
|
+
onkeydown={handleTriggerKeydown}
|
|
373
|
+
role="button"
|
|
374
|
+
tabindex="0"
|
|
375
|
+
aria-haspopup="menu"
|
|
376
|
+
aria-expanded={open}
|
|
377
|
+
>
|
|
378
|
+
{#if typeof trigger === 'function'}
|
|
379
|
+
{@render trigger({
|
|
380
|
+
onclick: toggle,
|
|
381
|
+
onkeydown: handleTriggerKeydown,
|
|
382
|
+
ariaHaspopup: 'menu',
|
|
383
|
+
ariaExpanded: open
|
|
384
|
+
})}
|
|
385
|
+
{/if}
|
|
386
|
+
</div>
|
|
387
|
+
{/if}
|
|
362
388
|
|
|
363
389
|
{#if open}
|
|
364
390
|
<div
|
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
import type { Snippet } from 'svelte';
|
|
2
|
+
/** The interaction wiring Menu hands to its `trigger` snippet. */
|
|
3
|
+
export type MenuTriggerProps = {
|
|
4
|
+
onclick: (event: MouseEvent) => void;
|
|
5
|
+
onkeydown: (event: KeyboardEvent) => void;
|
|
6
|
+
/** camelCase to match the library's own prop convention, so it spreads onto Button. */
|
|
7
|
+
ariaHaspopup: 'menu';
|
|
8
|
+
ariaExpanded: boolean;
|
|
9
|
+
};
|
|
2
10
|
export type MenuItem = {
|
|
3
11
|
label: string;
|
|
4
12
|
value: string;
|
|
@@ -23,7 +31,26 @@ export type MandatoryMenuProperties = {
|
|
|
23
31
|
export type OptionalMenuProperties = {
|
|
24
32
|
open?: boolean;
|
|
25
33
|
testId?: string;
|
|
26
|
-
|
|
34
|
+
/**
|
|
35
|
+
* Renders the control that opens the menu. Receives Menu's interaction wiring, so a
|
|
36
|
+
* consumer whose trigger is ITSELF an interactive element (a Button, say) can spread
|
|
37
|
+
* it onto that element and set `interactiveTrigger` — see below. A snippet that
|
|
38
|
+
* declares no parameters simply ignores what it is handed, so existing triggers are
|
|
39
|
+
* unaffected.
|
|
40
|
+
*/
|
|
41
|
+
trigger?: Snippet<[MenuTriggerProps]>;
|
|
42
|
+
/**
|
|
43
|
+
* Set when the trigger snippet renders its own interactive element. Menu then stops
|
|
44
|
+
* making its wrapper a second one.
|
|
45
|
+
*
|
|
46
|
+
* By default Menu wraps the trigger in a `role="button" tabindex="0"` div carrying
|
|
47
|
+
* the click/keydown handlers. That is correct for inert trigger content, but if the
|
|
48
|
+
* snippet renders a real control the result is two focusable elements for one
|
|
49
|
+
* conceptual trigger — two Tab stops, both announcing as a button, and interactive
|
|
50
|
+
* content nested inside interactive content. Defaults to `false`, preserving the
|
|
51
|
+
* existing behaviour for every current consumer.
|
|
52
|
+
*/
|
|
53
|
+
interactiveTrigger?: boolean;
|
|
27
54
|
classes?: string;
|
|
28
55
|
/** Value of the currently selected item. When set, opening the menu focuses the
|
|
29
56
|
* selected option instead of the first item, the matching item gets the
|
package/dist/types.d.ts
CHANGED
|
@@ -1,9 +1,20 @@
|
|
|
1
1
|
import type { FlyParams } from 'svelte/transition';
|
|
2
2
|
/**
|
|
3
3
|
* @name InputDataType
|
|
4
|
-
* @description Different types of input data which can be passed to the Input Component
|
|
4
|
+
* @description Different types of input data which can be passed to the Input Component.
|
|
5
|
+
*
|
|
6
|
+
* Input renders `<input type={dataType}>`, so this union is the only thing deciding
|
|
7
|
+
* which native types a consumer may ask for. The four added beyond the original
|
|
8
|
+
* text/tel/password/email/number all keep `value` a plain string with no parallel
|
|
9
|
+
* `checked`/`files` model, so Input's existing value plumbing covers them unchanged.
|
|
10
|
+
* `validateInput()` switches on dataType with no default branch, and `number` has
|
|
11
|
+
* always fallen through it unvalidated — these fall through identically.
|
|
12
|
+
*
|
|
13
|
+
* Deliberately NOT included: checkbox and radio (driven by `checked`, which Input has
|
|
14
|
+
* no prop for), and file (rejects scripted `value` writes outright). Those need new
|
|
15
|
+
* props, not a wider union.
|
|
5
16
|
*/
|
|
6
|
-
export type InputDataType = 'text' | 'tel' | 'password' | 'email' | 'number';
|
|
17
|
+
export type InputDataType = 'text' | 'tel' | 'password' | 'email' | 'number' | 'time' | 'date' | 'search' | 'url';
|
|
7
18
|
export type ModalTransition = 'IN' | 'ALL';
|
|
8
19
|
/**
|
|
9
20
|
* @name CustomValidator
|