@juspay/svelte-ui-components 3.5.0 → 3.5.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/README.md +1 -1
- package/dist/Accordion/Accordion.svelte +1 -5
- package/dist/Accordion/properties.d.ts +0 -1
- package/dist/AreaChart/AreaChart.svelte +2 -8
- package/dist/AreaChart/properties.d.ts +0 -10
- package/dist/AttachmentChipRow/AttachmentChipRow.svelte +30 -30
- package/dist/AttachmentChipRow/properties.d.ts +6 -6
- package/dist/Banner/Banner.svelte +1 -5
- package/dist/Banner/properties.d.ts +0 -1
- package/dist/BarChart/BarChart.svelte +7 -13
- package/dist/BarChart/properties.d.ts +1 -9
- package/dist/Book/Book.svelte +1 -5
- package/dist/Book/properties.d.ts +0 -1
- package/dist/Calendar/Calendar.svelte +3 -11
- package/dist/Calendar/properties.d.ts +0 -11
- package/dist/Chat/Chat.svelte +9 -29
- package/dist/Chat/properties.d.ts +0 -9
- package/dist/Chat/types.d.ts +7 -0
- package/dist/ChatBubble/ChatBubble.svelte +3 -11
- package/dist/ChatBubble/properties.d.ts +0 -3
- package/dist/ChatComposer/ChatComposer.svelte +18 -44
- package/dist/ChatComposer/properties.d.ts +0 -12
- package/dist/ChatHeader/ChatHeader.svelte +1 -5
- package/dist/ChatHeader/properties.d.ts +0 -1
- package/dist/ChatMessage/ChatMessage.svelte +87 -11
- package/dist/ChatMessage/properties.d.ts +18 -3
- package/dist/ChatMessageList/ChatMessageList.svelte +5 -11
- package/dist/ChatMessageList/properties.d.ts +0 -6
- package/dist/ChatSuggestions/ChatSuggestions.svelte +1 -5
- package/dist/ChatSuggestions/properties.d.ts +0 -1
- package/dist/CheckListItem/CheckListItem.svelte +1 -5
- package/dist/CheckListItem/properties.d.ts +0 -1
- package/dist/Checkbox/Checkbox.svelte +1 -5
- package/dist/Checkbox/properties.d.ts +0 -1
- package/dist/ChipInput/ChipInput.svelte +10 -20
- package/dist/ChipInput/properties.d.ts +0 -4
- package/dist/Choicebox/Choicebox.svelte +1 -5
- package/dist/Choicebox/properties.d.ts +0 -1
- package/dist/ColorPicker/ColorPicker.svelte +4 -10
- package/dist/ColorPicker/properties.d.ts +0 -2
- package/dist/Combobox/Combobox.svelte +15 -33
- package/dist/Combobox/properties.d.ts +0 -8
- package/dist/CommandMenu/CommandMenu.svelte +2 -8
- package/dist/CommandMenu/properties.d.ts +0 -2
- package/dist/ContextMenu/ContextMenu.svelte +3 -11
- package/dist/ContextMenu/properties.d.ts +0 -3
- package/dist/DateRangePicker/DateRangePicker.svelte +6 -20
- package/dist/DateRangePicker/properties.d.ts +0 -19
- package/dist/Draggable/Draggable.svelte +7 -7
- package/dist/Draggable/properties.d.ts +3 -3
- package/dist/DualAxisBarChart/DualAxisBarChart.svelte +1 -5
- package/dist/DualAxisBarChart/properties.d.ts +0 -4
- package/dist/FileDropzoneTrigger/FileDropzoneTrigger.svelte +1 -5
- package/dist/FileDropzoneTrigger/properties.d.ts +0 -1
- package/dist/FileInput/FileInput.svelte +2 -8
- package/dist/FileInput/properties.d.ts +0 -2
- package/dist/FunnelChart/FunnelChart.svelte +2 -8
- package/dist/FunnelChart/properties.d.ts +0 -8
- package/dist/Gallery/Gallery.svelte +15 -15
- package/dist/Gallery/properties.d.ts +6 -6
- package/dist/HITL/HITL.svelte +10 -8
- package/dist/HITL/properties.d.ts +2 -2
- package/dist/IframeViewer/IframeViewer.svelte +3 -2
- package/dist/IframeViewer/properties.d.ts +1 -1
- package/dist/Img/Img.svelte +119 -39
- package/dist/Img/properties.d.ts +0 -1
- package/dist/Input/Input.svelte +22 -37
- package/dist/Input/properties.d.ts +3 -10
- package/dist/InputButton/InputButton.svelte +2 -2
- package/dist/LineChart/LineChart.svelte +4 -10
- package/dist/LineChart/properties.d.ts +1 -11
- package/dist/ListItem/ListItem.svelte +10 -22
- package/dist/ListItem/properties.d.ts +5 -10
- package/dist/LottiePlayer/LottiePlayer.svelte +2 -8
- package/dist/LottiePlayer/properties.d.ts +0 -2
- package/dist/MediaPlayer/MediaPlayer.svelte +1 -5
- package/dist/MediaPlayer/properties.d.ts +0 -1
- package/dist/MediaUpload/MediaUpload.svelte +6 -6
- package/dist/MediaUpload/properties.d.ts +3 -3
- package/dist/Menu/Menu.svelte +3 -11
- package/dist/Menu/properties.d.ts +0 -3
- package/dist/Modal/Modal.svelte +15 -31
- package/dist/Modal/properties.d.ts +5 -11
- package/dist/Pagination/Pagination.svelte +3 -7
- package/dist/Pagination/properties.d.ts +1 -2
- package/dist/PieChart/PieChart.svelte +4 -10
- package/dist/PieChart/properties.d.ts +1 -9
- package/dist/Pill/Pill.svelte +1 -5
- package/dist/Pill/properties.d.ts +0 -1
- package/dist/Radio/Radio.svelte +1 -5
- package/dist/Radio/properties.d.ts +0 -1
- package/dist/Resizable/Resizable.svelte +3 -11
- package/dist/Resizable/properties.d.ts +0 -3
- package/dist/SankeyChart/SankeyChart.svelte +4 -14
- package/dist/SankeyChart/properties.d.ts +0 -12
- package/dist/Scroller/Scroller.svelte +1 -5
- package/dist/Scroller/properties.d.ts +0 -1
- package/dist/Select/Select.svelte +3 -11
- package/dist/Select/properties.d.ts +0 -3
- package/dist/Sheet/Sheet.svelte +3 -11
- package/dist/Sheet/properties.d.ts +0 -3
- package/dist/Slider/Slider.svelte +2 -8
- package/dist/Slider/properties.d.ts +0 -2
- package/dist/Snippet/Snippet.svelte +1 -5
- package/dist/Snippet/properties.d.ts +0 -1
- package/dist/SplitButton/SplitButton.svelte +1 -5
- package/dist/SplitButton/properties.d.ts +0 -1
- package/dist/SplitInput/SplitInput.svelte +6 -14
- package/dist/SplitInput/properties.d.ts +0 -3
- package/dist/StatCard/StatCard.svelte +2 -2
- package/dist/StatCard/properties.d.ts +1 -1
- package/dist/Status/Status.svelte +2 -6
- package/dist/Status/properties.d.ts +1 -2
- package/dist/Stepper/Stepper.svelte +2 -12
- package/dist/Stepper/properties.d.ts +1 -14
- package/dist/Table/BuiltinCell.svelte +1 -1
- package/dist/Table/Table.svelte +16 -17
- package/dist/Table/properties.d.ts +3 -35
- package/dist/Tabs/Tabs.svelte +2 -8
- package/dist/Tabs/properties.d.ts +0 -2
- package/dist/TaskList/TaskList.svelte +1 -4
- package/dist/TaskList/properties.d.ts +0 -1
- package/dist/ThemeSwitcher/ThemeSwitcher.svelte +1 -5
- package/dist/ThemeSwitcher/properties.d.ts +0 -1
- package/dist/ThinkingIndicator/ThinkingIndicator.svelte +4 -10
- package/dist/ThinkingIndicator/properties.d.ts +1 -3
- package/dist/Toast/Toast.svelte +2 -2
- package/dist/Toast/properties.d.ts +1 -1
- package/dist/Toggle/Toggle.svelte +1 -5
- package/dist/Toggle/properties.d.ts +0 -1
- package/dist/ToolCallLog/ToolCallLog.svelte +1 -10
- package/dist/ToolCallLog/properties.d.ts +0 -1
- package/dist/Toolbar/Toolbar.svelte +2 -6
- package/dist/Toolbar/properties.d.ts +1 -2
- package/dist/TypewriterText/TypewriterText.svelte +3 -3
- package/dist/TypewriterText/properties.d.ts +1 -1
- package/dist-codemod/bin.js +32 -0
- package/dist-codemod/cli.js +175 -0
- package/dist-codemod/legacy-pairs.js +228 -0
- package/dist-codemod/transform.js +278 -0
- package/dist-codemod/wc-children.js +66 -0
- package/dist-wc/index.js +4458 -5127
- package/package.json +9 -7
- package/scripts/postinstall.mjs +14 -12
- package/dist/deprecation.d.ts +0 -42
- package/dist/deprecation.js +0 -57
- package/scripts/codemod/README.md +0 -76
- package/scripts/codemod/cli.ts +0 -206
- package/scripts/codemod/map.ts +0 -118
- package/scripts/codemod/transform.ts +0 -549
- package/scripts/codemod/tsconfig.json +0 -15
- package/scripts/codemod/wc-children.ts +0 -75
package/dist/Img/Img.svelte
CHANGED
|
@@ -1,20 +1,8 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { ImgProperties } from './properties';
|
|
3
3
|
|
|
4
|
-
let {
|
|
5
|
-
|
|
6
|
-
alt,
|
|
7
|
-
fallback,
|
|
8
|
-
onerror: onerrorLegacy,
|
|
9
|
-
onError,
|
|
10
|
-
classes,
|
|
11
|
-
inlineSvg,
|
|
12
|
-
transformSvg,
|
|
13
|
-
testId
|
|
14
|
-
}: ImgProperties = $props();
|
|
15
|
-
|
|
16
|
-
// Event-casing phase 1: both spellings accepted, the correct one wins.
|
|
17
|
-
const onerror = $derived(onError ?? onerrorLegacy);
|
|
4
|
+
let { src, alt, fallback, onerror, classes, inlineSvg, transformSvg, testId }: ImgProperties =
|
|
5
|
+
$props();
|
|
18
6
|
|
|
19
7
|
let currentSrc = $derived(src);
|
|
20
8
|
// Per-source failure marker: when inlining a given URL fails we fall back to
|
|
@@ -92,10 +80,83 @@
|
|
|
92
80
|
'focusable'
|
|
93
81
|
]);
|
|
94
82
|
|
|
83
|
+
/**
|
|
84
|
+
* The host attributes this component writes itself. A fetched root may
|
|
85
|
+
* legitimately overwrite one (an icon set's own role/aria-label), and the
|
|
86
|
+
* src-change cleanup then has to put the component's value back rather than
|
|
87
|
+
* just remove it: Svelte only re-applies its own attribute when `alt` or
|
|
88
|
+
* `testId` changes, so a bare removal would leave the host with no role
|
|
89
|
+
* until the next re-render.
|
|
90
|
+
*/
|
|
91
|
+
/**
|
|
92
|
+
* `alt` is a required `string` in `properties.ts`, which settles it for a
|
|
93
|
+
* Svelte consumer and settles nothing for a web-component one: `<sui-img>`
|
|
94
|
+
* takes its props from JavaScript, so an omitted `alt` arrives as undefined
|
|
95
|
+
* and every `alt.length` below would throw where the compiler cannot see it.
|
|
96
|
+
*/
|
|
97
|
+
const label = $derived(alt ?? '');
|
|
98
|
+
|
|
99
|
+
function restoreHostOwnedAttribute(host: SVGSVGElement, name: string): boolean {
|
|
100
|
+
const named = label.length > 0;
|
|
101
|
+
switch (name.toLowerCase()) {
|
|
102
|
+
case 'role':
|
|
103
|
+
return setOrRemove(host, name, named ? 'img' : null);
|
|
104
|
+
case 'aria-label':
|
|
105
|
+
return setOrRemove(host, name, named ? label : null);
|
|
106
|
+
case 'aria-hidden':
|
|
107
|
+
return setOrRemove(host, name, named ? null : 'true');
|
|
108
|
+
case 'data-pw':
|
|
109
|
+
case 'testid':
|
|
110
|
+
return setOrRemove(host, name, testId ?? null);
|
|
111
|
+
default:
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function setOrRemove(host: SVGSVGElement, name: string, value: string | null): boolean {
|
|
117
|
+
if (value === null) {
|
|
118
|
+
host.removeAttribute(name);
|
|
119
|
+
} else {
|
|
120
|
+
host.setAttribute(name, value);
|
|
121
|
+
}
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
|
|
95
125
|
function isSafeInlineRootAttribute(lowerCaseName: string): boolean {
|
|
96
126
|
return SAFE_INLINE_ROOT_ATTRIBUTES.has(lowerCaseName) || lowerCaseName.startsWith('aria-');
|
|
97
127
|
}
|
|
98
128
|
|
|
129
|
+
/**
|
|
130
|
+
* Descendants removed outright, because nothing static artwork needs is
|
|
131
|
+
* expressed with them.
|
|
132
|
+
*
|
|
133
|
+
* `script` and `foreignObject` are the obvious two. The SMIL animation
|
|
134
|
+
* elements are here because SMIL animates *any* attribute by name — `<set
|
|
135
|
+
* attributeName="onclick" to="…">` plants an event handler, and `<animate
|
|
136
|
+
* attributeName="xlink:href" values="javascript:…">` plants a URL — so a
|
|
137
|
+
* guard that strips `on*` and bad hrefs at adoption time but keeps SMIL
|
|
138
|
+
* only moves the same vector one element deeper, to be applied a frame
|
|
139
|
+
* later. `use` stays: it is how real icon sets reference their own `defs`,
|
|
140
|
+
* and where it points is handled by the URL rule below.
|
|
141
|
+
*/
|
|
142
|
+
const REMOVED_ELEMENTS =
|
|
143
|
+
'script, foreignObject, animate, animateMotion, animateTransform, set, mpath, discard';
|
|
144
|
+
|
|
145
|
+
const URL_ATTRIBUTES: ReadonlySet<string> = new Set(['href', 'xlink:href', 'src']);
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Whether a URL attribute points inside this same document (`#gradient`).
|
|
149
|
+
*
|
|
150
|
+
* Only a fragment survives. A `javascript:` URL is the classic vector, but
|
|
151
|
+
* an ordinary remote URL is not safe either: on `<image href>` or `<use
|
|
152
|
+
* href>` it fetches on adoption, which is a request the consumer's page
|
|
153
|
+
* never asked to make, from markup the consumer did not write. A same
|
|
154
|
+
* document reference can do neither.
|
|
155
|
+
*/
|
|
156
|
+
function isSameDocumentReference(value: string): boolean {
|
|
157
|
+
return value.trim().startsWith('#');
|
|
158
|
+
}
|
|
159
|
+
|
|
99
160
|
/**
|
|
100
161
|
* Strips executable content from a fetched SVG's descendants.
|
|
101
162
|
*
|
|
@@ -110,11 +171,11 @@
|
|
|
110
171
|
* legitimately carry the entire SVG geometry and paint vocabulary (`d`,
|
|
111
172
|
* `transform`, `gradientUnits`, …), so enumerating what is permitted would
|
|
112
173
|
* break real artwork. What is dangerous is narrow and well understood:
|
|
113
|
-
* scripting elements, `on*` handlers, and URL attributes
|
|
114
|
-
*
|
|
174
|
+
* scripting elements, SMIL animation, `on*` handlers, and URL attributes
|
|
175
|
+
* that leave this document.
|
|
115
176
|
*/
|
|
116
177
|
function sanitizeInlinedSubtree(root: SVGSVGElement): void {
|
|
117
|
-
for (const element of Array.from(root.querySelectorAll(
|
|
178
|
+
for (const element of Array.from(root.querySelectorAll(REMOVED_ELEMENTS))) {
|
|
118
179
|
element.remove();
|
|
119
180
|
}
|
|
120
181
|
for (const element of Array.from(root.querySelectorAll('*'))) {
|
|
@@ -124,10 +185,7 @@
|
|
|
124
185
|
element.removeAttribute(attribute.name);
|
|
125
186
|
continue;
|
|
126
187
|
}
|
|
127
|
-
|
|
128
|
-
// on activation of an <a> wrapper or on load of a nested resource.
|
|
129
|
-
const isUrlAttribute = name === 'href' || name === 'xlink:href' || name === 'src';
|
|
130
|
-
if (isUrlAttribute && /^\s*javascript:/i.test(attribute.value)) {
|
|
188
|
+
if (URL_ATTRIBUTES.has(name) && !isSameDocumentReference(attribute.value)) {
|
|
131
189
|
element.removeAttribute(attribute.name);
|
|
132
190
|
}
|
|
133
191
|
}
|
|
@@ -150,17 +208,25 @@
|
|
|
150
208
|
return new Set(Array.from(root.attributes, (attribute) => attribute.name.toLowerCase()));
|
|
151
209
|
}
|
|
152
210
|
|
|
211
|
+
/**
|
|
212
|
+
* Resolves to the root attribute names this load copied onto the host, so
|
|
213
|
+
* the next load can remove them first. Without that, an attribute the
|
|
214
|
+
* previous file supplied (say `fill`) outlives a `src` change to a file that
|
|
215
|
+
* does not, and the two icons blend. Early exits hand back `previouslyCopied`
|
|
216
|
+
* untouched: nothing was painted, so nothing is owed.
|
|
217
|
+
*/
|
|
153
218
|
async function loadInlineSvg(
|
|
154
219
|
host: SVGSVGElement,
|
|
155
220
|
url: string,
|
|
156
221
|
transform: ((svg: string) => string) | null,
|
|
157
|
-
signal: AbortSignal
|
|
158
|
-
|
|
222
|
+
signal: AbortSignal,
|
|
223
|
+
previouslyCopied: readonly string[]
|
|
224
|
+
): Promise<readonly string[]> {
|
|
159
225
|
try {
|
|
160
226
|
const response = await fetch(url, { signal });
|
|
161
227
|
if (!response.ok) {
|
|
162
228
|
failedInlineSrc = url;
|
|
163
|
-
return;
|
|
229
|
+
return previouslyCopied;
|
|
164
230
|
}
|
|
165
231
|
const rawSvg = await response.text();
|
|
166
232
|
const hasTransform = typeof transform === 'function';
|
|
@@ -168,22 +234,27 @@
|
|
|
168
234
|
const parsed = new DOMParser().parseFromString(markup, 'image/svg+xml');
|
|
169
235
|
if (parsed.querySelector('parsererror') !== null) {
|
|
170
236
|
failedInlineSrc = url;
|
|
171
|
-
return;
|
|
237
|
+
return previouslyCopied;
|
|
172
238
|
}
|
|
173
239
|
const sourceSvg = parsed.querySelector('svg');
|
|
174
240
|
if (sourceSvg === null) {
|
|
175
241
|
failedInlineSrc = url;
|
|
176
|
-
return;
|
|
242
|
+
return previouslyCopied;
|
|
177
243
|
}
|
|
178
244
|
// The action may have been torn down (or re-run) while awaiting the
|
|
179
245
|
// body — bail before mutating so a stale fetch never paints over the
|
|
180
246
|
// latest one.
|
|
181
247
|
if (signal.aborted) {
|
|
182
|
-
return;
|
|
248
|
+
return previouslyCopied;
|
|
183
249
|
}
|
|
184
250
|
while (host.firstChild !== null) {
|
|
185
251
|
host.removeChild(host.firstChild);
|
|
186
252
|
}
|
|
253
|
+
for (const name of previouslyCopied) {
|
|
254
|
+
if (!restoreHostOwnedAttribute(host, name)) {
|
|
255
|
+
host.removeAttribute(name);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
187
258
|
// With no transform the parsed root IS the fetched root, so every name
|
|
188
259
|
// is network-supplied and only the allowlist applies. With a transform,
|
|
189
260
|
// names absent from the raw payload were added by the caller's own hook
|
|
@@ -191,36 +262,45 @@
|
|
|
191
262
|
// nothing can be attributed to the caller and the allowlist applies to
|
|
192
263
|
// everything.
|
|
193
264
|
const fetchedRootNames = hasTransform ? collectRootAttributeNames(rawSvg) : null;
|
|
194
|
-
|
|
265
|
+
const accepted = Array.from(sourceSvg.attributes).filter((attribute) => {
|
|
195
266
|
const name = attribute.name.toLowerCase();
|
|
196
|
-
if (name === 'class') {
|
|
197
|
-
continue;
|
|
198
|
-
}
|
|
199
267
|
const addedByTransform = fetchedRootNames !== null && !fetchedRootNames.has(name);
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
268
|
+
return name !== 'class' && (isSafeInlineRootAttribute(name) || addedByTransform);
|
|
269
|
+
});
|
|
270
|
+
for (const attribute of accepted) {
|
|
271
|
+
host.setAttribute(attribute.name, attribute.value);
|
|
203
272
|
}
|
|
273
|
+
const copied = accepted.map((attribute) => attribute.name);
|
|
204
274
|
// Before adoption, not after: an event-handler attribute becomes a live
|
|
205
275
|
// handler as soon as its element enters the document.
|
|
206
276
|
sanitizeInlinedSubtree(sourceSvg);
|
|
207
277
|
while (sourceSvg.firstChild !== null) {
|
|
208
278
|
host.appendChild(sourceSvg.firstChild);
|
|
209
279
|
}
|
|
280
|
+
return copied;
|
|
210
281
|
} catch {
|
|
211
282
|
if (!signal.aborted) {
|
|
212
283
|
failedInlineSrc = url;
|
|
213
284
|
}
|
|
285
|
+
return previouslyCopied;
|
|
214
286
|
}
|
|
215
287
|
}
|
|
216
288
|
|
|
217
289
|
function inlineSvgInto(host: SVGSVGElement, params: InlineParams) {
|
|
218
290
|
let controller = new AbortController();
|
|
291
|
+
let copied: readonly string[] = [];
|
|
219
292
|
|
|
220
293
|
function load(current: InlineParams): void {
|
|
221
294
|
controller.abort();
|
|
222
295
|
controller = new AbortController();
|
|
223
|
-
|
|
296
|
+
const { signal } = controller;
|
|
297
|
+
void loadInlineSvg(host, current.url, current.transform, signal, copied).then((names) => {
|
|
298
|
+
// A superseded load resolves after the one that replaced it may
|
|
299
|
+
// already have recorded its own names; only the live load may write.
|
|
300
|
+
if (!signal.aborted) {
|
|
301
|
+
copied = names;
|
|
302
|
+
}
|
|
303
|
+
});
|
|
224
304
|
}
|
|
225
305
|
|
|
226
306
|
load(params);
|
|
@@ -240,9 +320,9 @@
|
|
|
240
320
|
<svg
|
|
241
321
|
use:inlineSvgInto={{ url: currentSrc, transform: transformSvg ?? null }}
|
|
242
322
|
class={classes ?? ''}
|
|
243
|
-
role={
|
|
244
|
-
aria-label={
|
|
245
|
-
aria-hidden={
|
|
323
|
+
role={label.length > 0 ? 'img' : null}
|
|
324
|
+
aria-label={label.length > 0 ? label : null}
|
|
325
|
+
aria-hidden={label.length === 0 ? 'true' : null}
|
|
246
326
|
data-pw={testId}
|
|
247
327
|
testID={testId}
|
|
248
328
|
></svg>
|
|
@@ -250,7 +330,7 @@
|
|
|
250
330
|
<img
|
|
251
331
|
class={classes ?? ''}
|
|
252
332
|
src={currentSrc}
|
|
253
|
-
{
|
|
333
|
+
alt={label}
|
|
254
334
|
onerror={handleFallback}
|
|
255
335
|
data-pw={testId}
|
|
256
336
|
testID={testId}
|
package/dist/Img/properties.d.ts
CHANGED
package/dist/Input/Input.svelte
CHANGED
|
@@ -30,20 +30,14 @@
|
|
|
30
30
|
testId = '',
|
|
31
31
|
textTransformers = [],
|
|
32
32
|
textViewPresentation = [],
|
|
33
|
-
onFocus: onFocusLegacy = () => {},
|
|
34
33
|
onfocus,
|
|
35
|
-
onFocusout: onFocusoutLegacy = () => {},
|
|
36
34
|
onfocusout,
|
|
37
|
-
onBlur: onBlurLegacy = () => {},
|
|
38
35
|
onblur,
|
|
39
|
-
onInput: onInputLegacy = () => {},
|
|
40
36
|
oninput,
|
|
41
|
-
onPaste: onPasteLegacy = () => {},
|
|
42
37
|
onpaste,
|
|
43
|
-
|
|
44
|
-
|
|
38
|
+
// Called unguarded below, so it keeps the no-op default the resolver gave it.
|
|
39
|
+
onstatechange = () => {},
|
|
45
40
|
onclick,
|
|
46
|
-
onKeyDown: onKeyDownLegacy = () => {},
|
|
47
41
|
onkeydown,
|
|
48
42
|
classes,
|
|
49
43
|
role,
|
|
@@ -54,8 +48,8 @@
|
|
|
54
48
|
ariaActivedescendant,
|
|
55
49
|
leftIcon,
|
|
56
50
|
rightIcon,
|
|
57
|
-
|
|
58
|
-
|
|
51
|
+
onlefticonclick,
|
|
52
|
+
onrighticonclick,
|
|
59
53
|
leftIconLabel = 'Leading action',
|
|
60
54
|
rightIconLabel = 'Trailing action',
|
|
61
55
|
mandatory = false,
|
|
@@ -68,15 +62,6 @@
|
|
|
68
62
|
showCount = false
|
|
69
63
|
}: InputProperties = $props();
|
|
70
64
|
|
|
71
|
-
// Event-casing phase 1: both spellings accepted, the correct one wins.
|
|
72
|
-
const onBlur = $derived(onblur ?? onBlurLegacy);
|
|
73
|
-
const onClick = $derived(onclick ?? onClickLegacy);
|
|
74
|
-
const onFocus = $derived(onfocus ?? onFocusLegacy);
|
|
75
|
-
const onFocusout = $derived(onfocusout ?? onFocusoutLegacy);
|
|
76
|
-
const onInput = $derived(oninput ?? onInputLegacy);
|
|
77
|
-
const onKeyDown = $derived(onkeydown ?? onKeyDownLegacy);
|
|
78
|
-
const onPaste = $derived(onpaste ?? onPasteLegacy);
|
|
79
|
-
|
|
80
65
|
/* `for` on a <label> resolves against an element's id, never its name. The label
|
|
81
66
|
was emitted with for={name} while the field itself carried only name={name},
|
|
82
67
|
so the association never completed for any caller. Derive the id from name so
|
|
@@ -131,7 +116,7 @@
|
|
|
131
116
|
|
|
132
117
|
// eslint-disable-next-line no-restricted-syntax
|
|
133
118
|
$effect(() => {
|
|
134
|
-
|
|
119
|
+
onstatechange(validationState);
|
|
135
120
|
});
|
|
136
121
|
|
|
137
122
|
const showErrorMessage = $derived(validationState === 'Invalid');
|
|
@@ -236,7 +221,7 @@
|
|
|
236
221
|
inputElement.value = currentValue;
|
|
237
222
|
}
|
|
238
223
|
value = inputElement.value;
|
|
239
|
-
|
|
224
|
+
oninput?.(inputElement.value, event);
|
|
240
225
|
}
|
|
241
226
|
|
|
242
227
|
/**
|
|
@@ -250,11 +235,11 @@
|
|
|
250
235
|
}
|
|
251
236
|
|
|
252
237
|
// Everything below the tel branch is tel-specific digit normalisation, and
|
|
253
|
-
//
|
|
238
|
+
// onpaste was only ever invoked from inside it — so a non-tel field (notably
|
|
254
239
|
// useTextArea) had no way to observe a paste at all. Hand the event over
|
|
255
240
|
// before that branch and return, leaving tel's behaviour byte-identical.
|
|
256
241
|
if (dataType !== 'tel') {
|
|
257
|
-
|
|
242
|
+
onpaste?.(event);
|
|
258
243
|
return;
|
|
259
244
|
}
|
|
260
245
|
|
|
@@ -288,11 +273,11 @@
|
|
|
288
273
|
);
|
|
289
274
|
// Adding reactivity
|
|
290
275
|
value = finalValue;
|
|
291
|
-
|
|
276
|
+
onpaste?.(event);
|
|
292
277
|
event.preventDefault(); // prevent bubble and let finalValue be entered
|
|
293
278
|
}
|
|
294
279
|
/**
|
|
295
|
-
* if numeric pasted text has length less than max length, bubble to
|
|
280
|
+
* if numeric pasted text has length less than max length, bubble to oninput.
|
|
296
281
|
*/
|
|
297
282
|
}
|
|
298
283
|
}
|
|
@@ -309,8 +294,8 @@
|
|
|
309
294
|
if (validationState === 'InProgress' && value.length > 0) {
|
|
310
295
|
validationState = 'Invalid';
|
|
311
296
|
}
|
|
312
|
-
|
|
313
|
-
|
|
297
|
+
onfocusout?.(event);
|
|
298
|
+
onblur?.(event);
|
|
314
299
|
}
|
|
315
300
|
</script>
|
|
316
301
|
|
|
@@ -340,12 +325,12 @@
|
|
|
340
325
|
aria-invalid={showError && !actionInput ? 'true' : null}
|
|
341
326
|
aria-describedby={describedBy || null}
|
|
342
327
|
required={mandatory || null}
|
|
343
|
-
onfocus
|
|
328
|
+
{onfocus}
|
|
344
329
|
onfocusout={_onFocusOut}
|
|
345
330
|
oninput={handleOnInput}
|
|
346
331
|
onpaste={handleOnPaste}
|
|
347
|
-
onclick
|
|
348
|
-
onkeydown
|
|
332
|
+
{onclick}
|
|
333
|
+
{onkeydown}
|
|
349
334
|
data-pw={testId}
|
|
350
335
|
testID={testId}
|
|
351
336
|
class:action-input={actionInput}
|
|
@@ -378,12 +363,12 @@
|
|
|
378
363
|
aria-invalid={showError && !actionInput ? 'true' : null}
|
|
379
364
|
aria-describedby={describedBy || null}
|
|
380
365
|
required={mandatory || null}
|
|
381
|
-
onfocus
|
|
366
|
+
{onfocus}
|
|
382
367
|
onfocusout={_onFocusOut}
|
|
383
368
|
oninput={handleOnInput}
|
|
384
369
|
onpaste={handleOnPaste}
|
|
385
|
-
onclick
|
|
386
|
-
onkeydown
|
|
370
|
+
{onclick}
|
|
371
|
+
{onkeydown}
|
|
387
372
|
data-pw={testId}
|
|
388
373
|
testID={testId}
|
|
389
374
|
class:action-input={actionInput}
|
|
@@ -406,12 +391,12 @@
|
|
|
406
391
|
class:has-right-icon={hasRightIcon}
|
|
407
392
|
>
|
|
408
393
|
{#if hasLeftIcon}
|
|
409
|
-
{#if
|
|
394
|
+
{#if onlefticonclick}
|
|
410
395
|
<button
|
|
411
396
|
type="button"
|
|
412
397
|
class="input-icon input-icon-left input-icon-button"
|
|
413
398
|
aria-label={leftIconLabel}
|
|
414
|
-
onclick={
|
|
399
|
+
onclick={onlefticonclick}
|
|
415
400
|
>
|
|
416
401
|
{@render leftIcon?.()}
|
|
417
402
|
</button>
|
|
@@ -421,12 +406,12 @@
|
|
|
421
406
|
{/if}
|
|
422
407
|
{@render fieldElement()}
|
|
423
408
|
{#if hasRightIcon}
|
|
424
|
-
{#if
|
|
409
|
+
{#if onrighticonclick}
|
|
425
410
|
<button
|
|
426
411
|
type="button"
|
|
427
412
|
class="input-icon input-icon-right input-icon-button"
|
|
428
413
|
aria-label={rightIconLabel}
|
|
429
|
-
onclick={
|
|
414
|
+
onclick={onrighticonclick}
|
|
430
415
|
>
|
|
431
416
|
{@render rightIcon?.()}
|
|
432
417
|
</button>
|
|
@@ -87,9 +87,9 @@ export type OptionalInputProperties = {
|
|
|
87
87
|
/** Passive/clickable icon rendered inside the field on the trailing edge (e.g. a clear button). */
|
|
88
88
|
rightIcon?: Snippet;
|
|
89
89
|
/** When set, the leftIcon becomes a focusable button invoking this handler. */
|
|
90
|
-
|
|
90
|
+
onlefticonclick?: () => void;
|
|
91
91
|
/** When set, the rightIcon becomes a focusable button invoking this handler. */
|
|
92
|
-
|
|
92
|
+
onrighticonclick?: () => void;
|
|
93
93
|
/** Accessible label for the clickable leftIcon button (defaults to a generic label). */
|
|
94
94
|
leftIconLabel?: string;
|
|
95
95
|
/** Accessible label for the clickable rightIcon button (defaults to a generic label). */
|
|
@@ -100,19 +100,12 @@ export type OptionalInputProperties = {
|
|
|
100
100
|
forceError?: boolean;
|
|
101
101
|
};
|
|
102
102
|
export type InputEventProperties = {
|
|
103
|
-
onInput?: (value: string, event: Event) => void;
|
|
104
103
|
oninput?: (value: string, event: Event) => void;
|
|
105
|
-
onFocus?: (event: FocusEvent) => void;
|
|
106
104
|
onfocus?: (event: FocusEvent) => void;
|
|
107
|
-
onFocusout?: (event: FocusEvent) => void;
|
|
108
105
|
onfocusout?: (event: FocusEvent) => void;
|
|
109
|
-
onBlur?: (event: FocusEvent) => void;
|
|
110
106
|
onblur?: (event: FocusEvent) => void;
|
|
111
|
-
onPaste?: (event: ClipboardEvent) => void;
|
|
112
107
|
onpaste?: (event: ClipboardEvent) => void;
|
|
113
|
-
onClick?: (event: MouseEvent) => void;
|
|
114
108
|
onclick?: (event: MouseEvent) => void;
|
|
115
|
-
|
|
116
|
-
onKeyDown?: (event: KeyboardEvent) => void;
|
|
109
|
+
onstatechange?: (state: ValidationState) => void;
|
|
117
110
|
onkeydown?: (event: KeyboardEvent) => void;
|
|
118
111
|
};
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
|
|
51
51
|
function handleStateChange(state: ValidationState): void {
|
|
52
52
|
validationState = state;
|
|
53
|
-
inputEventProperties?.
|
|
53
|
+
inputEventProperties?.onstatechange?.(state);
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
export function focus() {
|
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
{...inputEventProperties}
|
|
90
90
|
bind:value
|
|
91
91
|
bind:this={inputRef}
|
|
92
|
-
|
|
92
|
+
onstatechange={handleStateChange}
|
|
93
93
|
actionInput={true}
|
|
94
94
|
/>
|
|
95
95
|
</div>
|
|
@@ -59,19 +59,13 @@
|
|
|
59
59
|
hideLegendBelow = 360,
|
|
60
60
|
tooltipPortal = false,
|
|
61
61
|
highlightedIndex = null,
|
|
62
|
-
|
|
63
|
-
onpointclick
|
|
64
|
-
|
|
65
|
-
onpointhover: onpointhoverLegacy,
|
|
66
|
-
onPointHover,
|
|
62
|
+
onchartready,
|
|
63
|
+
onpointclick,
|
|
64
|
+
onpointhover,
|
|
67
65
|
testId,
|
|
68
66
|
classes
|
|
69
67
|
}: LineChartProperties = $props();
|
|
70
68
|
|
|
71
|
-
// Event-casing phase 1: both spellings accepted, the correct one wins.
|
|
72
|
-
const onpointclick = $derived(onPointClick ?? onpointclickLegacy);
|
|
73
|
-
const onpointhover = $derived(onPointHover ?? onpointhoverLegacy);
|
|
74
|
-
|
|
75
69
|
// ── State ──────────────────────────────────────────────────────
|
|
76
70
|
|
|
77
71
|
let containerEl: HTMLDivElement | null = $state(null);
|
|
@@ -127,7 +121,7 @@
|
|
|
127
121
|
}
|
|
128
122
|
};
|
|
129
123
|
|
|
130
|
-
|
|
124
|
+
onchartready?.(api);
|
|
131
125
|
});
|
|
132
126
|
|
|
133
127
|
// ── Layout ─────────────────────────────────────────────────────
|
|
@@ -142,25 +142,15 @@ export type LineChartEventProperties = {
|
|
|
142
142
|
pointIndex: number;
|
|
143
143
|
point: LineChartDataPoint;
|
|
144
144
|
}) => void;
|
|
145
|
-
onPointClick?: (event: {
|
|
146
|
-
seriesIndex: number;
|
|
147
|
-
pointIndex: number;
|
|
148
|
-
point: LineChartDataPoint;
|
|
149
|
-
}) => void;
|
|
150
145
|
onpointhover?: (event: {
|
|
151
146
|
seriesIndex: number;
|
|
152
147
|
pointIndex: number;
|
|
153
148
|
point: LineChartDataPoint;
|
|
154
149
|
} | null) => void;
|
|
155
|
-
onPointHover?: (event: {
|
|
156
|
-
seriesIndex: number;
|
|
157
|
-
pointIndex: number;
|
|
158
|
-
point: LineChartDataPoint;
|
|
159
|
-
} | null) => void;
|
|
160
150
|
/**
|
|
161
151
|
* Called once after the chart mounts, handing back a `ChartHighlightAPI`
|
|
162
152
|
* so an external orchestrator (e.g. voice narration sync) can drive point
|
|
163
153
|
* highlighting without knowledge of the chart's internal state.
|
|
164
154
|
*/
|
|
165
|
-
|
|
155
|
+
onchartready?: (api: ChartHighlightAPI) => void;
|
|
166
156
|
};
|
|
@@ -25,16 +25,11 @@
|
|
|
25
25
|
centerContent,
|
|
26
26
|
rightContent,
|
|
27
27
|
bottomContent,
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
onCenterTextClick,
|
|
34
|
-
onitemClick: onitemClickLegacy,
|
|
35
|
-
onItemClick,
|
|
36
|
-
ontopSectionClick: ontopSectionClickLegacy,
|
|
37
|
-
onTopSectionClick,
|
|
28
|
+
onleftimageclick,
|
|
29
|
+
onrightimageclick,
|
|
30
|
+
oncentertextclick,
|
|
31
|
+
onitemclick,
|
|
32
|
+
ontopsectionclick,
|
|
38
33
|
onkeydown,
|
|
39
34
|
classes,
|
|
40
35
|
transformSvg,
|
|
@@ -43,31 +38,24 @@
|
|
|
43
38
|
id
|
|
44
39
|
}: ListItemProperties = $props();
|
|
45
40
|
|
|
46
|
-
// Event-casing phase 1: both spellings accepted, the correct one wins.
|
|
47
|
-
const oncenterTextClick = $derived(onCenterTextClick ?? oncenterTextClickLegacy);
|
|
48
|
-
const onitemClick = $derived(onItemClick ?? onitemClickLegacy);
|
|
49
|
-
const onleftImageClick = $derived(onLeftImageClick ?? onleftImageClickLegacy);
|
|
50
|
-
const onrightImageClick = $derived(onRightImageClick ?? onrightImageClickLegacy);
|
|
51
|
-
const ontopSectionClick = $derived(onTopSectionClick ?? ontopSectionClickLegacy);
|
|
52
|
-
|
|
53
41
|
function handleLeftImageClick(event: MouseEvent): void {
|
|
54
|
-
|
|
42
|
+
onleftimageclick?.(event);
|
|
55
43
|
}
|
|
56
44
|
|
|
57
45
|
function handleRightImageClick(event: MouseEvent): void {
|
|
58
|
-
|
|
46
|
+
onrightimageclick?.(event);
|
|
59
47
|
}
|
|
60
48
|
|
|
61
49
|
function handleCenterTextClick(event: MouseEvent): void {
|
|
62
|
-
|
|
50
|
+
oncentertextclick?.(event);
|
|
63
51
|
}
|
|
64
52
|
|
|
65
53
|
function handleItemClick(event: MouseEvent): void {
|
|
66
|
-
|
|
54
|
+
onitemclick?.(event);
|
|
67
55
|
}
|
|
68
56
|
|
|
69
57
|
function handleTopSectionClick(event: MouseEvent): void {
|
|
70
|
-
|
|
58
|
+
ontopsectionclick?.(event);
|
|
71
59
|
}
|
|
72
60
|
</script>
|
|
73
61
|
|
|
@@ -32,15 +32,10 @@ export type ListItemProperties = ListItemEventProperties & {
|
|
|
32
32
|
id?: string;
|
|
33
33
|
};
|
|
34
34
|
export type ListItemEventProperties = {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
onCenterTextClick?: (event: MouseEvent) => void;
|
|
41
|
-
onitemClick?: (event: MouseEvent) => void;
|
|
42
|
-
onItemClick?: (event: MouseEvent) => void;
|
|
43
|
-
ontopSectionClick?: (event: MouseEvent) => void;
|
|
44
|
-
onTopSectionClick?: (event: MouseEvent) => void;
|
|
35
|
+
onleftimageclick?: (event: MouseEvent) => void;
|
|
36
|
+
onrightimageclick?: (event: MouseEvent) => void;
|
|
37
|
+
oncentertextclick?: (event: MouseEvent) => void;
|
|
38
|
+
onitemclick?: (event: MouseEvent) => void;
|
|
39
|
+
ontopsectionclick?: (event: MouseEvent) => void;
|
|
45
40
|
onkeydown?: (event: KeyboardEvent) => void;
|
|
46
41
|
};
|
|
@@ -18,16 +18,10 @@
|
|
|
18
18
|
ariaHidden = true,
|
|
19
19
|
testId,
|
|
20
20
|
classes,
|
|
21
|
-
oncomplete
|
|
22
|
-
|
|
23
|
-
onerror: onerrorLegacy,
|
|
24
|
-
onError
|
|
21
|
+
oncomplete,
|
|
22
|
+
onerror
|
|
25
23
|
}: LottiePlayerProperties = $props();
|
|
26
24
|
|
|
27
|
-
// Event-casing phase 1: both spellings accepted, the correct one wins.
|
|
28
|
-
const oncomplete = $derived(onComplete ?? oncompleteLegacy);
|
|
29
|
-
const onerror = $derived(onError ?? onerrorLegacy);
|
|
30
|
-
|
|
31
25
|
let containerEl: HTMLDivElement | null = $state(null);
|
|
32
26
|
let animationItem: LocalAnimationItem | null = $state(null);
|
|
33
27
|
|
|
@@ -31,8 +31,6 @@ export type OptionalLottiePlayerProperties = {
|
|
|
31
31
|
export type LottiePlayerEventProperties = {
|
|
32
32
|
/** Fired when the animation completes (non-looping). */
|
|
33
33
|
oncomplete?: () => void;
|
|
34
|
-
onComplete?: () => void;
|
|
35
34
|
/** Fired when the animation fails to load. */
|
|
36
35
|
onerror?: () => void;
|
|
37
|
-
onError?: () => void;
|
|
38
36
|
};
|
|
@@ -26,15 +26,11 @@
|
|
|
26
26
|
captionsSrcLang,
|
|
27
27
|
onplay,
|
|
28
28
|
onpause,
|
|
29
|
-
onvolumechange
|
|
30
|
-
onVolumeChange,
|
|
29
|
+
onvolumechange,
|
|
31
30
|
testId,
|
|
32
31
|
classes
|
|
33
32
|
}: MediaPlayerProperties = $props();
|
|
34
33
|
|
|
35
|
-
// Event-casing phase 1: both spellings accepted, the correct one wins.
|
|
36
|
-
const onvolumechange = $derived(onVolumeChange ?? onvolumechangeLegacy);
|
|
37
|
-
|
|
38
34
|
let videoPlayer: HTMLVideoElement | null = $state(null);
|
|
39
35
|
|
|
40
36
|
function togglePlayback(): void {
|