@juspay/svelte-ui-components 2.124.0 → 2.126.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.
Files changed (56) hide show
  1. package/dist/Chat/Chat.svelte +158 -0
  2. package/dist/Chat/Chat.svelte.d.ts +4 -0
  3. package/dist/Chat/controller.svelte.d.ts +24 -0
  4. package/dist/Chat/controller.svelte.js +190 -0
  5. package/dist/Chat/properties.d.ts +51 -0
  6. package/dist/Chat/properties.js +1 -0
  7. package/dist/Chat/roles.d.ts +2 -0
  8. package/dist/Chat/roles.js +3 -0
  9. package/dist/Chat/types.d.ts +45 -0
  10. package/dist/Chat/types.js +1 -0
  11. package/dist/ChatBubble/ChatBubble.svelte +419 -0
  12. package/dist/ChatBubble/ChatBubble.svelte.d.ts +4 -0
  13. package/dist/ChatBubble/properties.d.ts +43 -0
  14. package/dist/ChatBubble/properties.js +1 -0
  15. package/dist/ChatComposer/ChatComposer.svelte +289 -0
  16. package/dist/ChatComposer/ChatComposer.svelte.d.ts +4 -0
  17. package/dist/ChatComposer/properties.d.ts +33 -0
  18. package/dist/ChatComposer/properties.js +1 -0
  19. package/dist/ChatHeader/ChatHeader.svelte +169 -0
  20. package/dist/ChatHeader/ChatHeader.svelte.d.ts +4 -0
  21. package/dist/ChatHeader/properties.d.ts +19 -0
  22. package/dist/ChatHeader/properties.js +1 -0
  23. package/dist/ChatMessage/ChatMessage.svelte +330 -0
  24. package/dist/ChatMessage/ChatMessage.svelte.d.ts +4 -0
  25. package/dist/ChatMessage/properties.d.ts +29 -0
  26. package/dist/ChatMessage/properties.js +1 -0
  27. package/dist/ChatMessageList/ChatMessageList.svelte +181 -0
  28. package/dist/ChatMessageList/ChatMessageList.svelte.d.ts +4 -0
  29. package/dist/ChatMessageList/properties.d.ts +22 -0
  30. package/dist/ChatMessageList/properties.js +1 -0
  31. package/dist/ChatSuggestions/ChatSuggestions.svelte +46 -0
  32. package/dist/ChatSuggestions/ChatSuggestions.svelte.d.ts +4 -0
  33. package/dist/ChatSuggestions/properties.d.ts +16 -0
  34. package/dist/ChatSuggestions/properties.js +1 -0
  35. package/dist/ChatToolStatus/ChatToolStatus.svelte +63 -0
  36. package/dist/ChatToolStatus/ChatToolStatus.svelte.d.ts +4 -0
  37. package/dist/ChatToolStatus/properties.d.ts +10 -0
  38. package/dist/ChatToolStatus/properties.js +1 -0
  39. package/dist/LineChart/LineChart.svelte +36 -15
  40. package/dist/Resizable/Resizable.svelte +304 -0
  41. package/dist/Resizable/Resizable.svelte.d.ts +4 -0
  42. package/dist/Resizable/properties.d.ts +27 -0
  43. package/dist/Resizable/properties.js +1 -0
  44. package/dist/Table/Table.svelte +109 -10
  45. package/dist/Table/properties.d.ts +1 -0
  46. package/dist/assets/attach.svg +3 -0
  47. package/dist/assets/chat.svg +3 -0
  48. package/dist/assets/mic.svg +5 -0
  49. package/dist/assets/retry.svg +4 -0
  50. package/dist/assets/send.svg +4 -0
  51. package/dist/assets/stop.svg +3 -0
  52. package/dist/assets/thumb-down.svg +4 -0
  53. package/dist/assets/thumb-up.svg +4 -0
  54. package/dist/index.d.ts +21 -0
  55. package/dist/index.js +11 -0
  56. package/package.json +1 -1
@@ -0,0 +1,419 @@
1
+ <script lang="ts">
2
+ import { tick } from 'svelte';
3
+ import Button from '../Button/Button.svelte';
4
+ import Resizable from '../Resizable/Resizable.svelte';
5
+ import chatSvg from '../assets/chat.svg?raw';
6
+ import closeSvg from '../assets/close.svg?raw';
7
+ import type { ResizeEdge } from '../Resizable/properties';
8
+ import type { BubbleDrag, ChatBubbleProperties } from './properties';
9
+
10
+ let {
11
+ open = $bindable(false),
12
+ position = 'bottom-right',
13
+ label = 'Open chat',
14
+ closeLabel = 'Close chat',
15
+ icon,
16
+ openIcon,
17
+ children,
18
+ draggable = false,
19
+ dragMode = 'snap',
20
+ dragX = $bindable(0),
21
+ dragY = $bindable(0),
22
+ resizable = false,
23
+ panelWidth = $bindable(380),
24
+ panelHeight = $bindable(600),
25
+ minPanelWidth = 280,
26
+ minPanelHeight = 360,
27
+ expanded = $bindable(false),
28
+ expandedPanelWidth = $bindable(600),
29
+ expandedPanelHeight = $bindable(760),
30
+ onopen,
31
+ onclose,
32
+ ontoggle,
33
+ testId,
34
+ classes
35
+ }: ChatBubbleProperties = $props();
36
+
37
+ const DRAG_THRESHOLD = 4;
38
+
39
+ function handlesFor(vertical: 'top' | 'bottom', side: 'left' | 'right'): ResizeEdge[] {
40
+ if (vertical === 'bottom') {
41
+ return side === 'right' ? ['top', 'left', 'top-left'] : ['top', 'right', 'top-right'];
42
+ }
43
+ return side === 'right'
44
+ ? ['bottom', 'left', 'bottom-left']
45
+ : ['bottom', 'right', 'bottom-right'];
46
+ }
47
+
48
+ let root: HTMLElement | null = $state(null);
49
+ let panel: HTMLElement | null = $state(null);
50
+ let launcher: HTMLElement | null = $state(null);
51
+ let drag = $state<BubbleDrag | null>(null);
52
+ let flipHorizontal: 'left' | 'right' | null = $state(null);
53
+ let flipVertical: 'top' | 'bottom' | null = $state(null);
54
+ let availWidth: number | null = $state(null);
55
+ let availHeight: number | null = $state(null);
56
+ let suppressClick = false;
57
+
58
+ let dragging = $derived(drag !== null && drag.moved);
59
+ let effectiveSide: 'left' | 'right' = $derived(
60
+ flipHorizontal ?? (position.endsWith('right') ? 'right' : 'left')
61
+ );
62
+ let verticalSide: 'top' | 'bottom' = $derived(
63
+ flipVertical ?? (position.startsWith('top') ? 'top' : 'bottom')
64
+ );
65
+ let resizeHandles = $derived(handlesFor(verticalSide, effectiveSide));
66
+
67
+ let liveWidth = $derived(expanded ? expandedPanelWidth : panelWidth);
68
+ let liveHeight = $derived(expanded ? expandedPanelHeight : panelHeight);
69
+
70
+ function setLiveWidth(value: number): void {
71
+ if (expanded) {
72
+ expandedPanelWidth = value;
73
+ } else {
74
+ panelWidth = value;
75
+ }
76
+ }
77
+
78
+ function setLiveHeight(value: number): void {
79
+ if (expanded) {
80
+ expandedPanelHeight = value;
81
+ } else {
82
+ panelHeight = value;
83
+ }
84
+ }
85
+
86
+ function snapMargin(): number {
87
+ if (root === null) {
88
+ return 24;
89
+ }
90
+ const raw = getComputedStyle(root).getPropertyValue('--chat-bubble-offset-x').trim();
91
+ const parsed = Number.parseFloat(raw);
92
+ return Number.isNaN(parsed) ? 24 : parsed;
93
+ }
94
+
95
+ function capFor(
96
+ left: number,
97
+ top: number,
98
+ right: number,
99
+ bottom: number,
100
+ horizontal: 'left' | 'right',
101
+ vertical: 'top' | 'bottom'
102
+ ): void {
103
+ const gap = 16;
104
+ const margin = 8;
105
+ availHeight = Math.max(
106
+ 0,
107
+ vertical === 'bottom' ? top - gap - margin : window.innerHeight - bottom - gap - margin
108
+ );
109
+ availWidth = Math.max(
110
+ 0,
111
+ horizontal === 'right' ? right - margin : window.innerWidth - left - margin
112
+ );
113
+ }
114
+
115
+ function placeAt(left: number, top: number, right: number, bottom: number): void {
116
+ if (typeof window === 'undefined') {
117
+ return;
118
+ }
119
+ const horizontal = (left + right) / 2 < window.innerWidth / 2 ? 'left' : 'right';
120
+ const vertical = (top + bottom) / 2 < window.innerHeight / 2 ? 'top' : 'bottom';
121
+ flipHorizontal = horizontal;
122
+ flipVertical = vertical;
123
+ capFor(left, top, right, bottom, horizontal, vertical);
124
+ }
125
+
126
+ async function setOpen(next: boolean): Promise<void> {
127
+ if (next === open) {
128
+ return;
129
+ }
130
+ if (next && launcher !== null) {
131
+ const rect = launcher.getBoundingClientRect();
132
+ placeAt(rect.left, rect.top, rect.right, rect.bottom);
133
+ }
134
+ open = next;
135
+ ontoggle?.(open);
136
+ if (open) {
137
+ onopen?.();
138
+ await tick();
139
+ panel?.focus();
140
+ } else {
141
+ onclose?.();
142
+ launcher?.querySelector('button')?.focus();
143
+ }
144
+ }
145
+
146
+ function handleLauncherClick(): void {
147
+ if (suppressClick) {
148
+ suppressClick = false;
149
+ return;
150
+ }
151
+ void setOpen(!open);
152
+ }
153
+
154
+ function startBubbleDrag(event: PointerEvent): void {
155
+ if (!draggable || launcher === null) {
156
+ return;
157
+ }
158
+ suppressClick = false;
159
+ const rect = launcher.getBoundingClientRect();
160
+ drag = {
161
+ startX: event.clientX,
162
+ startY: event.clientY,
163
+ baseX: dragX,
164
+ baseY: dragY,
165
+ moved: false,
166
+ left0: rect.left - dragX,
167
+ top0: rect.top - dragY,
168
+ width: rect.width,
169
+ height: rect.height
170
+ };
171
+ }
172
+
173
+ function clampToViewport(
174
+ next: BubbleDrag,
175
+ nextX: number,
176
+ nextY: number
177
+ ): { x: number; y: number } {
178
+ if (typeof window === 'undefined') {
179
+ return { x: nextX, y: nextY };
180
+ }
181
+ let x = nextX;
182
+ let y = nextY;
183
+ const left = next.left0 + nextX;
184
+ const top = next.top0 + nextY;
185
+ if (left < 0) {
186
+ x = -next.left0;
187
+ } else if (left + next.width > window.innerWidth) {
188
+ x = window.innerWidth - next.width - next.left0;
189
+ }
190
+ if (top < 0) {
191
+ y = -next.top0;
192
+ } else if (top + next.height > window.innerHeight) {
193
+ y = window.innerHeight - next.height - next.top0;
194
+ }
195
+ return { x, y };
196
+ }
197
+
198
+ function moveBubbleDrag(event: PointerEvent): void {
199
+ if (drag === null) {
200
+ return;
201
+ }
202
+ const dx = event.clientX - drag.startX;
203
+ const dy = event.clientY - drag.startY;
204
+ if (!drag.moved && Math.hypot(dx, dy) < DRAG_THRESHOLD) {
205
+ return;
206
+ }
207
+ drag.moved = true;
208
+ const clamped = clampToViewport(drag, drag.baseX + dx, drag.baseY + dy);
209
+ dragX = clamped.x;
210
+ dragY = clamped.y;
211
+ if (open && flipHorizontal !== null && flipVertical !== null) {
212
+ const left = drag.left0 + dragX;
213
+ const top = drag.top0 + dragY;
214
+ capFor(left, top, left + drag.width, top + drag.height, flipHorizontal, flipVertical);
215
+ }
216
+ }
217
+
218
+ function endBubbleDrag(): void {
219
+ if (drag === null) {
220
+ return;
221
+ }
222
+ const ended = drag;
223
+ drag = null;
224
+ if (!ended.moved) {
225
+ return;
226
+ }
227
+ suppressClick = true;
228
+ if (typeof window === 'undefined') {
229
+ return;
230
+ }
231
+ if (dragMode === 'snap') {
232
+ const margin = snapMargin();
233
+ const toLeft = ended.left0 + dragX + ended.width / 2 < window.innerWidth / 2;
234
+ dragX = toLeft
235
+ ? margin - ended.left0
236
+ : window.innerWidth - margin - ended.width - ended.left0;
237
+ }
238
+ const left = ended.left0 + dragX;
239
+ const top = ended.top0 + dragY;
240
+ placeAt(left, top, left + ended.width, top + ended.height);
241
+ }
242
+
243
+ function handlePanelKeydown(event: KeyboardEvent): void {
244
+ if (event.key === 'Escape') {
245
+ event.stopPropagation();
246
+ void setOpen(false);
247
+ }
248
+ }
249
+ </script>
250
+
251
+ <svelte:window onpointermove={moveBubbleDrag} onpointerup={endBubbleDrag} />
252
+
253
+ <div
254
+ class="chat-bubble {classes ?? ''}"
255
+ class:is-draggable={draggable}
256
+ class:dragging
257
+ data-position={position}
258
+ data-effective-side={effectiveSide}
259
+ data-effective-vertical={verticalSide}
260
+ data-expanded={expanded}
261
+ data-pw={typeof testId === 'string' ? testId : null}
262
+ testID={typeof testId === 'string' ? testId : null}
263
+ bind:this={root}
264
+ style:transform={draggable ? `translate(${dragX}px, ${dragY}px)` : null}
265
+ >
266
+ {#if open}
267
+ <div
268
+ class="panel-anchor"
269
+ style:--resizable-max-width={availWidth === null ? null : `${availWidth}px`}
270
+ style:--resizable-max-height={availHeight === null ? null : `${availHeight}px`}
271
+ >
272
+ <Resizable
273
+ disabled={!resizable}
274
+ bind:width={() => liveWidth, setLiveWidth}
275
+ bind:height={() => liveHeight, setLiveHeight}
276
+ minWidth={minPanelWidth}
277
+ minHeight={minPanelHeight}
278
+ maxWidth={availWidth ?? Number.POSITIVE_INFINITY}
279
+ maxHeight={availHeight ?? Number.POSITIVE_INFINITY}
280
+ handles={resizeHandles}
281
+ >
282
+ <div
283
+ class="panel"
284
+ role="dialog"
285
+ aria-label={label}
286
+ tabindex="-1"
287
+ bind:this={panel}
288
+ onkeydown={handlePanelKeydown}
289
+ >
290
+ {#if typeof children === 'function'}
291
+ {@render children()}
292
+ {/if}
293
+ </div>
294
+ </Resizable>
295
+ </div>
296
+ {/if}
297
+
298
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
299
+ <div class="launcher" bind:this={launcher} onpointerdown={startBubbleDrag}>
300
+ <Button onclick={handleLauncherClick} ariaLabel={open ? closeLabel : label} ariaExpanded={open}>
301
+ {#if open}
302
+ {#if typeof openIcon === 'function'}
303
+ {@render openIcon()}
304
+ {:else}
305
+ <!-- eslint-disable-next-line svelte/no-at-html-tags -->
306
+ {@html closeSvg}
307
+ {/if}
308
+ {:else if typeof icon === 'function'}
309
+ {@render icon()}
310
+ {:else}
311
+ <!-- eslint-disable-next-line svelte/no-at-html-tags -->
312
+ {@html chatSvg}
313
+ {/if}
314
+ </Button>
315
+ </div>
316
+ </div>
317
+
318
+ <style>
319
+ .chat-bubble {
320
+ position: fixed;
321
+ z-index: var(--chat-bubble-z-index, 1000);
322
+ transition: var(--chat-bubble-snap-transition, transform 0.28s cubic-bezier(0.22, 1, 0.36, 1));
323
+ }
324
+
325
+ .chat-bubble.dragging {
326
+ transition: none;
327
+ }
328
+
329
+ .chat-bubble[data-position='bottom-right'] {
330
+ right: var(--chat-bubble-offset-x, 24px);
331
+ bottom: var(--chat-bubble-offset-y, 24px);
332
+ }
333
+
334
+ .chat-bubble[data-position='bottom-left'] {
335
+ left: var(--chat-bubble-offset-x, 24px);
336
+ bottom: var(--chat-bubble-offset-y, 24px);
337
+ }
338
+
339
+ .chat-bubble[data-position='top-right'] {
340
+ right: var(--chat-bubble-offset-x, 24px);
341
+ top: var(--chat-bubble-offset-y, 24px);
342
+ }
343
+
344
+ .chat-bubble[data-position='top-left'] {
345
+ left: var(--chat-bubble-offset-x, 24px);
346
+ top: var(--chat-bubble-offset-y, 24px);
347
+ }
348
+
349
+ .panel-anchor {
350
+ position: absolute;
351
+ --resizable-handle-color: var(--chat-bubble-resize-handle-color, transparent);
352
+ --resizable-transition: var(
353
+ --chat-bubble-expand-transition,
354
+ width 0.32s cubic-bezier(0.22, 1, 0.36, 1),
355
+ height 0.32s cubic-bezier(0.22, 1, 0.36, 1)
356
+ );
357
+ }
358
+
359
+ .chat-bubble[data-effective-vertical='bottom'] .panel-anchor {
360
+ bottom: calc(100% + var(--chat-bubble-panel-gap, 16px));
361
+ }
362
+
363
+ .chat-bubble[data-effective-vertical='top'] .panel-anchor {
364
+ top: calc(100% + var(--chat-bubble-panel-gap, 16px));
365
+ }
366
+
367
+ .chat-bubble[data-effective-side='right'] .panel-anchor {
368
+ right: 0;
369
+ }
370
+
371
+ .chat-bubble[data-effective-side='left'] .panel-anchor {
372
+ left: 0;
373
+ }
374
+
375
+ .panel {
376
+ box-sizing: border-box;
377
+ width: 100%;
378
+ height: 100%;
379
+ max-width: var(--chat-bubble-panel-max-width, calc(100vw - 32px));
380
+ max-height: var(--chat-bubble-panel-max-height, calc(100dvh - 120px));
381
+ border-radius: var(--chat-bubble-panel-border-radius, 16px);
382
+ overflow: hidden;
383
+ background: var(--chat-bubble-panel-background, #ffffff);
384
+ box-shadow: var(--chat-bubble-panel-box-shadow, 0 16px 48px rgba(0, 0, 0, 0.22));
385
+ outline: none;
386
+ }
387
+
388
+ .launcher {
389
+ --button-width: var(--chat-bubble-size, 56px);
390
+ --button-height: var(--chat-bubble-size, 56px);
391
+ --button-padding: var(--chat-bubble-padding, 16px);
392
+ --button-border-radius: var(--chat-bubble-border-radius, 50%);
393
+ --button-color: var(--chat-bubble-background-color, #18181b);
394
+ --button-text-color: var(--chat-bubble-color, #ffffff);
395
+ --button-content-gap: 0px;
396
+ --button-box-shadow: var(--chat-bubble-box-shadow, 0 8px 24px rgba(0, 0, 0, 0.25));
397
+ --button-hover-color: var(--chat-bubble-hover-background-color, #27272a);
398
+ }
399
+
400
+ .chat-bubble.is-draggable .launcher {
401
+ --cursor: grab;
402
+ touch-action: none;
403
+ }
404
+
405
+ .chat-bubble.is-draggable.dragging .launcher {
406
+ --cursor: grabbing;
407
+ }
408
+
409
+ .launcher :global(svg) {
410
+ height: 100%;
411
+ width: 100%;
412
+ }
413
+
414
+ @media (prefers-reduced-motion: reduce) {
415
+ .chat-bubble {
416
+ transition: none;
417
+ }
418
+ }
419
+ </style>
@@ -0,0 +1,4 @@
1
+ import type { ChatBubbleProperties } from './properties';
2
+ declare const ChatBubble: import("svelte").Component<ChatBubbleProperties, {}, "open" | "dragX" | "dragY" | "panelWidth" | "panelHeight" | "expanded" | "expandedPanelWidth" | "expandedPanelHeight">;
3
+ type ChatBubble = ReturnType<typeof ChatBubble>;
4
+ export default ChatBubble;
@@ -0,0 +1,43 @@
1
+ import type { Snippet } from 'svelte';
2
+ export type ChatBubblePosition = 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
3
+ export type ChatBubbleDragMode = 'snap' | 'free';
4
+ export type BubbleDrag = {
5
+ startX: number;
6
+ startY: number;
7
+ baseX: number;
8
+ baseY: number;
9
+ moved: boolean;
10
+ left0: number;
11
+ top0: number;
12
+ width: number;
13
+ height: number;
14
+ };
15
+ export type ChatBubbleProperties = OptionalChatBubbleProperties & ChatBubbleEventProperties;
16
+ export type OptionalChatBubbleProperties = {
17
+ open?: boolean;
18
+ position?: ChatBubblePosition;
19
+ label?: string;
20
+ closeLabel?: string;
21
+ icon?: Snippet;
22
+ openIcon?: Snippet;
23
+ children?: Snippet;
24
+ draggable?: boolean;
25
+ dragMode?: ChatBubbleDragMode;
26
+ dragX?: number;
27
+ dragY?: number;
28
+ resizable?: boolean;
29
+ panelWidth?: number;
30
+ panelHeight?: number;
31
+ minPanelWidth?: number;
32
+ minPanelHeight?: number;
33
+ expanded?: boolean;
34
+ expandedPanelWidth?: number;
35
+ expandedPanelHeight?: number;
36
+ testId?: string;
37
+ classes?: string;
38
+ };
39
+ export type ChatBubbleEventProperties = {
40
+ onopen?: () => void;
41
+ onclose?: () => void;
42
+ ontoggle?: (open: boolean) => void;
43
+ };
@@ -0,0 +1 @@
1
+ export {};