@juspay/svelte-ui-components 4.33.2 → 4.34.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/Accordion/Accordion.svelte +26 -2
- package/dist/Accordion/properties.d.ts +7 -0
- package/dist/ArmedButton/ArmedButton.svelte +147 -0
- package/dist/ArmedButton/ArmedButton.svelte.d.ts +4 -0
- package/dist/ArmedButton/properties.d.ts +24 -0
- package/dist/ArmedButton/properties.js +1 -0
- package/dist/Banner/Banner.svelte +13 -8
- package/dist/Banner/properties.d.ts +8 -1
- package/dist/Button/Button.svelte +26 -0
- package/dist/Button/properties.d.ts +17 -0
- package/dist/ChatComposer/ChatComposer.svelte +314 -1
- package/dist/ChatComposer/properties.d.ts +42 -0
- package/dist/ChatMessageList/ChatMessageList.svelte +22 -2
- package/dist/ChatMessageList/ChatMessageList.svelte.d.ts +1 -1
- package/dist/CommandMenu/CommandMenu.svelte +53 -20
- package/dist/CommandMenu/properties.d.ts +24 -0
- package/dist/DiffViewer/DiffViewer.svelte +210 -0
- package/dist/DiffViewer/DiffViewer.svelte.d.ts +4 -0
- package/dist/DiffViewer/properties.d.ts +25 -0
- package/dist/DiffViewer/properties.js +1 -0
- package/dist/EmptyState/EmptyState.svelte +22 -3
- package/dist/EmptyState/properties.d.ts +9 -0
- package/dist/HITL/HITL.svelte +318 -49
- package/dist/HITL/properties.d.ts +113 -11
- package/dist/Input/Input.svelte +45 -1
- package/dist/Input/properties.d.ts +15 -0
- package/dist/KeyValue/KeyValue.svelte +16 -3
- package/dist/KeyValue/properties.d.ts +2 -0
- package/dist/Progress/Progress.svelte +96 -41
- package/dist/Progress/properties.d.ts +19 -0
- package/dist/Snippet/Snippet.svelte +45 -1
- package/dist/Snippet/properties.d.ts +8 -0
- package/dist/Tabs/Tabs.svelte +75 -16
- package/dist/Tabs/properties.d.ts +21 -0
- package/dist/ThinkingIndicator/ThinkingIndicator.svelte.d.ts +1 -1
- package/dist/ThinkingOrb/orb/modes/form.js +30 -3
- package/dist/ThinkingOrb/orb/modes/network.d.ts +4 -0
- package/dist/ThinkingOrb/orb/modes/network.js +33 -1
- package/dist/ThinkingOrb/orb/modes/sphere.js +69 -73
- package/dist/Toolbar/Toolbar.svelte +81 -3
- package/dist/Toolbar/properties.d.ts +37 -0
- package/dist/WindowedList/WindowedList.svelte +129 -0
- package/dist/WindowedList/WindowedList.svelte.d.ts +25 -0
- package/dist/WindowedList/properties.d.ts +38 -0
- package/dist/WindowedList/properties.js +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +3 -0
- package/dist/styles/theme-dark.css +42 -0
- package/dist-wc/index.js +2714 -1708
- package/package.json +2 -1
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
classes,
|
|
11
11
|
testId,
|
|
12
12
|
disabled = false,
|
|
13
|
-
panelId
|
|
13
|
+
panelId,
|
|
14
|
+
lazy = false
|
|
14
15
|
}: AccordionProperties = $props();
|
|
15
16
|
|
|
16
17
|
/* The trigger and the panel are siblings, not ancestor/descendant, so nothing in the
|
|
@@ -25,6 +26,19 @@
|
|
|
25
26
|
control's id stays stable for assistive technology and anything else referencing it. */
|
|
26
27
|
const triggerId = `accordion-trigger-${uid}`;
|
|
27
28
|
|
|
29
|
+
/* `lazy` mounts the panel's children the first time it opens and then keeps
|
|
30
|
+
them, so closing still animates real content and whatever state it holds
|
|
31
|
+
survives a close. The latch is a plain variable, not $state: it only ever
|
|
32
|
+
goes false -> true, and only while this derived recomputes because `expand`
|
|
33
|
+
or `lazy` changed, so it adds no dependency of its own. */
|
|
34
|
+
let hasOpened = false;
|
|
35
|
+
const mounted = $derived.by(() => {
|
|
36
|
+
if (!lazy || expand) {
|
|
37
|
+
hasOpened = true;
|
|
38
|
+
}
|
|
39
|
+
return hasOpened;
|
|
40
|
+
});
|
|
41
|
+
|
|
28
42
|
function handleTriggerClick(): void {
|
|
29
43
|
if (disabled) {
|
|
30
44
|
return;
|
|
@@ -62,11 +76,21 @@
|
|
|
62
76
|
aria-labelledby={trigger ? triggerId : null}
|
|
63
77
|
class="accordion {classes ?? ''}"
|
|
64
78
|
class:expanded={expand}
|
|
79
|
+
inert={lazy && !expand}
|
|
65
80
|
data-pw={typeof testId === 'string' ? testId : null}
|
|
66
81
|
testID={typeof testId === 'string' ? testId : null}
|
|
67
82
|
>
|
|
83
|
+
<!-- `inert` while collapsed, lazy only: a lazy panel's content stays mounted
|
|
84
|
+
(not torn down) between opens, so without this its links/buttons would
|
|
85
|
+
stay in the tab order and the accessibility tree while clipped to 0px
|
|
86
|
+
and invisible. A non-lazy panel never reaches this state: `mounted` is
|
|
87
|
+
already unconditionally true for it, matching pre-`lazy` behaviour, so
|
|
88
|
+
marking it inert too would be a new, non-opt-in default-path change.
|
|
89
|
+
The children are chosen by a conditional snippet, not an {#if}: an {#if} would be a
|
|
90
|
+
new block around them, so a local transition inside would stop following the outer
|
|
91
|
+
block that adds or removes the Accordion. This stays the bare render tag it was. -->
|
|
68
92
|
<div class="accordion-content">
|
|
69
|
-
{@render children?.()}
|
|
93
|
+
{@render (mounted ? children : null)?.()}
|
|
70
94
|
</div>
|
|
71
95
|
</div>
|
|
72
96
|
|
|
@@ -24,6 +24,13 @@ export type OptionalAccordionProperties = {
|
|
|
24
24
|
* something else needs to reference the panel by a known id.
|
|
25
25
|
*/
|
|
26
26
|
panelId?: string;
|
|
27
|
+
/**
|
|
28
|
+
* Mounts `children` only once the panel is first expanded, then keeps them
|
|
29
|
+
* mounted. For long lists of mostly-closed panels, where rendering every
|
|
30
|
+
* closed body up front is the cost. Off by default: closed content is
|
|
31
|
+
* rendered (though `inert`) exactly as before.
|
|
32
|
+
*/
|
|
33
|
+
lazy?: boolean;
|
|
27
34
|
};
|
|
28
35
|
export type AccordionEventProperties = {
|
|
29
36
|
ontoggle?: (expanded: boolean) => void;
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import Button from '../Button/Button.svelte';
|
|
3
|
+
import { onDestroy, type Snippet } from 'svelte';
|
|
4
|
+
import type { ArmedButtonProperties } from './properties';
|
|
5
|
+
|
|
6
|
+
// Arm-then-confirm for a destructive action: first click arms, second
|
|
7
|
+
// within the window commits, and the arm lapses on its own. No component
|
|
8
|
+
// here models a two-stage confirmation any other way -- a consumer that
|
|
9
|
+
// needs one reaches for this instead of hand-rolling a boolean and a timer,
|
|
10
|
+
// which is exactly how a shared boolean across several rows previously left
|
|
11
|
+
// one control armed forever after a single mis-click.
|
|
12
|
+
//
|
|
13
|
+
// STYLING IS BY CUSTOM PROPERTY, NOT BY CLASS. `classes` lands on this
|
|
14
|
+
// component's own root, same as every other component here; the button
|
|
15
|
+
// underneath is a separate scope a consumer's own selector cannot reach
|
|
16
|
+
// directly, so every one of its properties is bridged through an
|
|
17
|
+
// --armed-btn-* hook instead.
|
|
18
|
+
//
|
|
19
|
+
// The contract that must survive any future change here: disarm happens
|
|
20
|
+
// BEFORE `onconfirm` is awaited, not after. A version that awaits first is
|
|
21
|
+
// a different component with different behaviour under a slow confirm --
|
|
22
|
+
// it would stay visually "armed" for the duration of the call, which reads
|
|
23
|
+
// as still-awaiting-a-second-click rather than as committed.
|
|
24
|
+
|
|
25
|
+
let {
|
|
26
|
+
onconfirm,
|
|
27
|
+
label,
|
|
28
|
+
confirmLabel = 'sure?',
|
|
29
|
+
armedMs = 3000,
|
|
30
|
+
disabled = false,
|
|
31
|
+
title,
|
|
32
|
+
icon,
|
|
33
|
+
classes
|
|
34
|
+
}: ArmedButtonProperties = $props();
|
|
35
|
+
|
|
36
|
+
let armed = $state(false);
|
|
37
|
+
let timer: ReturnType<typeof setTimeout> | null = null;
|
|
38
|
+
|
|
39
|
+
function disarm(): void {
|
|
40
|
+
armed = false;
|
|
41
|
+
if (timer !== null) {
|
|
42
|
+
clearTimeout(timer);
|
|
43
|
+
}
|
|
44
|
+
timer = null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Teardown matters here: an armed row that unmounts -- the list refreshes,
|
|
48
|
+
// the session ends -- must not leave a timer holding a reference to it.
|
|
49
|
+
onDestroy(() => {
|
|
50
|
+
if (timer !== null) {
|
|
51
|
+
clearTimeout(timer);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
async function click(): Promise<void> {
|
|
56
|
+
if (timer !== null) {
|
|
57
|
+
clearTimeout(timer);
|
|
58
|
+
}
|
|
59
|
+
if (!armed) {
|
|
60
|
+
armed = true;
|
|
61
|
+
timer = setTimeout(disarm, armedMs);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
disarm();
|
|
65
|
+
await onconfirm();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Button's `text`/`icon` are plain optionals, not nullable -- omitting the
|
|
69
|
+
// key entirely (via spread) is how a Svelte prop stays genuinely unset,
|
|
70
|
+
// rather than assigning it a value that means "unset".
|
|
71
|
+
const labelProps = $derived.by((): { text?: string; icon?: Snippet } => {
|
|
72
|
+
if (armed) {
|
|
73
|
+
return { text: confirmLabel };
|
|
74
|
+
}
|
|
75
|
+
if (typeof icon === 'function') {
|
|
76
|
+
return { icon };
|
|
77
|
+
}
|
|
78
|
+
return { text: label };
|
|
79
|
+
});
|
|
80
|
+
</script>
|
|
81
|
+
|
|
82
|
+
<span
|
|
83
|
+
class="armed-button {classes ?? ''}"
|
|
84
|
+
data-armed={armed}
|
|
85
|
+
role="presentation"
|
|
86
|
+
onfocusout={disarm}
|
|
87
|
+
>
|
|
88
|
+
<Button
|
|
89
|
+
{...labelProps}
|
|
90
|
+
{disabled}
|
|
91
|
+
title={title ?? (armed ? `click again to ${label.toLowerCase()}` : label)}
|
|
92
|
+
ariaLabel={armed ? `confirm: ${label}` : label}
|
|
93
|
+
onclick={click}
|
|
94
|
+
/>
|
|
95
|
+
</span>
|
|
96
|
+
|
|
97
|
+
<style>
|
|
98
|
+
/* Every default below is a plain, generic small-button look, independent
|
|
99
|
+
of any consumer's own tokens -- exactly the two-layer fallback this
|
|
100
|
+
library uses throughout: override via --armed-btn-* if a consumer sets
|
|
101
|
+
it, sane default otherwise. */
|
|
102
|
+
.armed-button {
|
|
103
|
+
--button-color: var(--armed-btn-bg, #f0f0f0);
|
|
104
|
+
--button-hover-color: var(--armed-btn-hover-bg, var(--armed-btn-bg, #f0f0f0));
|
|
105
|
+
--button-text-color: var(--armed-btn-color, #4d4d4d);
|
|
106
|
+
--button-hover-text-color: var(--armed-btn-hover-color, #1a1a1a);
|
|
107
|
+
--button-border: var(--armed-btn-border, 1px solid #d0d0d0);
|
|
108
|
+
--button-border-radius: var(--armed-btn-radius, 7px);
|
|
109
|
+
--button-height: var(--armed-btn-height, 26px);
|
|
110
|
+
--button-width: var(--armed-btn-width, auto);
|
|
111
|
+
--button-padding: var(--armed-btn-padding, 0 8px);
|
|
112
|
+
--button-content-gap: var(--armed-btn-gap, 4px);
|
|
113
|
+
--button-font-size: var(--armed-btn-font-size, 12px);
|
|
114
|
+
--button-font-weight: var(--armed-btn-font-weight, 400);
|
|
115
|
+
--button-font-family: var(--armed-btn-font-family, inherit);
|
|
116
|
+
--button-justify-content: center;
|
|
117
|
+
--button-transition:
|
|
118
|
+
background var(--armed-btn-duration, 150ms) ease, color var(--armed-btn-duration, 150ms) ease;
|
|
119
|
+
|
|
120
|
+
--disabled-opacity: var(--armed-btn-disabled-opacity, 0.5);
|
|
121
|
+
--disabled-cursor: not-allowed;
|
|
122
|
+
|
|
123
|
+
display: var(--armed-btn-display, inline-flex);
|
|
124
|
+
margin-left: var(--armed-btn-margin-left, 0);
|
|
125
|
+
flex-shrink: var(--armed-btn-flex-shrink, 1);
|
|
126
|
+
font-variant-ligatures: var(--armed-btn-font-ligatures, normal);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/* Armed has its own geometry as well as its own colour: an icon-only
|
|
130
|
+
control is a square at rest and has to grow to fit "sure?" once armed. */
|
|
131
|
+
.armed-button[data-armed='true'] {
|
|
132
|
+
--button-color: var(--armed-btn-armed-bg, #dc2626);
|
|
133
|
+
--button-hover-color: var(--armed-btn-armed-bg, #dc2626);
|
|
134
|
+
--button-text-color: var(--armed-btn-armed-color, #ffffff);
|
|
135
|
+
--button-hover-text-color: var(--armed-btn-armed-color, #ffffff);
|
|
136
|
+
--button-border: 1px solid var(--armed-btn-armed-border, #dc2626);
|
|
137
|
+
--button-width: var(--armed-btn-armed-width, auto);
|
|
138
|
+
--button-padding: var(--armed-btn-armed-padding, 0 8px);
|
|
139
|
+
--button-font-weight: var(--armed-btn-armed-weight, 600);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
@media (prefers-reduced-motion: reduce) {
|
|
143
|
+
.armed-button {
|
|
144
|
+
--button-transition: none;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
</style>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
export type ArmedButtonProperties = {
|
|
3
|
+
/**
|
|
4
|
+
* Called on the SECOND click, after the button has disarmed. Disarming
|
|
5
|
+
* happens before this is awaited, not after -- a slow confirm must not
|
|
6
|
+
* hold the button in its armed, mid-confirmation-looking state.
|
|
7
|
+
*/
|
|
8
|
+
onconfirm: () => void | Promise<void>;
|
|
9
|
+
/** Resting label. Replaced by `confirmLabel` while armed. */
|
|
10
|
+
label: string;
|
|
11
|
+
/** Shown in place of `label` while armed. Short -- it replaces the label, not beside it. */
|
|
12
|
+
confirmLabel?: string;
|
|
13
|
+
/** How long the armed state lasts before disarming itself. */
|
|
14
|
+
armedMs?: number;
|
|
15
|
+
disabled?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Native title attribute. Defaults to `label` at rest and "click again to
|
|
18
|
+
* <label, lowercased>" while armed.
|
|
19
|
+
*/
|
|
20
|
+
title?: string;
|
|
21
|
+
/** Replaces the resting label with an icon; `confirmLabel` still shows as text once armed. */
|
|
22
|
+
icon?: Snippet;
|
|
23
|
+
classes?: string;
|
|
24
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
import closeSvg from '../assets/close.svg?raw';
|
|
11
11
|
|
|
12
12
|
let {
|
|
13
|
-
text,
|
|
13
|
+
text = '',
|
|
14
|
+
children,
|
|
14
15
|
icon,
|
|
15
16
|
linkText,
|
|
16
17
|
dismissible = false,
|
|
@@ -73,12 +74,16 @@
|
|
|
73
74
|
{@render title()}
|
|
74
75
|
</div>
|
|
75
76
|
{/if}
|
|
76
|
-
|
|
77
|
-
{
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
77
|
+
{#if typeof children === 'function'}
|
|
78
|
+
{@render children()}
|
|
79
|
+
{:else}
|
|
80
|
+
<div class="banner-text">
|
|
81
|
+
{text}
|
|
82
|
+
{#if typeof linkText === 'string' && linkText.length > 0}
|
|
83
|
+
<span class="banner-link-text">{linkText}</span>
|
|
84
|
+
{/if}
|
|
85
|
+
</div>
|
|
86
|
+
{/if}
|
|
82
87
|
</div>
|
|
83
88
|
{#if typeof rightContent === 'function'}
|
|
84
89
|
<div class="banner-right">
|
|
@@ -169,7 +174,7 @@
|
|
|
169
174
|
.banner-right {
|
|
170
175
|
display: flex;
|
|
171
176
|
align-items: center;
|
|
172
|
-
flex-shrink: 0;
|
|
177
|
+
flex-shrink: var(--banner-right-flex-shrink, 0);
|
|
173
178
|
}
|
|
174
179
|
|
|
175
180
|
.banner-dismiss {
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
import type { Snippet } from 'svelte';
|
|
2
2
|
export type BannerProperties = MandatoryBannerProperties & OptionalBannerProperties & BannerEventProperties;
|
|
3
3
|
export type MandatoryBannerProperties = {
|
|
4
|
-
text
|
|
4
|
+
/** The message as plain text (with optional `linkText`). Defaults to ''. */
|
|
5
|
+
text?: string;
|
|
5
6
|
};
|
|
6
7
|
export type OptionalBannerProperties = {
|
|
8
|
+
/**
|
|
9
|
+
* The message as markup -- a sentence with a link, or a sentence and a
|
|
10
|
+
* Retry button -- rendered as the banner body in place of `text` and
|
|
11
|
+
* `linkText`. `title` still renders above it.
|
|
12
|
+
*/
|
|
13
|
+
children?: Snippet;
|
|
7
14
|
icon?: Snippet;
|
|
8
15
|
title?: Snippet;
|
|
9
16
|
linkText?: string;
|
|
@@ -25,9 +25,12 @@
|
|
|
25
25
|
ariaControls,
|
|
26
26
|
ariaHaspopup,
|
|
27
27
|
ariaSelected,
|
|
28
|
+
ariaPressed,
|
|
28
29
|
ariaBusy,
|
|
29
30
|
role,
|
|
30
31
|
title,
|
|
32
|
+
statusText,
|
|
33
|
+
statusTestId,
|
|
31
34
|
onclick,
|
|
32
35
|
onkeydown = () => {},
|
|
33
36
|
onkeyup = () => {},
|
|
@@ -95,6 +98,7 @@
|
|
|
95
98
|
aria-controls={ariaControls ?? null}
|
|
96
99
|
aria-haspopup={ariaHaspopup ?? null}
|
|
97
100
|
aria-selected={ariaSelected ?? null}
|
|
101
|
+
aria-pressed={ariaPressed ?? null}
|
|
98
102
|
aria-busy={isBusy || ariaBusy || null}
|
|
99
103
|
title={title ?? null}
|
|
100
104
|
type={href ? null : type}
|
|
@@ -123,6 +127,11 @@
|
|
|
123
127
|
{@render children()}
|
|
124
128
|
{/if}
|
|
125
129
|
</svelte:element>
|
|
130
|
+
{#if typeof statusText === 'string'}
|
|
131
|
+
<div class="button-status" role="status" aria-live="polite" data-pw={statusTestId ?? null}>
|
|
132
|
+
{statusText}
|
|
133
|
+
</div>
|
|
134
|
+
{/if}
|
|
126
135
|
</div>
|
|
127
136
|
|
|
128
137
|
<style>
|
|
@@ -131,6 +140,23 @@
|
|
|
131
140
|
width: var(--button-width, fit-content);
|
|
132
141
|
}
|
|
133
142
|
|
|
143
|
+
/* The statusText region: out of flow at 1x1px inside the positioned
|
|
144
|
+
container, so it never moves the button or its row (the visually-hidden
|
|
145
|
+
recipe ChatComposer and Label use). Not named .sr-only: `classes` lands on
|
|
146
|
+
this container, so a consumer's own `sr-only` class would match a rule of
|
|
147
|
+
that name here and hide the whole button. */
|
|
148
|
+
.button-status {
|
|
149
|
+
position: absolute;
|
|
150
|
+
width: 1px;
|
|
151
|
+
height: 1px;
|
|
152
|
+
padding: 0;
|
|
153
|
+
overflow: hidden;
|
|
154
|
+
clip: rect(0, 0, 0, 0);
|
|
155
|
+
clip-path: inset(50%);
|
|
156
|
+
white-space: nowrap;
|
|
157
|
+
border-width: 0;
|
|
158
|
+
}
|
|
159
|
+
|
|
134
160
|
/* ---- Variant defaults (set the internal --_btn-* layer; explicit --button-* always wins) ---- */
|
|
135
161
|
.variant-primary {
|
|
136
162
|
--_btn-color: #3a4550;
|
|
@@ -64,6 +64,12 @@ export type OptionalButtonProperties = {
|
|
|
64
64
|
*/
|
|
65
65
|
ariaHaspopup?: 'menu' | 'listbox' | 'tree' | 'grid' | 'dialog' | boolean;
|
|
66
66
|
ariaSelected?: boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Native `aria-pressed`, for a toggle button (a chip that stays on once
|
|
69
|
+
* picked). `aria-selected` only means something on option/tab/row roles, so a
|
|
70
|
+
* plain button that toggles wants this instead.
|
|
71
|
+
*/
|
|
72
|
+
ariaPressed?: boolean;
|
|
67
73
|
/**
|
|
68
74
|
* Native `aria-busy`, for a control that stays usable while related data loads.
|
|
69
75
|
* Deliberately separate from `loading`, which also renders the spinner and
|
|
@@ -78,6 +84,17 @@ export type OptionalButtonProperties = {
|
|
|
78
84
|
* affordance; an icon-only button generally wants both.
|
|
79
85
|
*/
|
|
80
86
|
title?: string;
|
|
87
|
+
/**
|
|
88
|
+
* Opt-in sr-only status region (`role="status" aria-live="polite"`) rendered
|
|
89
|
+
* beside the button, never around it -- e.g. "Copied" after a copy button's
|
|
90
|
+
* click, announced without re-announcing the button itself. Rendered only
|
|
91
|
+
* when set (an empty string still renders an emptied region, which is how a
|
|
92
|
+
* caller keeps it mounted before the first announcement, as a live region
|
|
93
|
+
* must be). The sentence is the caller's; nothing is hardcoded here.
|
|
94
|
+
*/
|
|
95
|
+
statusText?: string;
|
|
96
|
+
/** Test id on the status region (see `statusText`). */
|
|
97
|
+
statusTestId?: string;
|
|
81
98
|
disabled?: boolean;
|
|
82
99
|
classes?: string;
|
|
83
100
|
/**
|