@juspay/svelte-ui-components 2.124.0 → 2.125.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 (54) 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/assets/attach.svg +3 -0
  45. package/dist/assets/chat.svg +3 -0
  46. package/dist/assets/mic.svg +5 -0
  47. package/dist/assets/retry.svg +4 -0
  48. package/dist/assets/send.svg +4 -0
  49. package/dist/assets/stop.svg +3 -0
  50. package/dist/assets/thumb-down.svg +4 -0
  51. package/dist/assets/thumb-up.svg +4 -0
  52. package/dist/index.d.ts +21 -0
  53. package/dist/index.js +11 -0
  54. package/package.json +1 -1
@@ -0,0 +1,289 @@
1
+ <script lang="ts">
2
+ import Button from '../Button/Button.svelte';
3
+ import Pill from '../Pill/Pill.svelte';
4
+ import sendSvg from '../assets/send.svg?raw';
5
+ import stopSvg from '../assets/stop.svg?raw';
6
+ import micSvg from '../assets/mic.svg?raw';
7
+ import attachSvg from '../assets/attach.svg?raw';
8
+ import type { Action } from 'svelte/action';
9
+ import type { ChatComposerProperties } from './properties';
10
+
11
+ let {
12
+ value = $bindable(''),
13
+ placeholder = '',
14
+ disabled = false,
15
+ submitOnEnter = true,
16
+ maxLength = 0,
17
+ streaming = false,
18
+ recording = false,
19
+ attachments = $bindable([]),
20
+ accept = '',
21
+ multiple = false,
22
+ sendLabel = 'Send message',
23
+ stopLabel = 'Stop generating',
24
+ voiceLabel = 'Voice input',
25
+ attachLabel = 'Attach files',
26
+ sendIcon,
27
+ stopIcon,
28
+ voiceIcon,
29
+ attachIcon,
30
+ leading,
31
+ onsubmit,
32
+ oninput,
33
+ onkeydown,
34
+ onstop,
35
+ onvoice,
36
+ onattach,
37
+ testId,
38
+ classes
39
+ }: ChatComposerProperties = $props();
40
+
41
+ let fileInput: HTMLInputElement | null = $state(null);
42
+
43
+ let showVoice = $derived(typeof onvoice === 'function');
44
+ let showAttach = $derived(typeof onattach === 'function');
45
+ let canSend = $derived(!disabled && (value.trim().length > 0 || attachments.length > 0));
46
+
47
+ function submit(): void {
48
+ if (!canSend) {
49
+ return;
50
+ }
51
+ onsubmit?.(value, attachments);
52
+ value = '';
53
+ attachments = [];
54
+ }
55
+
56
+ function handleKeydown(event: KeyboardEvent): void {
57
+ if (
58
+ submitOnEnter &&
59
+ event.key === 'Enter' &&
60
+ !event.shiftKey &&
61
+ !event.isComposing &&
62
+ !streaming
63
+ ) {
64
+ event.preventDefault();
65
+ submit();
66
+ }
67
+ onkeydown?.(event);
68
+ }
69
+
70
+ function handleInput(event: Event & { currentTarget: HTMLTextAreaElement }): void {
71
+ oninput?.(event.currentTarget.value, event);
72
+ }
73
+
74
+ function handleFiles(event: Event & { currentTarget: HTMLInputElement }): void {
75
+ const picked = Array.from(event.currentTarget.files ?? []);
76
+ if (picked.length > 0) {
77
+ attachments = [...attachments, ...picked];
78
+ onattach?.(picked);
79
+ }
80
+ event.currentTarget.value = '';
81
+ }
82
+
83
+ function removeAttachment(index: number): void {
84
+ attachments = attachments.filter((_, position) => position !== index);
85
+ }
86
+
87
+ const autoGrow: Action<HTMLTextAreaElement, string> = (node) => {
88
+ function resize(): void {
89
+ node.style.height = '0px';
90
+ node.style.height = `${node.scrollHeight}px`;
91
+ }
92
+ resize();
93
+ return { update: resize };
94
+ };
95
+ </script>
96
+
97
+ <div
98
+ class="chat-composer {classes ?? ''}"
99
+ class:disabled
100
+ data-pw={typeof testId === 'string' ? testId : null}
101
+ testID={typeof testId === 'string' ? testId : null}
102
+ >
103
+ {#if attachments.length > 0}
104
+ <div class="attachments">
105
+ {#each attachments as file, index (file.name + index)}
106
+ <Pill text={file.name} dismissible ondismiss={() => removeAttachment(index)} />
107
+ {/each}
108
+ </div>
109
+ {/if}
110
+
111
+ <div class="input-row">
112
+ {#if showAttach}
113
+ <div class="control attach">
114
+ <Button onclick={() => fileInput?.click()} {disabled} ariaLabel={attachLabel}>
115
+ {#if typeof attachIcon === 'function'}
116
+ {@render attachIcon()}
117
+ {:else}
118
+ <!-- eslint-disable-next-line svelte/no-at-html-tags -->
119
+ {@html attachSvg}
120
+ {/if}
121
+ </Button>
122
+ <input
123
+ bind:this={fileInput}
124
+ type="file"
125
+ {accept}
126
+ {multiple}
127
+ class="file-input"
128
+ onchange={handleFiles}
129
+ hidden
130
+ />
131
+ </div>
132
+ {/if}
133
+
134
+ {#if typeof leading === 'function'}
135
+ <div class="leading">{@render leading()}</div>
136
+ {/if}
137
+
138
+ <textarea
139
+ class="input"
140
+ bind:value
141
+ {placeholder}
142
+ {disabled}
143
+ rows="1"
144
+ aria-label={placeholder.length > 0 ? placeholder : 'Message'}
145
+ maxlength={maxLength > 0 ? maxLength : null}
146
+ oninput={handleInput}
147
+ onkeydown={handleKeydown}
148
+ use:autoGrow={value}
149
+ ></textarea>
150
+
151
+ {#if showVoice}
152
+ <div class="control voice" class:recording>
153
+ <Button onclick={() => onvoice?.()} {disabled} ariaLabel={voiceLabel}>
154
+ {#if typeof voiceIcon === 'function'}
155
+ {@render voiceIcon()}
156
+ {:else}
157
+ <!-- eslint-disable-next-line svelte/no-at-html-tags -->
158
+ {@html micSvg}
159
+ {/if}
160
+ </Button>
161
+ </div>
162
+ {/if}
163
+
164
+ {#if streaming}
165
+ <div class="control send stop">
166
+ <Button onclick={() => onstop?.()} ariaLabel={stopLabel}>
167
+ {#if typeof stopIcon === 'function'}
168
+ {@render stopIcon()}
169
+ {:else}
170
+ <!-- eslint-disable-next-line svelte/no-at-html-tags -->
171
+ {@html stopSvg}
172
+ {/if}
173
+ </Button>
174
+ </div>
175
+ {:else}
176
+ <div class="control send">
177
+ <Button onclick={submit} disabled={!canSend} ariaLabel={sendLabel}>
178
+ {#if typeof sendIcon === 'function'}
179
+ {@render sendIcon()}
180
+ {:else}
181
+ <!-- eslint-disable-next-line svelte/no-at-html-tags -->
182
+ {@html sendSvg}
183
+ {/if}
184
+ </Button>
185
+ </div>
186
+ {/if}
187
+ </div>
188
+ </div>
189
+
190
+ <style>
191
+ .chat-composer {
192
+ box-sizing: border-box;
193
+ display: flex;
194
+ flex-direction: column;
195
+ gap: var(--chat-composer-stack-gap, 8px);
196
+ width: var(--chat-composer-width, 100%);
197
+ padding: var(--chat-composer-padding, 8px);
198
+ background: var(--chat-composer-background, #ffffff);
199
+ border: var(--chat-composer-border, 1px solid #e4e4e7);
200
+ border-radius: var(--chat-composer-border-radius, 24px);
201
+ box-shadow: var(--chat-composer-box-shadow, none);
202
+ }
203
+
204
+ .chat-composer.disabled {
205
+ opacity: var(--chat-composer-disabled-opacity, 0.6);
206
+ }
207
+
208
+ .attachments {
209
+ display: flex;
210
+ flex-wrap: wrap;
211
+ gap: var(--chat-composer-attachments-gap, 6px);
212
+ padding: var(--chat-composer-attachments-padding, 2px 4px 0);
213
+ }
214
+
215
+ .input-row {
216
+ display: flex;
217
+ align-items: flex-end;
218
+ gap: var(--chat-composer-gap, 8px);
219
+ }
220
+
221
+ .leading {
222
+ display: flex;
223
+ align-items: center;
224
+ flex-shrink: 0;
225
+ }
226
+
227
+ .input {
228
+ flex: 1;
229
+ box-sizing: border-box;
230
+ resize: none;
231
+ border: none;
232
+ outline: none;
233
+ background: transparent;
234
+ font-family: var(--chat-composer-font-family, inherit);
235
+ font-size: var(--chat-composer-font-size, 0.9375rem);
236
+ line-height: var(--chat-composer-line-height, 1.5);
237
+ color: var(--chat-composer-color, #18181b);
238
+ padding: var(--chat-composer-input-padding, 6px 4px);
239
+ max-height: var(--chat-composer-max-height, 160px);
240
+ overflow-y: auto;
241
+ }
242
+
243
+ .input::placeholder {
244
+ color: var(--chat-composer-placeholder-color, #a1a1aa);
245
+ }
246
+
247
+ .control {
248
+ flex-shrink: 0;
249
+ display: flex;
250
+ }
251
+
252
+ .control :global(svg) {
253
+ height: 100%;
254
+ width: 100%;
255
+ }
256
+
257
+ .attach,
258
+ .voice {
259
+ --button-width: var(--chat-composer-action-size, 36px);
260
+ --button-height: var(--chat-composer-action-size, 36px);
261
+ --button-padding: var(--chat-composer-action-padding, 8px);
262
+ --button-border-radius: var(--chat-composer-action-border-radius, 50%);
263
+ --button-color: var(--chat-composer-action-background-color, transparent);
264
+ --button-text-color: var(--chat-composer-action-color, #52525b);
265
+ --button-content-gap: 0px;
266
+ --button-hover-color: var(--chat-composer-action-hover-background-color, #f4f4f5);
267
+ }
268
+
269
+ .voice.recording {
270
+ --button-color: var(--chat-composer-voice-recording-background-color, #fee2e2);
271
+ --button-text-color: var(--chat-composer-voice-recording-color, #dc2626);
272
+ }
273
+
274
+ .send {
275
+ --button-width: var(--chat-composer-send-size, 40px);
276
+ --button-height: var(--chat-composer-send-size, 40px);
277
+ --button-padding: var(--chat-composer-send-padding, 8px);
278
+ --button-border-radius: var(--chat-composer-send-border-radius, 50%);
279
+ --button-color: var(--chat-composer-send-background-color, #18181b);
280
+ --button-text-color: var(--chat-composer-send-color, #ffffff);
281
+ --button-content-gap: 0px;
282
+ --button-hover-color: var(--chat-composer-send-hover-background-color, #27272a);
283
+ }
284
+
285
+ .send.stop {
286
+ --button-color: var(--chat-composer-stop-background-color, #18181b);
287
+ --button-text-color: var(--chat-composer-stop-color, #ffffff);
288
+ }
289
+ </style>
@@ -0,0 +1,4 @@
1
+ import type { ChatComposerProperties } from './properties';
2
+ declare const ChatComposer: import("svelte").Component<ChatComposerProperties, {}, "value" | "attachments">;
3
+ type ChatComposer = ReturnType<typeof ChatComposer>;
4
+ export default ChatComposer;
@@ -0,0 +1,33 @@
1
+ import type { Snippet } from 'svelte';
2
+ export type ChatComposerProperties = OptionalChatComposerProperties & ChatComposerEventProperties;
3
+ export type OptionalChatComposerProperties = {
4
+ value?: string;
5
+ placeholder?: string;
6
+ disabled?: boolean;
7
+ submitOnEnter?: boolean;
8
+ maxLength?: number;
9
+ streaming?: boolean;
10
+ recording?: boolean;
11
+ attachments?: File[];
12
+ accept?: string;
13
+ multiple?: boolean;
14
+ sendLabel?: string;
15
+ stopLabel?: string;
16
+ voiceLabel?: string;
17
+ attachLabel?: string;
18
+ sendIcon?: Snippet;
19
+ stopIcon?: Snippet;
20
+ voiceIcon?: Snippet;
21
+ attachIcon?: Snippet;
22
+ leading?: Snippet;
23
+ testId?: string;
24
+ classes?: string;
25
+ };
26
+ export type ChatComposerEventProperties = {
27
+ onsubmit?: (value: string, attachments: File[]) => void;
28
+ oninput?: (value: string, event: Event) => void;
29
+ onkeydown?: (event: KeyboardEvent) => void;
30
+ onstop?: () => void;
31
+ onvoice?: () => void;
32
+ onattach?: (files: File[]) => void;
33
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,169 @@
1
+ <script lang="ts">
2
+ import Button from '../Button/Button.svelte';
3
+ import Img from '../Img/Img.svelte';
4
+ import closeSvg from '../assets/close.svg?raw';
5
+ import type { ChatHeaderProperties } from './properties';
6
+
7
+ let {
8
+ title = '',
9
+ subtitle = '',
10
+ image,
11
+ imageAlt = '',
12
+ avatar,
13
+ actions,
14
+ closeIcon,
15
+ closeLabel = 'Close',
16
+ showClose,
17
+ onclose,
18
+ children,
19
+ testId,
20
+ classes
21
+ }: ChatHeaderProperties = $props();
22
+
23
+ let displayClose = $derived(showClose ?? typeof onclose === 'function');
24
+ </script>
25
+
26
+ <header
27
+ class="chat-header {classes ?? ''}"
28
+ data-pw={typeof testId === 'string' ? testId : null}
29
+ testID={typeof testId === 'string' ? testId : null}
30
+ >
31
+ <div class="bar">
32
+ <div class="brand">
33
+ {#if typeof avatar === 'function'}
34
+ <div class="avatar">{@render avatar()}</div>
35
+ {:else if typeof image === 'string' && image.length > 0}
36
+ <span class="image">
37
+ <Img src={image} alt={imageAlt} />
38
+ </span>
39
+ {/if}
40
+ {#if title.length > 0 || subtitle.length > 0}
41
+ <div class="titles">
42
+ {#if title.length > 0}
43
+ <span class="title">{title}</span>
44
+ {/if}
45
+ {#if subtitle.length > 0}
46
+ <span class="subtitle">{subtitle}</span>
47
+ {/if}
48
+ </div>
49
+ {/if}
50
+ </div>
51
+
52
+ <div class="trailing">
53
+ {#if typeof actions === 'function'}
54
+ {@render actions()}
55
+ {/if}
56
+ {#if displayClose}
57
+ <div class="close">
58
+ <Button onclick={() => onclose?.()} ariaLabel={closeLabel}>
59
+ {#if typeof closeIcon === 'function'}
60
+ {@render closeIcon()}
61
+ {:else}
62
+ <!-- eslint-disable-next-line svelte/no-at-html-tags -->
63
+ {@html closeSvg}
64
+ {/if}
65
+ </Button>
66
+ </div>
67
+ {/if}
68
+ </div>
69
+ </div>
70
+
71
+ {#if typeof children === 'function'}
72
+ <div class="extra">{@render children()}</div>
73
+ {/if}
74
+ </header>
75
+
76
+ <style>
77
+ .chat-header {
78
+ box-sizing: border-box;
79
+ display: flex;
80
+ flex-direction: column;
81
+ gap: var(--chat-header-extra-gap, 8px);
82
+ width: var(--chat-header-width, 100%);
83
+ padding: var(--chat-header-padding, 0.75rem 1.5rem);
84
+ background: var(--chat-header-background, transparent);
85
+ border-bottom: var(--chat-header-border-bottom, none);
86
+ }
87
+
88
+ .bar {
89
+ display: flex;
90
+ align-items: center;
91
+ justify-content: space-between;
92
+ gap: var(--chat-header-gap, 12px);
93
+ width: 100%;
94
+ }
95
+
96
+ .extra {
97
+ width: 100%;
98
+ }
99
+
100
+ .brand {
101
+ display: flex;
102
+ align-items: center;
103
+ gap: var(--chat-header-brand-gap, 10px);
104
+ min-width: 0;
105
+ }
106
+
107
+ .avatar {
108
+ display: flex;
109
+ align-items: center;
110
+ justify-content: center;
111
+ flex-shrink: 0;
112
+ }
113
+
114
+ .image {
115
+ display: contents;
116
+ --image-height: var(--chat-header-image-size, 28px);
117
+ --image-width: var(--chat-header-image-size, 28px);
118
+ --image-object-fit: var(--chat-header-image-object-fit, cover);
119
+ --image-border-radius: var(--chat-header-image-border-radius, 50%);
120
+ --image-padding: 0px;
121
+ --image-margin: 0px;
122
+ }
123
+
124
+ .titles {
125
+ display: flex;
126
+ flex-direction: column;
127
+ min-width: 0;
128
+ }
129
+
130
+ .title {
131
+ font-size: var(--chat-header-title-font-size, 0.95rem);
132
+ font-weight: var(--chat-header-title-font-weight, 600);
133
+ color: var(--chat-header-title-color, #18181b);
134
+ white-space: nowrap;
135
+ overflow: hidden;
136
+ text-overflow: ellipsis;
137
+ }
138
+
139
+ .subtitle {
140
+ font-size: var(--chat-header-subtitle-font-size, 0.7rem);
141
+ font-weight: var(--chat-header-subtitle-font-weight, 500);
142
+ color: var(--chat-header-subtitle-color, #71717a);
143
+ text-transform: var(--chat-header-subtitle-text-transform, none);
144
+ letter-spacing: var(--chat-header-subtitle-letter-spacing, normal);
145
+ }
146
+
147
+ .trailing {
148
+ display: flex;
149
+ align-items: center;
150
+ gap: var(--chat-header-trailing-gap, 8px);
151
+ flex-shrink: 0;
152
+ }
153
+
154
+ .close {
155
+ --button-width: var(--chat-header-close-size, 36px);
156
+ --button-height: var(--chat-header-close-size, 36px);
157
+ --button-padding: var(--chat-header-close-padding, 8px);
158
+ --button-border-radius: var(--chat-header-close-border-radius, 50%);
159
+ --button-color: var(--chat-header-close-background-color, transparent);
160
+ --button-text-color: var(--chat-header-close-color, #52525b);
161
+ --button-content-gap: 0px;
162
+ --button-hover-color: var(--chat-header-close-hover-background-color, #f4f4f5);
163
+ }
164
+
165
+ .close :global(svg) {
166
+ height: 100%;
167
+ width: 100%;
168
+ }
169
+ </style>
@@ -0,0 +1,4 @@
1
+ import type { ChatHeaderProperties } from './properties';
2
+ declare const ChatHeader: import("svelte").Component<ChatHeaderProperties, {}, "">;
3
+ type ChatHeader = ReturnType<typeof ChatHeader>;
4
+ export default ChatHeader;
@@ -0,0 +1,19 @@
1
+ import type { Snippet } from 'svelte';
2
+ export type ChatHeaderProperties = OptionalChatHeaderProperties & ChatHeaderEventProperties;
3
+ export type OptionalChatHeaderProperties = {
4
+ title?: string;
5
+ subtitle?: string;
6
+ image?: string;
7
+ imageAlt?: string;
8
+ avatar?: Snippet;
9
+ actions?: Snippet;
10
+ closeIcon?: Snippet;
11
+ closeLabel?: string;
12
+ showClose?: boolean;
13
+ children?: Snippet;
14
+ testId?: string;
15
+ classes?: string;
16
+ };
17
+ export type ChatHeaderEventProperties = {
18
+ onclose?: () => void;
19
+ };
@@ -0,0 +1 @@
1
+ export {};