@juspay/svelte-ui-components 2.134.1 → 2.136.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/Chat/Chat.svelte +38 -2
- package/dist/Chat/properties.d.ts +7 -0
- package/dist/ChatMessageList/ChatMessageList.svelte +54 -1
- package/dist/CheckListItem/CheckListItem.svelte +4 -1
- package/dist/ChipInput/ChipInput.svelte +150 -10
- package/dist/ChipInput/properties.d.ts +18 -1
- package/dist/CommandMenu/CommandMenu.svelte +7 -3
- package/dist/EmptyState/EmptyState.svelte +17 -3
- package/dist/Input/Input.svelte +1 -0
- package/dist/ListItem/ListItem.svelte +14 -12
- package/dist/ListItem/properties.d.ts +7 -0
- package/dist/Menu/Menu.svelte +2 -1
- package/dist/Menu/properties.d.ts +2 -0
- package/dist/Modal/Modal.svelte +3 -3
- package/dist/Pill/Pill.svelte +2 -0
- package/dist/Pill/properties.d.ts +1 -0
- package/dist/Sheet/Sheet.svelte +3 -23
- package/dist/StatCard/StatCard.svelte +64 -1
- package/dist/StatCard/properties.d.ts +44 -2
- package/dist/Status/Status.svelte +2 -1
- package/dist/Status/properties.d.ts +10 -0
- package/dist/Stepper/Step.svelte +95 -2
- package/dist/Stepper/Stepper.svelte +52 -7
- package/dist/Stepper/properties.d.ts +34 -1
- package/dist/Table/BuiltinCell.svelte +46 -23
- package/dist/Table/Table.svelte +63 -40
- package/dist/Table/cellData.js +3 -0
- package/dist/Table/properties.d.ts +70 -0
- package/dist/ThinkingIndicator/ThinkingIndicator.svelte +93 -5
- package/dist/ThinkingIndicator/properties.d.ts +7 -3
- package/dist/TypewriterText/TypewriterText.svelte +67 -2
- package/dist/TypewriterText/properties.d.ts +97 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -1
- package/dist/utils.d.ts +2 -0
- package/dist/utils.js +30 -0
- package/dist-wc/index.js +2937 -2658
- package/package.json +1 -1
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { onMount, onDestroy, untrack } from 'svelte';
|
|
3
|
-
import type { TypewriterTextProperties } from './properties';
|
|
3
|
+
import type { TypewriterTextProperties, TypewriterCharacterDelayRange } from './properties';
|
|
4
4
|
|
|
5
5
|
let {
|
|
6
6
|
text,
|
|
7
7
|
speed = 15,
|
|
8
8
|
isStreaming = false,
|
|
9
9
|
renderText,
|
|
10
|
+
variableDelay,
|
|
11
|
+
resolveDelay,
|
|
12
|
+
onProgress,
|
|
13
|
+
renderCharacter,
|
|
10
14
|
testId,
|
|
11
15
|
classes
|
|
12
16
|
}: TypewriterTextProperties = $props();
|
|
@@ -18,11 +22,63 @@
|
|
|
18
22
|
// Where typing left off, so newly streamed-in text continues rather than restarts.
|
|
19
23
|
let previousTextLength = $state(0);
|
|
20
24
|
|
|
25
|
+
// Whitespace characters revealed so far — the state `resolveDelay` reads via
|
|
26
|
+
// `TypewriterDelayContext.wordCount`. Reset alongside the other typing state
|
|
27
|
+
// whenever `text` is replaced rather than continued (see the mount $effect below).
|
|
28
|
+
let revealedWordCount = $state(0);
|
|
29
|
+
|
|
30
|
+
const WHITESPACE_CHARACTERS = new Set([' ', '\n']);
|
|
31
|
+
const PUNCTUATION_CHARACTERS = new Set([',', '.', '?', '!']);
|
|
32
|
+
const DIGIT_PATTERN = /\d/;
|
|
33
|
+
|
|
34
|
+
const randomDelayInRange = (range: TypewriterCharacterDelayRange): number => {
|
|
35
|
+
return range.min + Math.random() * (range.max - range.min);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
// Falls straight through to the flat `speed` — byte-identical to the pre-`variableDelay`
|
|
39
|
+
// behaviour — for any consumer that never sets `variableDelay`/`resolveDelay`, or leaves
|
|
40
|
+
// a class out of `variableDelay`. `resolveDelay`, when set, takes over entirely: it is
|
|
41
|
+
// the more general mechanism (see its doc comment in properties.ts) and is expected to
|
|
42
|
+
// own the full pacing decision rather than compose with `variableDelay`/`speed`.
|
|
43
|
+
const resolveTypingDelay = (character: string, characterIndex: number): number => {
|
|
44
|
+
if (typeof resolveDelay === 'function') {
|
|
45
|
+
return resolveDelay({ character, index: characterIndex, wordCount: revealedWordCount });
|
|
46
|
+
}
|
|
47
|
+
if (!variableDelay) {
|
|
48
|
+
return speed;
|
|
49
|
+
}
|
|
50
|
+
if (DIGIT_PATTERN.test(character) && variableDelay.digit) {
|
|
51
|
+
return randomDelayInRange(variableDelay.digit);
|
|
52
|
+
}
|
|
53
|
+
if (WHITESPACE_CHARACTERS.has(character) && variableDelay.whitespace) {
|
|
54
|
+
return randomDelayInRange(variableDelay.whitespace);
|
|
55
|
+
}
|
|
56
|
+
if (PUNCTUATION_CHARACTERS.has(character) && variableDelay.punctuation) {
|
|
57
|
+
return randomDelayInRange(variableDelay.punctuation);
|
|
58
|
+
}
|
|
59
|
+
if (variableDelay.default) {
|
|
60
|
+
return randomDelayInRange(variableDelay.default);
|
|
61
|
+
}
|
|
62
|
+
return speed;
|
|
63
|
+
};
|
|
64
|
+
|
|
21
65
|
const typeNextCharacter = (): void => {
|
|
22
66
|
if (currentIndex < text.length) {
|
|
67
|
+
const revealedCharacter = text[currentIndex];
|
|
68
|
+
const revealedCharacterIndex = currentIndex;
|
|
69
|
+
// Word count is updated for THIS character before it is used to resolve THIS
|
|
70
|
+
// character's own delay — the ordering `TypewriterDelayContext.wordCount` documents
|
|
71
|
+
// and that a cyclical/positional `resolveDelay` depends on.
|
|
72
|
+
if (WHITESPACE_CHARACTERS.has(revealedCharacter)) {
|
|
73
|
+
revealedWordCount++;
|
|
74
|
+
}
|
|
23
75
|
displayedText = text.substring(0, currentIndex + 1);
|
|
24
76
|
currentIndex++;
|
|
25
|
-
|
|
77
|
+
onProgress?.({ index: currentIndex, total: text.length, displayedText });
|
|
78
|
+
timeoutId = setTimeout(
|
|
79
|
+
typeNextCharacter,
|
|
80
|
+
resolveTypingDelay(revealedCharacter, revealedCharacterIndex)
|
|
81
|
+
);
|
|
26
82
|
}
|
|
27
83
|
};
|
|
28
84
|
|
|
@@ -47,6 +103,7 @@
|
|
|
47
103
|
displayedText = '';
|
|
48
104
|
currentIndex = 0;
|
|
49
105
|
previousTextLength = 0;
|
|
106
|
+
revealedWordCount = 0;
|
|
50
107
|
}
|
|
51
108
|
if (nextText.length > 0 && nextText.length > previousTextLength) {
|
|
52
109
|
if (currentIndex >= previousTextLength) {
|
|
@@ -66,8 +123,12 @@
|
|
|
66
123
|
if (timeoutId !== null) {
|
|
67
124
|
clearTimeout(timeoutId);
|
|
68
125
|
}
|
|
126
|
+
const hadRemainingText = currentIndex < text.length;
|
|
69
127
|
displayedText = text;
|
|
70
128
|
currentIndex = text.length;
|
|
129
|
+
if (hadRemainingText) {
|
|
130
|
+
onProgress?.({ index: currentIndex, total: text.length, displayedText });
|
|
131
|
+
}
|
|
71
132
|
}
|
|
72
133
|
});
|
|
73
134
|
|
|
@@ -94,6 +155,10 @@
|
|
|
94
155
|
{#if typeof renderText === 'function'}
|
|
95
156
|
<!-- eslint-disable-next-line svelte/no-at-html-tags -->
|
|
96
157
|
{@html renderText(displayedText)}
|
|
158
|
+
{:else if renderCharacter}
|
|
159
|
+
{#each displayedText.split('') as character, index (index)}
|
|
160
|
+
{@render renderCharacter({ character, index })}
|
|
161
|
+
{/each}
|
|
97
162
|
{:else}
|
|
98
163
|
{displayedText}
|
|
99
164
|
{/if}
|
|
@@ -1,9 +1,72 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
1
2
|
export type TypewriterTextProperties = OptionalTypewriterTextProperties & MandatoryTypewriterTextProperties;
|
|
2
3
|
export type MandatoryTypewriterTextProperties = {
|
|
3
4
|
text: string;
|
|
4
5
|
};
|
|
6
|
+
/** A random delay in `[min, max]` milliseconds is picked per character in that class. Pass equal `min`/`max` for a fixed delay. */
|
|
7
|
+
export type TypewriterCharacterDelayRange = {
|
|
8
|
+
min: number;
|
|
9
|
+
max: number;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Per-character-class pacing, in place of the flat `speed`. Reach for this when a
|
|
13
|
+
* conversation needs to slow down for numbers (prices, OTPs, phone numbers) or add a
|
|
14
|
+
* beat at punctuation, the way a person reading it aloud would. Any class you omit —
|
|
15
|
+
* including `default` — falls back to `speed` for that character.
|
|
16
|
+
*/
|
|
17
|
+
export type TypewriterVariableDelay = {
|
|
18
|
+
/** Digits (`0`–`9`). */
|
|
19
|
+
digit?: TypewriterCharacterDelayRange;
|
|
20
|
+
/** A space or newline — the natural word-boundary pause. */
|
|
21
|
+
whitespace?: TypewriterCharacterDelayRange;
|
|
22
|
+
/** Sentence punctuation: `,` `.` `?` `!`. */
|
|
23
|
+
punctuation?: TypewriterCharacterDelayRange;
|
|
24
|
+
/** Every other character (letters and anything not covered above). */
|
|
25
|
+
default?: TypewriterCharacterDelayRange;
|
|
26
|
+
};
|
|
27
|
+
export type TypewriterProgress = {
|
|
28
|
+
/** Characters revealed so far. */
|
|
29
|
+
index: number;
|
|
30
|
+
/** Length of `text` at the time of this update — compare against `index` for a percentage. */
|
|
31
|
+
total: number;
|
|
32
|
+
/** The text revealed so far — the same value driving what's on screen. */
|
|
33
|
+
displayedText: string;
|
|
34
|
+
};
|
|
35
|
+
export type TypewriterCharacterContext = {
|
|
36
|
+
/** The character being rendered. */
|
|
37
|
+
character: string;
|
|
38
|
+
/** Its position within the full `text` string. */
|
|
39
|
+
index: number;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Everything `resolveDelay` gets to decide the next character's pacing from — a
|
|
43
|
+
* superset of `TypewriterCharacterContext` because pacing can depend on more than the
|
|
44
|
+
* character alone (see `wordCount`).
|
|
45
|
+
*/
|
|
46
|
+
export type TypewriterDelayContext = TypewriterCharacterContext & {
|
|
47
|
+
/**
|
|
48
|
+
* Whitespace characters (space or newline) revealed so far — INCLUDING this one, if
|
|
49
|
+
* `character` itself is whitespace. The component always updates this count before
|
|
50
|
+
* calling `resolveDelay`, so a cadence that keys off word position (a cyclical
|
|
51
|
+
* acceleration window, slowing down only for the first word of a sentence, etc.) can
|
|
52
|
+
* rely on that ordering instead of inferring it through a side channel like
|
|
53
|
+
* `onProgress`. Counts only whitespace, matching the `whitespace` class in
|
|
54
|
+
* `TypewriterVariableDelay` — it is not a word index in any richer sense.
|
|
55
|
+
*/
|
|
56
|
+
wordCount: number;
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* Computes the delay before the NEXT character types, given the one that was just
|
|
60
|
+
* revealed and enough state (`index`, `wordCount`) to vary that delay with position —
|
|
61
|
+
* not just character class. Reach for this instead of `variableDelay` when the cadence
|
|
62
|
+
* needs to depend on where typing currently is, not only on what the character is: e.g.
|
|
63
|
+
* an accelerating window every N words, or a pause that only applies to the first
|
|
64
|
+
* occurrence of a character class. `variableDelay` stays the right tool for a pure
|
|
65
|
+
* per-class rule with no positional state.
|
|
66
|
+
*/
|
|
67
|
+
export type TypewriterDelayResolver = (context: TypewriterDelayContext) => number;
|
|
5
68
|
export type OptionalTypewriterTextProperties = {
|
|
6
|
-
/** Milliseconds between characters. */
|
|
69
|
+
/** Milliseconds between characters. Ignored per character class covered by `variableDelay`. */
|
|
7
70
|
speed?: number;
|
|
8
71
|
/**
|
|
9
72
|
* While `true`, text revealed so far stays and new text keeps typing as `text` grows.
|
|
@@ -16,6 +79,39 @@ export type OptionalTypewriterTextProperties = {
|
|
|
16
79
|
* text can contain untrusted input. When omitted, the text renders as plain text.
|
|
17
80
|
*/
|
|
18
81
|
renderText?: (text: string) => string;
|
|
82
|
+
/**
|
|
83
|
+
* Opt into per-character-class pacing (digits, whitespace, punctuation, everything
|
|
84
|
+
* else) instead of the flat `speed`. Omit to keep the flat `speed` for every character.
|
|
85
|
+
*/
|
|
86
|
+
variableDelay?: TypewriterVariableDelay;
|
|
87
|
+
/**
|
|
88
|
+
* Opt into a fully custom pacing function, called once per character in place of
|
|
89
|
+
* `variableDelay`/`speed`. Needed when the cadence isn't a pure function of the
|
|
90
|
+
* character's own class — e.g. an accelerating window that recurs every N words and,
|
|
91
|
+
* while active, collapses whitespace/punctuation/default pacing to a single flat
|
|
92
|
+
* range regardless of class, with only digits kept slow throughout. `variableDelay`
|
|
93
|
+
* cannot express that fourth, position-driven case because it re-evaluates from
|
|
94
|
+
* scratch per character with no notion of where typing currently is; `resolveDelay`
|
|
95
|
+
* closes that gap by handing the resolver `index` and `wordCount` alongside the
|
|
96
|
+
* character (see `TypewriterDelayContext` for the ordering guarantee on `wordCount`),
|
|
97
|
+
* so state like a running cycle position can live in the resolver's own closure
|
|
98
|
+
* instead of a side channel like swapping `variableDelay` from inside `onProgress`.
|
|
99
|
+
* Takes priority over `variableDelay` when both are set. Omit to keep
|
|
100
|
+
* `variableDelay`/`speed` resolution exactly as today.
|
|
101
|
+
*/
|
|
102
|
+
resolveDelay?: TypewriterDelayResolver;
|
|
103
|
+
/**
|
|
104
|
+
* Called every time a character is revealed (and once more if `isStreaming` turns
|
|
105
|
+
* `false` while text remains, since the rest appears at once) — scroll a container to
|
|
106
|
+
* follow the reveal, or show how far along it is. Not called when omitted.
|
|
107
|
+
*/
|
|
108
|
+
onProgress?: (progress: TypewriterProgress) => void;
|
|
109
|
+
/**
|
|
110
|
+
* Render each revealed character yourself — highlight a token, wrap a number — instead
|
|
111
|
+
* of the plain text node. Ignored when `renderText` is set, since that renderer already
|
|
112
|
+
* owns the full markup. Falls back to plain text per character when omitted.
|
|
113
|
+
*/
|
|
114
|
+
renderCharacter?: Snippet<[TypewriterCharacterContext]>;
|
|
19
115
|
testId?: string;
|
|
20
116
|
classes?: string;
|
|
21
117
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -120,6 +120,7 @@ export type * from './Table/properties';
|
|
|
120
120
|
export type { NormalizedColumns } from './Table/normalizeColumns';
|
|
121
121
|
export type { SortTableRowsOptions, TableSortType } from './Table/sortEngine';
|
|
122
122
|
export type * from './Stepper/properties';
|
|
123
|
+
export type { Step as StepperStep } from './Stepper/properties';
|
|
123
124
|
export type * from './Toast/properties';
|
|
124
125
|
export type * from './IconStack/properties';
|
|
125
126
|
export type * from './Img/properties';
|
|
@@ -197,5 +198,5 @@ export type * from './MediaPlayer/properties';
|
|
|
197
198
|
export type * from './MediaUpload/properties';
|
|
198
199
|
export type * from './Gallery/properties';
|
|
199
200
|
export { createSoundKit } from './soundKit/soundKit';
|
|
200
|
-
export { validateInput } from './utils';
|
|
201
|
+
export { validateInput, lockBodyScroll, unlockBodyScroll } from './utils';
|
|
201
202
|
export { formatNumberIndian } from './_chart/format';
|
package/dist/index.js
CHANGED
|
@@ -101,5 +101,5 @@ export { ChatController } from './Chat/controller.svelte';
|
|
|
101
101
|
export { partyOf } from './Chat/roles';
|
|
102
102
|
export { SpeechToTextController } from './SpeechToText/controller.svelte';
|
|
103
103
|
export { createSoundKit } from './soundKit/soundKit';
|
|
104
|
-
export { validateInput } from './utils';
|
|
104
|
+
export { validateInput, lockBodyScroll, unlockBodyScroll } from './utils';
|
|
105
105
|
export { formatNumberIndian } from './_chart/format';
|
package/dist/utils.d.ts
CHANGED
|
@@ -26,3 +26,5 @@ export declare function hslToHsv(hDeg: number, sPct: number, lPct: number): Hsv;
|
|
|
26
26
|
export declare function isValidHex(hex: string): boolean;
|
|
27
27
|
export declare function clampInt(v: string, min: number, max: number): number;
|
|
28
28
|
export declare function createDebouncer(delay: number): <T extends unknown[]>(callback: (...args: T) => void, ...args: T) => void;
|
|
29
|
+
export declare function lockBodyScroll(): void;
|
|
30
|
+
export declare function unlockBodyScroll(): void;
|
package/dist/utils.js
CHANGED
|
@@ -292,3 +292,33 @@ export function createDebouncer(delay) {
|
|
|
292
292
|
}
|
|
293
293
|
};
|
|
294
294
|
}
|
|
295
|
+
/**
|
|
296
|
+
* Body scroll lock, reference counted.
|
|
297
|
+
*
|
|
298
|
+
* Modal, Sheet and CommandMenu each hide body overflow while they are open. Doing
|
|
299
|
+
* that with a bare assignment means the FIRST of them to unmount restores
|
|
300
|
+
* scrolling for all of them, so closing a confirmation dialog inside a still-open
|
|
301
|
+
* modal silently lets the page behind it scroll again. Counting the holders keeps
|
|
302
|
+
* the lock until the last one releases it.
|
|
303
|
+
*
|
|
304
|
+
* Callers must pair every lock with exactly one unlock.
|
|
305
|
+
*/
|
|
306
|
+
let bodyScrollLockCount = 0;
|
|
307
|
+
export function lockBodyScroll() {
|
|
308
|
+
if (typeof document === 'undefined') {
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
if (bodyScrollLockCount === 0) {
|
|
312
|
+
document.body.style.overflow = 'hidden';
|
|
313
|
+
}
|
|
314
|
+
bodyScrollLockCount += 1;
|
|
315
|
+
}
|
|
316
|
+
export function unlockBodyScroll() {
|
|
317
|
+
if (typeof document === 'undefined') {
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
bodyScrollLockCount = Math.max(0, bodyScrollLockCount - 1);
|
|
321
|
+
if (bodyScrollLockCount === 0) {
|
|
322
|
+
document.body.style.overflow = '';
|
|
323
|
+
}
|
|
324
|
+
}
|