@juspay/svelte-ui-components 4.31.3 → 4.32.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.
Files changed (46) hide show
  1. package/dist/Accordion/Accordion.svelte +6 -1
  2. package/dist/Animations/ModalAnimation.svelte +71 -8
  3. package/dist/Animations/OverlayAnimation.svelte +29 -4
  4. package/dist/Animations/tokenizedFly.d.ts +17 -0
  5. package/dist/Animations/tokenizedFly.js +153 -0
  6. package/dist/AreaChart/AreaChart.svelte +7 -5
  7. package/dist/BarChart/BarChart.svelte +2 -1
  8. package/dist/Book/Book.svelte +6 -3
  9. package/dist/ChatBubble/ChatBubble.svelte +18 -3
  10. package/dist/ChatComposer/ChatComposer.svelte +4 -0
  11. package/dist/Checkbox/Checkbox.svelte +15 -3
  12. package/dist/Choicebox/Choicebox.svelte +24 -2
  13. package/dist/Combobox/Combobox.svelte +15 -1
  14. package/dist/CommandMenu/CommandMenu.svelte +72 -2
  15. package/dist/ContextMenu/ContextMenu.svelte +41 -1
  16. package/dist/DualAxisBarChart/DualAxisBarChart.svelte +4 -3
  17. package/dist/FunnelChart/FunnelChart.svelte +5 -4
  18. package/dist/Gallery/Gallery.svelte +53 -1
  19. package/dist/Gallery/properties.d.ts +5 -3
  20. package/dist/Gauge/Gauge.svelte +2 -1
  21. package/dist/LineChart/LineChart.svelte +7 -5
  22. package/dist/MediaPlayer/MediaPlayer.svelte +9 -1
  23. package/dist/MediaPlayer/MediaPlayer.svelte.d.ts +1 -1
  24. package/dist/MediaUpload/MediaUpload.svelte +1 -1
  25. package/dist/Menu/Menu.svelte +38 -1
  26. package/dist/Modal/Modal.svelte +18 -4
  27. package/dist/Pagination/Pagination.svelte +9 -1
  28. package/dist/PieChart/PieChart.svelte +2 -2
  29. package/dist/Radio/Radio.svelte +14 -2
  30. package/dist/RatingGroup/RatingGroup.svelte +9 -0
  31. package/dist/SankeyChart/SankeyChart.svelte +6 -3
  32. package/dist/Select/Select.svelte +26 -4
  33. package/dist/Sheet/Sheet.svelte +34 -2
  34. package/dist/Slider/Slider.svelte +26 -5
  35. package/dist/Snippet/Snippet.svelte +7 -1
  36. package/dist/Table/Table.svelte +10 -2
  37. package/dist/Tabs/Tabs.svelte +27 -4
  38. package/dist/TaskList/TaskList.svelte +10 -2
  39. package/dist/ThemeSwitcher/ThemeSwitcher.svelte +13 -6
  40. package/dist/ThinkingIndicator/ThinkingIndicator.svelte +5 -3
  41. package/dist/Toast/Toast.svelte +216 -116
  42. package/dist/Toggle/Toggle.svelte +8 -4
  43. package/dist/ToolCallLog/ToolCallLog.svelte +10 -2
  44. package/dist/Tooltip/Tooltip.svelte +4 -2
  45. package/dist-wc/index.js +608 -413
  46. package/package.json +1 -1
@@ -1,9 +1,6 @@
1
1
  <script lang="ts">
2
2
  import { untrack } from 'svelte';
3
- import { fly } from 'svelte/transition';
4
- import { prefersReducedMotion } from '../utils';
5
3
  import type { ToastDirection, ToastProperties } from './properties';
6
- import type { FlyAnimationConfig } from '../types';
7
4
  import Img from '../Img/Img.svelte';
8
5
 
9
6
  let {
@@ -28,77 +25,79 @@
28
25
  classes
29
26
  }: ToastProperties = $props();
30
27
 
31
- const animationConfig: FlyAnimationConfig = $derived(getAnimationConfig(overlapPage, direction));
32
-
33
28
  let showToast = $state(true);
34
29
 
35
30
  const rootClass = $derived(
36
31
  ['toast', type ?? '', classes ?? ''].filter((cls) => cls.length > 0).join(' ')
37
32
  );
38
33
 
39
- function hideToast() {
40
- showToast = false;
41
- }
42
-
43
- function handleAnimationEnd() {
44
- ontoasthide?.();
45
- }
46
-
47
- function getAnimationConfig(
48
- overlapPage: boolean,
49
- toastDirection?: ToastDirection
50
- ): FlyAnimationConfig {
51
- let inX: number = 0;
52
- let inY: number = 0;
53
- let outX: number = 0;
54
- let outY: number = 0;
34
+ // Unset `direction` behaves like 'top-to-bottom' -- the same fallthrough the
35
+ // old `getAnimationConfig` switch used (`case 'top-to-bottom': default:`).
36
+ const resolvedDirection: ToastDirection = $derived(direction ?? 'top-to-bottom');
55
37
 
56
- switch (toastDirection) {
38
+ function directionalOffset(dir: ToastDirection, distance: number): { x?: number; y?: number } {
39
+ switch (dir) {
57
40
  case 'left-to-right':
58
- inX = -1 * (inAnimationOffset ?? 500);
59
- outX = -1 * (outAnimationOffset ?? 500);
60
- break;
41
+ return { x: -distance };
61
42
  case 'right-to-left':
62
- inX = inAnimationOffset ?? 500;
63
- outX = outAnimationOffset ?? 500;
64
- break;
43
+ return { x: distance };
65
44
  case 'bottom-to-top':
66
- inY = inAnimationOffset ?? (overlapPage ? 500 : 20);
67
- outY = outAnimationOffset ?? (overlapPage ? 500 : 20);
68
- break;
45
+ return { y: distance };
69
46
  case 'top-to-bottom':
70
47
  default:
71
- inY = -1 * (inAnimationOffset ?? (overlapPage ? 500 : 20));
72
- outY = -1 * (outAnimationOffset ?? (overlapPage ? 100 : 20));
73
- break;
48
+ return { y: -distance };
74
49
  }
50
+ }
75
51
 
76
- // Reduced motion zeroes the OFFSETS as well as the durations, and the offsets
77
- // are the part that matters. `fly` interpolates from x/y to 0, so a duration of
78
- // 0 with x still at 500 paints the toast 500px away on its first frame and then
79
- // snaps -- a stranded frame that reads as a glitch rather than as no animation.
80
- // Zeroing both makes it simply appear in place, which is what the preference
81
- // asks for. A `@media` block cannot reach any of this: these values are consumed
82
- // by `in:fly={...}` / `out:fly={...}`, so the guard has to live here.
83
- if (prefersReducedMotion()) {
84
- return {
85
- in: { x: 0, y: 0, duration: 0 },
86
- out: { x: 0, y: 0, duration: 0 }
87
- };
88
- }
52
+ // `@starting-style` (in the stylesheet below) supplies one shared "hidden"
53
+ // frame that the entrance reads from *and* the exit animates back to --
54
+ // unlike the old `in:fly`/`out:fly`, CSS has no way to give entry and exit
55
+ // independent offsets, since both converge on the same non-`.is-visible`
56
+ // rule. `inAnimationOffset` wins when both are set. When neither is set,
57
+ // this resolves to `{}` and no inline style is emitted at all, so the
58
+ // direction defaults in CSS (themeable via `--distance-overlay`) apply.
59
+ const enterOffset: { x?: number; y?: number } = $derived.by(() => {
60
+ const distance = inAnimationOffset ?? outAnimationOffset;
61
+ return distance == null ? {} : directionalOffset(resolvedDirection, distance);
62
+ });
89
63
 
90
- return {
91
- in: {
92
- x: inX,
93
- y: inY,
94
- duration: inAnimationDuration ?? 400
95
- },
96
- out: {
97
- x: outX,
98
- y: outY,
99
- duration: outAnimationDuration ?? 800
100
- }
101
- };
64
+ // A `0`/`0s` CSS transition-duration never starts a transition, so it never
65
+ // fires `transitionend`, so `ontoasthide` (below) would never fire -- floor
66
+ // at 50ms so the transition always runs. Same reasoning as the reduced-motion
67
+ // guard in the stylesheet, which floors at 0.05s rather than 0s: under heavy
68
+ // main-thread jank a 1ms transition can still get style-recalc-coalesced
69
+ // across a single frame with no observable "before" frame, which drops
70
+ // `transitionend` the same way a literal 0 does. 50ms clears a normal frame
71
+ // budget with margin while staying well under perceptible motion.
72
+ function toDurationStyle(ms?: number | null): string | null {
73
+ return typeof ms === 'number' ? `${Math.max(ms, 50)}ms` : null;
74
+ }
75
+
76
+ const openDurationStyle = $derived(toDurationStyle(inAnimationDuration));
77
+ const closeDurationStyle = $derived(toDurationStyle(outAnimationDuration));
78
+
79
+ function hideToast() {
80
+ showToast = false;
81
+ }
82
+
83
+ function handleTransitionEnd(event: TransitionEvent) {
84
+ // `currentTarget` excludes `transitionend` bubbling up from inside
85
+ // consumer-supplied `bottomContent`; `propertyName` narrows the transition
86
+ // shorthand's three properties (opacity/transform/display) down to one
87
+ // firing; `!showToast` excludes the entrance's own opacity transition.
88
+ //
89
+ // A rapid re-show while this is still closing interrupts the closing
90
+ // transition -- per spec, an interrupted transition never fires its own
91
+ // transitionend, only the one that actually runs to completion does. That
92
+ // is correct here, not a gap: the interrupted instance's closing
93
+ // transitionend was never going to reflect where the toast ends up
94
+ // regardless, and !showToast is read fresh at whichever transition
95
+ // actually completes, against whatever showToast holds at that moment --
96
+ // correct under any reversal ordering, not just the common single-close
97
+ // case this guard was originally written for.
98
+ if (event.target === event.currentTarget && event.propertyName === 'opacity' && !showToast) {
99
+ ontoasthide?.();
100
+ }
102
101
  }
103
102
 
104
103
  // Track `message` and `duration` as reactive dependencies so the timer
@@ -122,65 +121,68 @@
122
121
  });
123
122
  </script>
124
123
 
125
- {#if showToast}
126
- <!-- `showToast` starts `true` (see the `$state(true)` above), so this
127
- `{#if}` is already satisfied on the component's own first render -- a
128
- *local* transition only plays when its enclosing block flips true as a
129
- later reactive update, not when the block is created already-true,
130
- which is what happens every time a caller mounts Toast fresh (e.g.
131
- `{#if visible}<Toast .../>{/if}` in the caller). `in:fly|global` plays
132
- the intro on creation regardless, matching Sheet's panel transition
133
- (Sheet.svelte). `out:fly` needs no such modifier: `hideToast()` always
134
- flips an already-mounted block from true to false, a genuine local
135
- transition that already fires correctly. -->
136
- <div
137
- class={rootClass}
138
- class:no-page-overlap={!overlapPage}
139
- role="alert"
140
- aria-live="assertive"
141
- in:fly|global={animationConfig.in}
142
- out:fly={animationConfig.out}
143
- onoutroend={handleAnimationEnd}
144
- data-pw={testId}
145
- testID={testId}
146
- >
147
- {#if typeof leftIcon === 'string' && leftIcon.length > 0}
148
- <div class="toast-icon-wrapper">
149
- <Img inlineSvg src={leftIcon} alt="" fallback="" />
150
- </div>
151
- {/if}
152
-
153
- <div class="toast-message" data-pw={messageTestId} testID={messageTestId}>
154
- {message}
155
- {#if typeof subtext === 'string' && subtext.length > 0}
156
- <div class="toast-subtext" data-pw={subTextTestId} testID={subTextTestId}>{subtext}</div>
157
- {/if}
158
-
159
- {#if typeof bottomContent === 'function'}
160
- {@render bottomContent()}
161
- {/if}
124
+ <!-- role="alert"/aria-live="assertive" re-announce reliably for the dominant
125
+ usage (a consumer's own {#if} mounts a fresh Toast per notification, a
126
+ fresh node every time, unambiguous to any AT). A single long-lived Toast
127
+ instance reused across separate notifications purely via prop changes --
128
+ relying on this same node's display:none -> flex toggle to register as a
129
+ fresh insertion -- is the one shape this hasn't been verified against on
130
+ real AT (no automated test exercises a screen reader here, before or
131
+ after this file's CSS-native migration). Flagging rather than guessing:
132
+ if that usage shape turns up a real gap, the established fix is toggling
133
+ aria-live off and back on around the reshow to force a re-announce,
134
+ not a change to the CSS transition mechanics above. -->
135
+ <div
136
+ class={rootClass}
137
+ class:is-visible={showToast}
138
+ class:no-page-overlap={!overlapPage}
139
+ data-direction={resolvedDirection}
140
+ role="alert"
141
+ aria-live="assertive"
142
+ style:--toast-open-duration={openDurationStyle}
143
+ style:--toast-close-duration={closeDurationStyle}
144
+ style:--toast-enter-x={enterOffset.x}
145
+ style:--toast-enter-y={enterOffset.y}
146
+ ontransitionend={handleTransitionEnd}
147
+ data-pw={testId}
148
+ testID={testId}
149
+ >
150
+ {#if typeof leftIcon === 'string' && leftIcon.length > 0}
151
+ <div class="toast-icon-wrapper">
152
+ <Img inlineSvg src={leftIcon} alt="" fallback="" />
162
153
  </div>
154
+ {/if}
155
+
156
+ <div class="toast-message" data-pw={messageTestId} testID={messageTestId}>
157
+ {message}
158
+ {#if typeof subtext === 'string' && subtext.length > 0}
159
+ <div class="toast-subtext" data-pw={subTextTestId} testID={subTextTestId}>{subtext}</div>
160
+ {/if}
163
161
 
164
- {#if typeof rightIcon === 'string' && rightIcon.length > 0}
165
- <div
166
- class="close-button"
167
- tabindex="0"
168
- role="button"
169
- onclick={hideToast}
170
- onkeydown={(event) => {
171
- if (event.key === 'Enter' || event.key === ' ') {
172
- event.preventDefault();
173
- hideToast();
174
- }
175
- }}
176
- data-pw={closeIconTestId}
177
- testID={closeIconTestId}
178
- >
179
- <Img inlineSvg src={rightIcon} alt="Close" fallback="" />
180
- </div>
162
+ {#if typeof bottomContent === 'function'}
163
+ {@render bottomContent()}
181
164
  {/if}
182
165
  </div>
183
- {/if}
166
+
167
+ {#if typeof rightIcon === 'string' && rightIcon.length > 0}
168
+ <div
169
+ class="close-button"
170
+ tabindex="0"
171
+ role="button"
172
+ onclick={hideToast}
173
+ onkeydown={(event) => {
174
+ if (event.key === 'Enter' || event.key === ' ') {
175
+ event.preventDefault();
176
+ hideToast();
177
+ }
178
+ }}
179
+ data-pw={closeIconTestId}
180
+ testID={closeIconTestId}
181
+ >
182
+ <Img inlineSvg src={rightIcon} alt="Close" fallback="" />
183
+ </div>
184
+ {/if}
185
+ </div>
184
186
 
185
187
  <style>
186
188
  .toast {
@@ -197,14 +199,12 @@
197
199
  margin: var(--toast-margin, 0px 10px 10px 10px);
198
200
  justify-content: var(--toast-justify-content, space-between);
199
201
  z-index: var(--toast-z-index, 1000);
200
- display: var(--toast-display, flex);
201
202
  position: var(--toast-position, absolute);
202
203
  top: var(--toast-top, 10px);
203
204
  left: var(--toast-left, 0);
204
205
  right: var(--toast-right, 0);
205
206
  bottom: var(--toast-bottom, auto);
206
207
  background-color: var(--toast-background-color, #87ceeb);
207
- opacity: var(--toast-opacity, 1);
208
208
  box-sizing: var(--toast-box-sizing);
209
209
 
210
210
  /* A toast is a transient status overlay, not a click target: it floats
@@ -214,12 +214,112 @@
214
214
  area below, and consumers with actionable bottomContent can opt the
215
215
  whole toast back in via --toast-pointer-events: auto. */
216
216
  pointer-events: var(--toast-pointer-events, none);
217
+
218
+ /* Closed / pre-enter state. `@starting-style` below reuses these same
219
+ values for the entrance's "before" frame, and removing `.is-visible`
220
+ transitions back to these same values for the exit -- one shared
221
+ "hidden" declaration, not independent in/out targets the way
222
+ `in:fly`/`out:fly` configs could be. */
223
+ display: none;
224
+ opacity: 0;
225
+ transform: translate(var(--toast-enter-x, 0px), var(--toast-enter-y, 0px));
226
+
227
+ /* max(50ms, …) rather than trusting the JS-side floor alone (toDurationStyle,
228
+ in the script block): that only clamps the inAnimationDuration/
229
+ outAnimationDuration PROP path. A consumer overriding --toast-close-duration
230
+ directly via CSS -- the whole point of exposing it as a token -- bypasses
231
+ the prop entirely, and a 0s/1ms transition never starts, so it never fires
232
+ transitionend, so ontoasthide never runs. The floor has to live wherever
233
+ the duration is actually consumed, not just where the props feed it. */
234
+ transition:
235
+ opacity max(50ms, var(--toast-close-duration, var(--motion-duration, 0.8s)))
236
+ var(--toast-close-easing, var(--motion-easing, ease-in)),
237
+ transform max(50ms, var(--toast-close-duration, var(--motion-duration, 0.8s)))
238
+ var(--toast-close-easing, var(--motion-easing, ease-in)),
239
+ display max(50ms, var(--toast-close-duration, var(--motion-duration, 0.8s))) allow-discrete;
240
+ }
241
+
242
+ .toast.is-visible {
243
+ display: var(--toast-display, flex);
244
+ opacity: var(--toast-opacity, 1);
245
+ transform: translate(0, 0);
246
+
247
+ /* 400ms matches --duration-slow exactly (DESIGN_PRINCIPLES.md #1's scale),
248
+ so it sits in this chain as the named tier; 800ms (the close side above)
249
+ matches no named tier and skips straight to the root token. */
250
+ /* Same max(50ms, …) floor as the closed-state block below, and for the same
251
+ reason -- a consumer-set --toast-open-duration can bypass the JS-side
252
+ floor on the inAnimationDuration prop just as easily as the close side. */
253
+ transition:
254
+ opacity
255
+ max(50ms, var(--toast-open-duration, var(--duration-slow, var(--motion-duration, 0.4s))))
256
+ var(--toast-open-easing, var(--ease-out, var(--motion-easing, ease-out))),
257
+ transform
258
+ max(50ms, var(--toast-open-duration, var(--duration-slow, var(--motion-duration, 0.4s))))
259
+ var(--toast-open-easing, var(--ease-out, var(--motion-easing, ease-out))),
260
+ display
261
+ max(50ms, var(--toast-open-duration, var(--duration-slow, var(--motion-duration, 0.4s))))
262
+ allow-discrete;
263
+
264
+ @starting-style {
265
+ opacity: 0;
266
+ transform: translate(var(--toast-enter-x, 0px), var(--toast-enter-y, 0px));
267
+ }
217
268
  }
218
269
 
219
270
  .no-page-overlap {
220
271
  position: var(--toast-position, relative);
221
272
  }
222
273
 
274
+ .toast[data-direction='left-to-right'] {
275
+ --toast-enter-x: calc(-1 * var(--distance-overlay, 60px));
276
+ }
277
+ .toast[data-direction='right-to-left'] {
278
+ --toast-enter-x: var(--distance-overlay, 60px);
279
+ }
280
+ .toast[data-direction='bottom-to-top'] {
281
+ --toast-enter-y: var(--distance-overlay, 60px);
282
+ }
283
+ .toast[data-direction='top-to-bottom'] {
284
+ --toast-enter-y: calc(-1 * var(--distance-overlay, 60px));
285
+ }
286
+
287
+ /* Vertical directions travel a shorter, fixed distance in non-overlap mode --
288
+ today's own literal (20px), kept as its own value rather than forced onto
289
+ `--distance-overlay`: that token replaces the old 500px "flying" default,
290
+ and 20px was already reasonable (DESIGN_PRINCIPLES.md #1). Horizontal
291
+ directions never varied with `overlapPage` before this migration (see the
292
+ pre-migration `getAnimationConfig` switch), so they get no non-overlap
293
+ override here either. */
294
+ .toast.no-page-overlap[data-direction='bottom-to-top'] {
295
+ --toast-enter-y: 20px;
296
+ }
297
+ .toast.no-page-overlap[data-direction='top-to-bottom'] {
298
+ --toast-enter-y: -20px;
299
+ }
300
+
301
+ /* Accessibility guard, not a style preference -- `!important` is deliberate.
302
+ It has to outrank both the direction rules above and any per-instance
303
+ inline `--toast-enter-x`/`-y` the component sets from `inAnimationOffset`/
304
+ `outAnimationOffset` above (an inline style otherwise beats any selector in
305
+ this sheet). Duration floors at 0.05s rather than 0s so the
306
+ `transitionend` listener that fires `ontoasthide` still runs -- a `0s`
307
+ transition never starts, so it never ends, and (empirically, under heavy
308
+ main-thread jank) even a 1ms duration can get coalesced across a single
309
+ style recalc with no observable "before" frame, which drops
310
+ `transitionend` the same way. 50ms clears a normal frame budget with
311
+ margin while staying well under perceptible motion. See
312
+ DESIGN_PRINCIPLES.md #1 on matching a guard's specificity to what it has
313
+ to override. */
314
+ @media (prefers-reduced-motion: reduce) {
315
+ .toast,
316
+ .toast.is-visible {
317
+ --toast-enter-x: 0px !important;
318
+ --toast-enter-y: 0px !important;
319
+ transition-duration: 0.05s !important;
320
+ }
321
+ }
322
+
223
323
  .toast-icon-wrapper {
224
324
  display: flex;
225
325
  width: var(--toast-icon-wrapper-width, 20px);
@@ -140,12 +140,14 @@
140
140
  background-color: var(--slider-unchecked-color, #ccc);
141
141
  -webkit-transition: var(
142
142
  --toggle-slider-transition,
143
- all var(--toggle-slider-transition-duration, var(--motion-duration, 0.4s))
143
+ all
144
+ var(--toggle-slider-transition-duration, var(--duration-slow, var(--motion-duration, 0.4s)))
144
145
  var(--toggle-slider-transition-easing, var(--motion-easing, ease))
145
146
  );
146
147
  transition: var(
147
148
  --toggle-slider-transition,
148
- all var(--toggle-slider-transition-duration, var(--motion-duration, 0.4s))
149
+ all
150
+ var(--toggle-slider-transition-duration, var(--duration-slow, var(--motion-duration, 0.4s)))
149
151
  var(--toggle-slider-transition-easing, var(--motion-easing, ease))
150
152
  );
151
153
  }
@@ -161,12 +163,14 @@
161
163
  background-color: var(--toggle-slider-before-background-color, white);
162
164
  -webkit-transition: var(
163
165
  --toggle-slider-transition,
164
- all var(--toggle-slider-transition-duration, var(--motion-duration, 0.4s))
166
+ all
167
+ var(--toggle-slider-transition-duration, var(--duration-slow, var(--motion-duration, 0.4s)))
165
168
  var(--toggle-slider-transition-easing, var(--motion-easing, ease))
166
169
  );
167
170
  transition: var(
168
171
  --toggle-slider-transition,
169
- all var(--toggle-slider-transition-duration, var(--motion-duration, 0.4s))
172
+ all
173
+ var(--toggle-slider-transition-duration, var(--duration-slow, var(--motion-duration, 0.4s)))
170
174
  var(--toggle-slider-transition-easing, var(--motion-easing, ease))
171
175
  );
172
176
  }
@@ -309,7 +309,11 @@
309
309
  max-width: 100%;
310
310
  animation: tool-call-log-fade-up
311
311
  var(--tool-call-log-chip-animation-duration, var(--motion-duration, 320ms))
312
- var(--tool-call-log-ease, var(--motion-easing, cubic-bezier(0.23, 1, 0.32, 1))) both;
312
+ var(
313
+ --tool-call-log-ease,
314
+ var(--ease-smooth-out, var(--motion-easing, cubic-bezier(0.23, 1, 0.32, 1)))
315
+ )
316
+ both;
313
317
  transition:
314
318
  background var(--tool-call-log-chip-transition-duration, var(--motion-duration, 150ms))
315
319
  var(--tool-call-log-chip-transition-easing, var(--motion-easing, ease)),
@@ -425,7 +429,11 @@
425
429
  box-shadow: var(--tool-call-log-popover-shadow, 0 10px 30px rgba(0, 0, 0, 0.12));
426
430
  animation: tool-call-log-fade-up
427
431
  var(--tool-call-log-popover-animation-duration, var(--motion-duration, 200ms))
428
- var(--tool-call-log-ease, var(--motion-easing, cubic-bezier(0.23, 1, 0.32, 1))) both;
432
+ var(
433
+ --tool-call-log-ease,
434
+ var(--ease-smooth-out, var(--motion-easing, cubic-bezier(0.23, 1, 0.32, 1)))
435
+ )
436
+ both;
429
437
  }
430
438
 
431
439
  .popover-detail {
@@ -276,7 +276,7 @@
276
276
  `white-space:normal`,
277
277
  `word-wrap:break-word`,
278
278
  `pointer-events:none`,
279
- `transition:opacity var(--tooltip-opacity-duration,0.15s) ease-in-out`
279
+ `transition:opacity var(--tooltip-opacity-duration,var(--duration-quick,var(--motion-duration,0.15s))) var(--tooltip-opacity-easing,var(--ease-in-out,var(--motion-easing,ease-in-out)))`
280
280
  ].join(';');
281
281
 
282
282
  const arrowEl = document.createElement('div');
@@ -432,7 +432,9 @@
432
432
  word-wrap: break-word;
433
433
  pointer-events: none;
434
434
  opacity: 1;
435
- transition: opacity var(--tooltip-opacity-duration, 0.15s) ease-in-out;
435
+ transition: opacity
436
+ var(--tooltip-opacity-duration, var(--duration-quick, var(--motion-duration, 0.15s)))
437
+ var(--tooltip-opacity-easing, var(--ease-in-out, var(--motion-easing, ease-in-out)));
436
438
  }
437
439
 
438
440
  .tooltip-arrow {