@juspay/svelte-ui-components 4.10.4 → 4.10.5

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.
@@ -1,11 +1,7 @@
1
1
  import { partyOf } from './roles';
2
+ import { prefersReducedMotion } from '../utils';
2
3
  const REVEAL_CHARS_PER_TICK = 2;
3
4
  const REVEAL_INTERVAL_MS = 22;
4
- function prefersReducedMotion() {
5
- return (typeof window !== 'undefined' &&
6
- typeof window.matchMedia === 'function' &&
7
- window.matchMedia('(prefers-reduced-motion: reduce)').matches);
8
- }
9
5
  let idCounter = 0;
10
6
  function defaultId() {
11
7
  if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
@@ -1,5 +1,6 @@
1
1
  <script lang="ts">
2
2
  import { onMount, onDestroy, untrack } from 'svelte';
3
+ import { prefersReducedMotion } from '../utils';
3
4
  import type { TypewriterTextProperties, TypewriterCharacterDelayRange } from './properties';
4
5
 
5
6
  let {
@@ -75,7 +76,34 @@
75
76
  return speed;
76
77
  };
77
78
 
79
+ // Disclose everything still pending at once. The whitespace count has to be rebuilt
80
+ // from the text itself because the per-character path that normally maintains it is
81
+ // skipped entirely, and a later continuation would otherwise resume from a count that
82
+ // never saw the revealed suffix.
83
+ const revealRemainingText = (): void => {
84
+ if (timeoutId !== null) {
85
+ clearTimeout(timeoutId);
86
+ timeoutId = null;
87
+ }
88
+ const hadRemainingText = currentIndex < text.length;
89
+ displayedText = text;
90
+ currentIndex = text.length;
91
+ revealedWordCount = countWhitespace(text);
92
+ if (hadRemainingText) {
93
+ onprogress?.({ index: currentIndex, total: text.length, displayedText });
94
+ }
95
+ };
96
+
78
97
  const typeNextCharacter = (): void => {
98
+ // Typing IS the animation here, so a reduced-motion request has to suppress the
99
+ // reveal itself rather than a transition around it: disclose the text instead.
100
+ // `ChatController` already bypasses its own drain loop on this setting, and the two
101
+ // reveal implementations have to answer it identically — a consumer composing this
102
+ // component through `Chat`'s `messageBody` snippet is running both at once.
103
+ if (prefersReducedMotion()) {
104
+ revealRemainingText();
105
+ return;
106
+ }
79
107
  if (currentIndex < text.length) {
80
108
  const revealedCharacter = text[currentIndex];
81
109
  const revealedCharacterIndex = currentIndex;
@@ -122,6 +150,7 @@
122
150
  if (currentIndex >= previousTextLength) {
123
151
  if (timeoutId !== null) {
124
152
  clearTimeout(timeoutId);
153
+ timeoutId = null;
125
154
  }
126
155
  typeNextCharacter();
127
156
  }
@@ -133,16 +162,7 @@
133
162
  // eslint-disable-next-line no-restricted-syntax
134
163
  $effect(() => {
135
164
  if (!isStreaming && text.length > 0) {
136
- if (timeoutId !== null) {
137
- clearTimeout(timeoutId);
138
- }
139
- const hadRemainingText = currentIndex < text.length;
140
- displayedText = text;
141
- currentIndex = text.length;
142
- revealedWordCount = countWhitespace(text);
143
- if (hadRemainingText) {
144
- onprogress?.({ index: currentIndex, total: text.length, displayedText });
145
- }
165
+ revealRemainingText();
146
166
  }
147
167
  });
148
168
 
package/dist/utils.d.ts CHANGED
@@ -25,6 +25,16 @@ export declare function hsvToHsl(h: number, s: number, v: number): Hsl;
25
25
  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
+ /**
29
+ * Whether the user has asked the OS to minimise animation.
30
+ *
31
+ * Shared rather than per-component: two independent character-reveal
32
+ * implementations ship in this library — `ChatController`'s buffered drain and
33
+ * `TypewriterText`'s typing loop — and a reveal that honours this setting in one
34
+ * but not the other means the same OS preference silences an animation in a chat
35
+ * bubble and leaves it running in the message body rendered inside it.
36
+ */
37
+ export declare function prefersReducedMotion(): boolean;
28
38
  export declare function createDebouncer(delay: number): <T extends unknown[]>(callback: (...args: T) => void, ...args: T) => void;
29
39
  export declare function lockBodyScroll(): void;
30
40
  export declare function unlockBodyScroll(): void;
package/dist/utils.js CHANGED
@@ -282,6 +282,20 @@ export function clampInt(v, min, max) {
282
282
  return Math.max(min, Math.min(max, n));
283
283
  }
284
284
  // ── Misc ────────────────────────────────────────────────────────
285
+ /**
286
+ * Whether the user has asked the OS to minimise animation.
287
+ *
288
+ * Shared rather than per-component: two independent character-reveal
289
+ * implementations ship in this library — `ChatController`'s buffered drain and
290
+ * `TypewriterText`'s typing loop — and a reveal that honours this setting in one
291
+ * but not the other means the same OS preference silences an animation in a chat
292
+ * bubble and leaves it running in the message body rendered inside it.
293
+ */
294
+ export function prefersReducedMotion() {
295
+ return (typeof window !== 'undefined' &&
296
+ typeof window.matchMedia === 'function' &&
297
+ window.matchMedia('(prefers-reduced-motion: reduce)').matches);
298
+ }
285
299
  export function createDebouncer(delay) {
286
300
  let lastCallTime = 0;
287
301
  return function (callback, ...args) {
package/dist-wc/index.js CHANGED
@@ -6125,6 +6125,9 @@ function clampInt(e, t, n) {
6125
6125
  let i = parseInt(e, 10);
6126
6126
  return Number.isNaN(i) ? t : Math.max(t, Math.min(n, i));
6127
6127
  }
6128
+ function prefersReducedMotion() {
6129
+ return typeof window < "u" && typeof window.matchMedia == "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
6130
+ }
6128
6131
  function createDebouncer(e) {
6129
6132
  let t = 0;
6130
6133
  return function(n, ...i) {
@@ -32398,36 +32401,40 @@ function TypewriterText(e, t) {
32398
32401
  index: t,
32399
32402
  wordCount: get(R)
32400
32403
  }) : s() ? re.test(e) && s().digit ? be(s().digit) : G.has(e) && s().whitespace ? be(s().whitespace) : ne.has(e) && s().punctuation ? be(s().punctuation) : s().default ? be(s().default) : i() : i(), Re = () => {
32404
+ get(C) !== null && (clearTimeout(get(C)), set(C, null));
32405
+ let e = get(S) < n().length;
32406
+ set(h, n(), !0), set(S, n().length, !0), set(R, te(n()), !0), e && l()?.({
32407
+ index: get(S),
32408
+ total: n().length,
32409
+ displayedText: get(h)
32410
+ });
32411
+ }, Ue = () => {
32412
+ if (prefersReducedMotion()) {
32413
+ Re();
32414
+ return;
32415
+ }
32401
32416
  if (get(S) < n().length) {
32402
32417
  let e = n()[get(S)], t = get(S);
32403
32418
  G.has(e) && update(R), set(h, n().substring(0, get(S) + 1), !0), update(S), l()?.({
32404
32419
  index: get(S),
32405
32420
  total: n().length,
32406
32421
  displayedText: get(h)
32407
- }), set(C, setTimeout(Re, Me(e, t)), !0);
32422
+ }), set(C, setTimeout(Ue, Me(e, t)), !0);
32408
32423
  }
32409
32424
  };
32410
32425
  user_effect(() => {
32411
32426
  let e = n();
32412
32427
  untrack(() => {
32413
- e.length >= get(k) && e.startsWith(get(h)) || (get(C) !== null && (clearTimeout(get(C)), set(C, null)), set(h, ""), set(S, 0), set(k, 0), set(R, 0)), e.length > 0 && e.length > get(k) && (get(S) >= get(k) && (get(C) !== null && clearTimeout(get(C)), Re()), set(k, e.length, !0));
32428
+ e.length >= get(k) && e.startsWith(get(h)) || (get(C) !== null && (clearTimeout(get(C)), set(C, null)), set(h, ""), set(S, 0), set(k, 0), set(R, 0)), e.length > 0 && e.length > get(k) && (get(S) >= get(k) && (get(C) !== null && (clearTimeout(get(C)), set(C, null)), Ue()), set(k, e.length, !0));
32414
32429
  });
32415
32430
  }), user_effect(() => {
32416
- if (!a() && n().length > 0) {
32417
- get(C) !== null && clearTimeout(get(C));
32418
- let e = get(S) < n().length;
32419
- set(h, n(), !0), set(S, n().length, !0), set(R, te(n()), !0), e && l()?.({
32420
- index: get(S),
32421
- total: n().length,
32422
- displayedText: get(h)
32423
- });
32424
- }
32431
+ !a() && n().length > 0 && Re();
32425
32432
  }), onMount(() => {
32426
- n().length > 0 && (set(k, n().length, !0), Re());
32433
+ n().length > 0 && (set(k, n().length, !0), Ue());
32427
32434
  }), onDestroy(() => {
32428
32435
  get(C) !== null && clearTimeout(get(C));
32429
32436
  });
32430
- var Ue = {
32437
+ var it = {
32431
32438
  get text() {
32432
32439
  return n();
32433
32440
  },
@@ -32488,12 +32495,12 @@ function TypewriterText(e, t) {
32488
32495
  set classes(e) {
32489
32496
  p(e), flushSync();
32490
32497
  }
32491
- }, it = root$12();
32492
- let at;
32493
- var ot = child(it), ct = (e) => {
32498
+ }, at = root$12();
32499
+ let ot;
32500
+ var ct = child(at), lt = (e) => {
32494
32501
  var t = comment();
32495
32502
  html(first_child(t), () => o()(get(h))), append(e, t);
32496
- }, lt = (e) => {
32503
+ }, ut = (e) => {
32497
32504
  var t = comment();
32498
32505
  each(first_child(t), 17, () => get(h).split(""), index, (e, t, n) => {
32499
32506
  var i = comment();
@@ -32502,15 +32509,15 @@ function TypewriterText(e, t) {
32502
32509
  index: n
32503
32510
  })), append(e, i);
32504
32511
  }), append(e, t);
32505
- }, ut = (e) => {
32512
+ }, dt = (e) => {
32506
32513
  var t = text();
32507
32514
  template_effect(() => set_text(t, get(h))), append(e, t);
32508
32515
  };
32509
- return if_block(ot, (e) => {
32510
- typeof o() == "function" ? e(ct) : u() ? e(lt, 1) : e(ut, -1);
32511
- }), reset(it), template_effect(() => {
32512
- at = set_class(it, 1, `typewriter-text ${p() ?? "" ?? ""}`, "svelte-12jnsxo", at, { plain: typeof o() != "function" }), set_attribute(it, "data-pw", typeof f() == "string" ? f() : null), set_attribute(it, "testid", typeof f() == "string" ? f() : null);
32513
- }), append(e, it), pop(Ue);
32516
+ return if_block(ct, (e) => {
32517
+ typeof o() == "function" ? e(lt) : u() ? e(ut, 1) : e(dt, -1);
32518
+ }), reset(at), template_effect(() => {
32519
+ ot = set_class(at, 1, `typewriter-text ${p() ?? "" ?? ""}`, "svelte-12jnsxo", ot, { plain: typeof o() != "function" }), set_attribute(at, "data-pw", typeof f() == "string" ? f() : null), set_attribute(at, "testid", typeof f() == "string" ? f() : null);
32520
+ }), append(e, at), pop(it);
32514
32521
  }
32515
32522
  create_custom_element(TypewriterText, {
32516
32523
  text: {},
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@juspay/svelte-ui-components",
3
- "version": "4.10.4",
3
+ "version": "4.10.5",
4
4
  "description": "A themeable Svelte 5 UI component library with CSS custom property driven styling",
5
5
  "keywords": [
6
6
  "svelte",