@juspay/svelte-ui-components 2.62.1 → 2.63.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.
@@ -391,6 +391,14 @@
391
391
  ) {
392
392
  return preset.label === activePresetLabel;
393
393
  }
394
+ // A preset was explicitly chosen this session — match it by label, not by date.
395
+ // Several presets can share a calendar day (e.g. "Today", "Last 30 minutes" and
396
+ // "Last 12 hours" all start today), so same-day matching would light up all of
397
+ // them at once. selectedPresetLabel is cleared on a direct calendar click, so the
398
+ // date-based fallbacks below still drive highlighting for manual selections.
399
+ if (selectedPresetLabel !== null) {
400
+ return preset.label === selectedPresetLabel;
401
+ }
394
402
  if (mode === 'single') {
395
403
  if (draftValue === null) {
396
404
  return false;
@@ -0,0 +1,14 @@
1
+ <!--
2
+ @internal
3
+ Helper component that renders a Svelte snippet into an imperatively-created DOM element via
4
+ mount(). Used by Tooltip's portal mode to project rich `content` snippets into a bubble
5
+ that lives on document.body outside the normal component tree. Not intended for direct
6
+ consumer use.
7
+ -->
8
+ <script lang="ts">
9
+ import type { Snippet } from 'svelte';
10
+
11
+ let { snippet }: { snippet: Snippet } = $props();
12
+ </script>
13
+
14
+ {@render snippet()}
@@ -0,0 +1,7 @@
1
+ import type { Snippet } from 'svelte';
2
+ type $$ComponentProps = {
3
+ snippet: Snippet;
4
+ };
5
+ declare const PortalContentRenderer: import("svelte").Component<$$ComponentProps, {}, "">;
6
+ type PortalContentRenderer = ReturnType<typeof PortalContentRenderer>;
7
+ export default PortalContentRenderer;
@@ -1,5 +1,7 @@
1
1
  <script lang="ts">
2
- import type { TooltipProperties } from './properties';
2
+ import { mount, unmount, onDestroy } from 'svelte';
3
+ import type { TooltipProperties, TooltipPosition } from './properties';
4
+ import PortalContentRenderer from './PortalContentRenderer.svelte';
3
5
 
4
6
  let {
5
7
  text,
@@ -9,32 +11,199 @@
9
11
  classes,
10
12
  children,
11
13
  icon,
12
- content
14
+ content,
15
+ usePortal = false
13
16
  }: TooltipProperties = $props();
14
17
 
15
18
  let visible = $state(false);
16
19
  let delayTimeout = $state<ReturnType<typeof setTimeout> | null>(null);
17
20
 
18
- function showTooltip() {
19
- if (delay > 0) {
20
- delayTimeout = setTimeout(() => {
21
- visible = true;
22
- }, delay);
21
+ /** Reference to the trigger wrapper element, used for `getBoundingClientRect` in portal mode. */
22
+ let containerEl: HTMLDivElement | null = $state(null);
23
+
24
+ /**
25
+ * Imperatively managed portal bubble element.
26
+ * Created in `showTooltip` and removed in `hideTooltip` when `usePortal=true`.
27
+ * All styles are applied inline so the element is not subject to Svelte's CSS scoping.
28
+ */
29
+ let portalBubbleEl: HTMLDivElement | null = null;
30
+
31
+ /**
32
+ * Mounted Svelte component instance used to render the `content` snippet into the
33
+ * portal bubble. Stored so it can be unmounted when the bubble is removed.
34
+ */
35
+ let portalContentMount: Record<string, unknown> | null = null;
36
+
37
+ const computePortalCoords = (
38
+ rect: DOMRect,
39
+ pos: TooltipPosition
40
+ ): { top: number; left: number; transform: string } => {
41
+ const offset = 8; // matches --tooltip-offset default
42
+ if (pos === 'top') {
43
+ return {
44
+ top: rect.top - offset,
45
+ left: rect.left + rect.width / 2,
46
+ transform: 'translate(-50%, -100%)'
47
+ };
48
+ }
49
+ if (pos === 'bottom') {
50
+ return {
51
+ top: rect.bottom + offset,
52
+ left: rect.left + rect.width / 2,
53
+ transform: 'translate(-50%, 0)'
54
+ };
55
+ }
56
+ if (pos === 'left') {
57
+ return {
58
+ top: rect.top + rect.height / 2,
59
+ left: rect.left - offset,
60
+ transform: 'translate(-100%, -50%)'
61
+ };
62
+ }
63
+ // right
64
+ return {
65
+ top: rect.top + rect.height / 2,
66
+ left: rect.right + offset,
67
+ transform: 'translate(0, -50%)'
68
+ };
69
+ };
70
+
71
+ const computeArrowStyle = (pos: TooltipPosition): string => {
72
+ const arrowSize = 5; // matches --tooltip-arrow-size default
73
+ const bg = 'var(--tooltip-arrow-color,var(--tooltip-background,#333333))';
74
+ const t = 'transparent';
75
+ const base = 'position:absolute;width:0;height:0;border-style:solid;';
76
+ if (pos === 'top') {
77
+ return `${base}top:100%;left:50%;transform:translateX(-50%);border-width:${arrowSize}px ${arrowSize}px 0 ${arrowSize}px;border-color:${bg} ${t} ${t} ${t};`;
78
+ }
79
+ if (pos === 'bottom') {
80
+ return `${base}bottom:100%;left:50%;transform:translateX(-50%);border-width:0 ${arrowSize}px ${arrowSize}px ${arrowSize}px;border-color:${t} ${t} ${bg} ${t};`;
81
+ }
82
+ if (pos === 'left') {
83
+ return `${base}top:50%;left:100%;transform:translateY(-50%);border-width:${arrowSize}px 0 ${arrowSize}px ${arrowSize}px;border-color:${t} ${t} ${t} ${bg};`;
84
+ }
85
+ // right
86
+ return `${base}top:50%;right:100%;transform:translateY(-50%);border-width:${arrowSize}px ${arrowSize}px ${arrowSize}px 0;border-color:${t} ${bg} ${t} ${t};`;
87
+ };
88
+
89
+ const createPortalBubble = (rect: DOMRect, pos: TooltipPosition): HTMLDivElement | null => {
90
+ if (typeof document === 'undefined') {
91
+ return null;
92
+ }
93
+ const bubble = document.createElement('div');
94
+ bubble.setAttribute('role', 'tooltip');
95
+
96
+ const coords = computePortalCoords(rect, pos);
97
+ bubble.style.cssText = [
98
+ `position:fixed`,
99
+ `top:${coords.top}px`,
100
+ `left:${coords.left}px`,
101
+ `transform:${coords.transform}`,
102
+ `z-index:var(--tooltip-z-index,1000)`,
103
+ `max-width:var(--tooltip-max-width,200px)`,
104
+ `background:var(--tooltip-background,#333333)`,
105
+ `color:var(--tooltip-color,#ffffff)`,
106
+ `font-size:var(--tooltip-font-size,12px)`,
107
+ `font-weight:var(--tooltip-font-weight,400)`,
108
+ `font-family:var(--tooltip-font-family,inherit)`,
109
+ `padding:var(--tooltip-padding,6px 10px)`,
110
+ `border-radius:var(--tooltip-border-radius,4px)`,
111
+ `border:var(--tooltip-border,none)`,
112
+ `box-shadow:var(--tooltip-box-shadow,0 2px 6px rgba(0,0,0,0.15))`,
113
+ `white-space:normal`,
114
+ `word-wrap:break-word`,
115
+ `pointer-events:none`,
116
+ `transition:opacity var(--tooltip-opacity-duration,0.15s) ease-in-out`
117
+ ].join(';');
118
+
119
+ const arrowEl = document.createElement('div');
120
+ arrowEl.style.cssText = computeArrowStyle(pos);
121
+ bubble.appendChild(arrowEl);
122
+
123
+ // Render rich `content` snippet when provided; fall back to plain text.
124
+ if (typeof content === 'function') {
125
+ const contentContainer = document.createElement('span');
126
+ bubble.appendChild(contentContainer);
127
+ portalContentMount = mount(PortalContentRenderer, {
128
+ target: contentContainer,
129
+ props: { snippet: content }
130
+ });
23
131
  } else {
132
+ const textEl = document.createElement('span');
133
+ textEl.style.cssText = `color:var(--tooltip-color,#ffffff)`;
134
+ textEl.textContent = text;
135
+ bubble.appendChild(textEl);
136
+ }
137
+
138
+ return bubble;
139
+ };
140
+
141
+ const showTooltip = () => {
142
+ // Guard: if a delay timer is already pending, a second showTooltip() call (e.g. rapid
143
+ // mouseenter + focusin) would schedule another timer. Return early so only one timer
144
+ // is ever pending at a time, preventing stale callbacks from re-showing after hide.
145
+ if (delayTimeout !== null) {
146
+ return;
147
+ }
148
+
149
+ const doShow = () => {
150
+ delayTimeout = null;
24
151
  visible = true;
152
+ if (usePortal && containerEl !== null && typeof document !== 'undefined') {
153
+ const rect = containerEl.getBoundingClientRect();
154
+ const pos = position;
155
+ // Guard: only one portal bubble may exist at a time (overlapping events protection).
156
+ if (portalBubbleEl !== null) {
157
+ return;
158
+ }
159
+ portalBubbleEl = createPortalBubble(rect, pos);
160
+ if (portalBubbleEl !== null) {
161
+ document.body.appendChild(portalBubbleEl);
162
+ }
163
+ }
164
+ };
165
+
166
+ if (delay > 0) {
167
+ delayTimeout = setTimeout(doShow, delay);
168
+ } else {
169
+ doShow();
25
170
  }
26
- }
171
+ };
27
172
 
28
- function hideTooltip() {
173
+ const hideTooltip = () => {
29
174
  if (delayTimeout !== null) {
30
175
  clearTimeout(delayTimeout);
31
176
  delayTimeout = null;
32
177
  }
33
178
  visible = false;
34
- }
179
+ if (portalContentMount !== null) {
180
+ unmount(portalContentMount);
181
+ portalContentMount = null;
182
+ }
183
+ if (portalBubbleEl !== null && typeof document !== 'undefined') {
184
+ portalBubbleEl.remove();
185
+ portalBubbleEl = null;
186
+ }
187
+ };
188
+
189
+ // Ensure the portal bubble and any pending delay timer are cleaned up when
190
+ // the component unmounts — prevents orphaned DOM nodes and memory leaks when
191
+ // Tooltip is used in dynamic lists or conditional rendering contexts.
192
+ onDestroy(() => {
193
+ if (delayTimeout !== null) {
194
+ clearTimeout(delayTimeout);
195
+ }
196
+ if (portalContentMount !== null) {
197
+ unmount(portalContentMount);
198
+ }
199
+ if (portalBubbleEl !== null && typeof document !== 'undefined') {
200
+ portalBubbleEl.remove();
201
+ }
202
+ });
35
203
  </script>
36
204
 
37
205
  <div
206
+ bind:this={containerEl}
38
207
  class="tooltip-container {classes ?? ''}"
39
208
  role="none"
40
209
  onmouseenter={showTooltip}
@@ -47,7 +216,7 @@
47
216
  <span class="tooltip-icon" aria-hidden="true">{@render icon()}</span>
48
217
  {/if}
49
218
  {@render children()}
50
- {#if visible}
219
+ {#if visible && !usePortal}
51
220
  <div class="tooltip-bubble {position}" role="tooltip">
52
221
  <div class="tooltip-arrow"></div>
53
222
  {#if typeof content === 'function'}
@@ -13,5 +13,23 @@ export type OptionalTooltipProperties = {
13
13
  icon?: Snippet;
14
14
  /** Snippet rendered as the bubble body. When provided, replaces the plain `text` string inside the tooltip bubble. */
15
15
  content?: Snippet;
16
+ /**
17
+ * When true, the tooltip bubble is mounted directly on `document.body` using
18
+ * `position: fixed` coordinates derived from `getBoundingClientRect`. This prevents
19
+ * clipping inside overflow-hidden or stacking-context ancestors (e.g. toolbar items).
20
+ */
21
+ usePortal?: boolean;
16
22
  };
17
23
  export type TooltipProperties = MandatoryTooltipProperties & OptionalTooltipProperties;
24
+ /**
25
+ * Options accepted by the `tooltip` Svelte action.
26
+ * All fields mirror the corresponding Tooltip component props.
27
+ */
28
+ export type TooltipActionOptions = {
29
+ /** Tooltip text shown in the bubble. */
30
+ text: string;
31
+ position?: TooltipPosition;
32
+ delay?: number;
33
+ /** Custom CSS classes forwarded to the bubble element. */
34
+ classes?: string;
35
+ };
@@ -0,0 +1,5 @@
1
+ import type { TooltipActionOptions } from './properties';
2
+ export declare const tooltip: (node: HTMLElement, options: TooltipActionOptions) => {
3
+ update: (nextOptions: TooltipActionOptions) => void;
4
+ destroy: () => void;
5
+ };
@@ -0,0 +1,229 @@
1
+ /**
2
+ * Svelte `use:tooltip` action — renderless alternative to the `<Tooltip>` component.
3
+ *
4
+ * Attaches hover and focus listeners to the host element without injecting any wrapper
5
+ * div, which prevents flex-child sizing breakage inside toolbars and icon rows.
6
+ * The tooltip bubble is mounted directly on `document.body` with `position:fixed`
7
+ * coordinates derived from `getBoundingClientRect`, so it is never clipped by
8
+ * `overflow:hidden` ancestors.
9
+ *
10
+ * Usage:
11
+ * ```svelte
12
+ * <script>
13
+ * import { tooltip } from '@juspay/svelte-ui-components';
14
+ * </script>
15
+ * <button use:tooltip={{ text: 'Save', position: 'top' }}>💾</button>
16
+ * ```
17
+ */
18
+ /** Monotonically-incrementing counter used to generate unique tooltip bubble IDs. */
19
+ let tooltipIdCounter = 0;
20
+ export const tooltip = (node, options) => {
21
+ let currentOptions = { ...options };
22
+ let bubbleEl = null;
23
+ let arrowEl = null;
24
+ let delayTimer = null;
25
+ const bubbleId = `sui-tooltip-${++tooltipIdCounter}`;
26
+ const OFFSET = 8; // px — matches --tooltip-offset default
27
+ const computeCoords = (rect, pos) => {
28
+ const arrowSize = 5; // px — matches --tooltip-arrow-size default
29
+ const bg = 'var(--tooltip-arrow-color,var(--tooltip-background,#333333))';
30
+ const t = 'transparent';
31
+ if (pos === 'top') {
32
+ return {
33
+ top: rect.top - OFFSET,
34
+ left: rect.left + rect.width / 2,
35
+ transform: 'translate(-50%, -100%)',
36
+ arrowTop: '100%',
37
+ arrowLeft: '50%',
38
+ arrowRight: '',
39
+ arrowTransform: 'translateX(-50%)',
40
+ arrowBorderWidth: `${arrowSize}px ${arrowSize}px 0 ${arrowSize}px`,
41
+ arrowBorderColor: `${bg} ${t} ${t} ${t}`
42
+ };
43
+ }
44
+ if (pos === 'bottom') {
45
+ return {
46
+ top: rect.bottom + OFFSET,
47
+ left: rect.left + rect.width / 2,
48
+ transform: 'translate(-50%, 0)',
49
+ arrowTop: `-${arrowSize}px`,
50
+ arrowLeft: '50%',
51
+ arrowRight: '',
52
+ arrowTransform: 'translateX(-50%)',
53
+ arrowBorderWidth: `0 ${arrowSize}px ${arrowSize}px ${arrowSize}px`,
54
+ arrowBorderColor: `${t} ${t} ${bg} ${t}`
55
+ };
56
+ }
57
+ if (pos === 'left') {
58
+ return {
59
+ top: rect.top + rect.height / 2,
60
+ left: rect.left - OFFSET,
61
+ transform: 'translate(-100%, -50%)',
62
+ arrowTop: '50%',
63
+ arrowLeft: '100%',
64
+ arrowRight: '',
65
+ arrowTransform: 'translateY(-50%)',
66
+ arrowBorderWidth: `${arrowSize}px 0 ${arrowSize}px ${arrowSize}px`,
67
+ arrowBorderColor: `${t} ${t} ${t} ${bg}`
68
+ };
69
+ }
70
+ // right
71
+ return {
72
+ top: rect.top + rect.height / 2,
73
+ left: rect.right + OFFSET,
74
+ transform: 'translate(0, -50%)',
75
+ arrowTop: '50%',
76
+ arrowLeft: '',
77
+ arrowRight: `${arrowSize}px`,
78
+ arrowTransform: 'translateY(-50%)',
79
+ arrowBorderWidth: `${arrowSize}px ${arrowSize}px ${arrowSize}px 0`,
80
+ arrowBorderColor: `${t} ${bg} ${t} ${t}`
81
+ };
82
+ };
83
+ /**
84
+ * Build the bubble and arrow elements and attach them to `document.body`.
85
+ * Inline styles are used to keep the action self-contained — no stylesheet injection.
86
+ * Sets `aria-describedby` on the host node to satisfy the ARIA tooltip pattern,
87
+ * which requires a programmatic association between the trigger and the bubble.
88
+ */
89
+ const createBubble = () => {
90
+ if (typeof document === 'undefined') {
91
+ return;
92
+ }
93
+ bubbleEl = document.createElement('div');
94
+ bubbleEl.setAttribute('role', 'tooltip');
95
+ bubbleEl.id = bubbleId;
96
+ node.setAttribute('aria-describedby', bubbleId);
97
+ bubbleEl.style.cssText = [
98
+ 'position:fixed',
99
+ `z-index:var(--tooltip-z-index,1000)`,
100
+ `max-width:var(--tooltip-max-width,200px)`,
101
+ `background:var(--tooltip-background,#333333)`,
102
+ `color:var(--tooltip-color,#ffffff)`,
103
+ `font-size:var(--tooltip-font-size,12px)`,
104
+ `font-weight:var(--tooltip-font-weight,400)`,
105
+ `font-family:var(--tooltip-font-family,inherit)`,
106
+ `padding:var(--tooltip-padding,6px 10px)`,
107
+ `border-radius:var(--tooltip-border-radius,4px)`,
108
+ `border:var(--tooltip-border,none)`,
109
+ `box-shadow:var(--tooltip-box-shadow,0 2px 6px rgba(0,0,0,0.15))`,
110
+ 'white-space:normal',
111
+ 'word-wrap:break-word',
112
+ 'pointer-events:none',
113
+ `transition:opacity var(--tooltip-opacity-duration,0.15s) ease-in-out`
114
+ ].join(';');
115
+ if (typeof currentOptions.classes === 'string' && currentOptions.classes.length > 0) {
116
+ bubbleEl.className = currentOptions.classes;
117
+ }
118
+ arrowEl = document.createElement('div');
119
+ arrowEl.style.cssText = 'position:absolute;width:0;height:0;border-style:solid;';
120
+ const textNode = document.createElement('span');
121
+ textNode.style.cssText = 'color:var(--tooltip-color,#ffffff)';
122
+ textNode.textContent = currentOptions.text;
123
+ bubbleEl.appendChild(arrowEl);
124
+ bubbleEl.appendChild(textNode);
125
+ document.body.appendChild(bubbleEl);
126
+ };
127
+ /**
128
+ * Compute and apply `top`/`left` fixed coordinates plus arrow styles based on the
129
+ * current bounding rect of the host element and the active `position` option.
130
+ */
131
+ const positionBubble = () => {
132
+ if (bubbleEl === null || arrowEl === null) {
133
+ return;
134
+ }
135
+ const rect = node.getBoundingClientRect();
136
+ const pos = currentOptions.position ?? 'top';
137
+ const coords = computeCoords(rect, pos);
138
+ bubbleEl.style.top = `${coords.top}px`;
139
+ bubbleEl.style.left = `${coords.left}px`;
140
+ bubbleEl.style.transform = coords.transform;
141
+ arrowEl.style.top = coords.arrowTop;
142
+ arrowEl.style.left = coords.arrowLeft;
143
+ if (coords.arrowRight !== '') {
144
+ arrowEl.style.right = coords.arrowRight;
145
+ }
146
+ arrowEl.style.transform = coords.arrowTransform;
147
+ arrowEl.style.borderWidth = coords.arrowBorderWidth;
148
+ arrowEl.style.borderColor = coords.arrowBorderColor;
149
+ };
150
+ const show = () => {
151
+ // Guard against overlapping events (e.g. mouseenter + focusin firing simultaneously,
152
+ // or two delayed timers both completing) — only one bubble may exist at a time.
153
+ // Also guard when a delay timer is already pending: a second show() call while the
154
+ // first is waiting would schedule a second timer; clearing it first prevents stale
155
+ // timers from re-opening the tooltip after hide() has already run.
156
+ if (bubbleEl !== null || delayTimer !== null) {
157
+ return;
158
+ }
159
+ const doShow = () => {
160
+ // Re-check after the delay: hide() may have been called while the timer was pending.
161
+ if (bubbleEl !== null) {
162
+ return;
163
+ }
164
+ delayTimer = null;
165
+ createBubble();
166
+ positionBubble();
167
+ };
168
+ const delayMs = currentOptions.delay ?? 0;
169
+ if (delayMs > 0) {
170
+ delayTimer = setTimeout(doShow, delayMs);
171
+ }
172
+ else {
173
+ doShow();
174
+ }
175
+ };
176
+ const hide = () => {
177
+ if (delayTimer !== null) {
178
+ clearTimeout(delayTimer);
179
+ delayTimer = null;
180
+ }
181
+ if (bubbleEl !== null) {
182
+ bubbleEl.remove();
183
+ bubbleEl = null;
184
+ arrowEl = null;
185
+ node.removeAttribute('aria-describedby');
186
+ }
187
+ };
188
+ /**
189
+ * Reposition the bubble when the viewport changes (scroll or resize) so the tooltip
190
+ * stays anchored to the trigger element while it is visible.
191
+ */
192
+ const handleReposition = () => {
193
+ if (bubbleEl !== null) {
194
+ positionBubble();
195
+ }
196
+ };
197
+ node.addEventListener('mouseenter', show);
198
+ node.addEventListener('mouseleave', hide);
199
+ node.addEventListener('focusin', show);
200
+ node.addEventListener('focusout', hide);
201
+ // Guard window access: Svelte actions run after mount (client-side only), but an
202
+ // explicit check keeps the action safe if it is somehow called during SSR.
203
+ const hasWindow = typeof window !== 'undefined';
204
+ if (hasWindow) {
205
+ window.addEventListener('resize', handleReposition);
206
+ window.addEventListener('scroll', handleReposition, true);
207
+ }
208
+ return {
209
+ update(nextOptions) {
210
+ currentOptions = { ...nextOptions };
211
+ // If bubble is currently visible, re-render it with new options.
212
+ if (bubbleEl !== null) {
213
+ hide();
214
+ show();
215
+ }
216
+ },
217
+ destroy() {
218
+ hide();
219
+ node.removeEventListener('mouseenter', show);
220
+ node.removeEventListener('mouseleave', hide);
221
+ node.removeEventListener('focusin', show);
222
+ node.removeEventListener('focusout', hide);
223
+ if (hasWindow) {
224
+ window.removeEventListener('resize', handleReposition);
225
+ window.removeEventListener('scroll', handleReposition, true);
226
+ }
227
+ }
228
+ };
229
+ };
package/dist/index.d.ts CHANGED
@@ -31,6 +31,7 @@ export { default as Tabs } from './Tabs/Tabs.svelte';
31
31
  export { default as Choicebox } from './Choicebox/Choicebox.svelte';
32
32
  export { default as Slider } from './Slider/Slider.svelte';
33
33
  export { default as Tooltip } from './Tooltip/Tooltip.svelte';
34
+ export { tooltip } from './Tooltip/tooltip-action';
34
35
  export { default as Shimmer } from './Shimmer/Shimmer.svelte';
35
36
  export { default as Progress } from './Progress/Progress.svelte';
36
37
  export { default as Pill } from './Pill/Pill.svelte';
package/dist/index.js CHANGED
@@ -31,6 +31,7 @@ export { default as Tabs } from './Tabs/Tabs.svelte';
31
31
  export { default as Choicebox } from './Choicebox/Choicebox.svelte';
32
32
  export { default as Slider } from './Slider/Slider.svelte';
33
33
  export { default as Tooltip } from './Tooltip/Tooltip.svelte';
34
+ export { tooltip } from './Tooltip/tooltip-action';
34
35
  export { default as Shimmer } from './Shimmer/Shimmer.svelte';
35
36
  export { default as Progress } from './Progress/Progress.svelte';
36
37
  export { default as Pill } from './Pill/Pill.svelte';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@juspay/svelte-ui-components",
3
- "version": "2.62.1",
3
+ "version": "2.63.1",
4
4
  "description": "A themeable Svelte 5 UI component library with CSS custom property driven styling",
5
5
  "keywords": [
6
6
  "svelte",