@juspay/svelte-ui-components 2.133.0 → 2.134.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 (38) hide show
  1. package/README.md +30 -0
  2. package/dist/Checkbox/Checkbox.svelte +3 -1
  3. package/dist/Checkbox/properties.d.ts +5 -0
  4. package/dist/Draggable/Draggable.svelte +175 -0
  5. package/dist/Draggable/Draggable.svelte.d.ts +4 -0
  6. package/dist/Draggable/properties.d.ts +26 -0
  7. package/dist/Draggable/properties.js +1 -0
  8. package/dist/Gallery/Gallery.svelte +593 -0
  9. package/dist/Gallery/Gallery.svelte.d.ts +4 -0
  10. package/dist/Gallery/properties.d.ts +39 -0
  11. package/dist/Gallery/properties.js +1 -0
  12. package/dist/Input/Input.svelte +17 -4
  13. package/dist/Input/properties.d.ts +6 -0
  14. package/dist/MediaPlayer/MediaPlayer.svelte +277 -0
  15. package/dist/MediaPlayer/MediaPlayer.svelte.d.ts +4 -0
  16. package/dist/MediaPlayer/properties.d.ts +34 -0
  17. package/dist/MediaPlayer/properties.js +1 -0
  18. package/dist/MediaUpload/MediaUpload.svelte +528 -0
  19. package/dist/MediaUpload/MediaUpload.svelte.d.ts +4 -0
  20. package/dist/MediaUpload/properties.d.ts +46 -0
  21. package/dist/MediaUpload/properties.js +1 -0
  22. package/dist/Menu/Menu.svelte +2 -0
  23. package/dist/Menu/properties.d.ts +5 -0
  24. package/dist/Modal/Modal.svelte +17 -3
  25. package/dist/Modal/properties.d.ts +4 -0
  26. package/dist/assets/add.svg +4 -0
  27. package/dist/assets/delete.svg +7 -0
  28. package/dist/assets/edit.svg +4 -0
  29. package/dist/assets/file.svg +4 -0
  30. package/dist/assets/mute.svg +5 -0
  31. package/dist/assets/pause.svg +4 -0
  32. package/dist/assets/play.svg +3 -0
  33. package/dist/assets/volume.svg +5 -0
  34. package/dist/index.d.ts +8 -0
  35. package/dist/index.js +4 -0
  36. package/dist-wc/index.d.ts +1 -0
  37. package/dist-wc/index.js +33018 -0
  38. package/package.json +16 -9
@@ -65,6 +65,12 @@ export type OptionalInputProperties = {
65
65
  */
66
66
  inputMode?: HTMLInputAttributes['inputmode'];
67
67
  name?: string;
68
+ /** Field id, applied to the rendered `<input>`/`<textarea>` so the visible
69
+ * `<label>` can reference it. Wins over the auto-derived id. Omitting it is
70
+ * safe: the fallback appends a per-instance suffix from `$props.id()`, so
71
+ * fields that share a `name` (radio groups, repeated rows) still get unique
72
+ * ids. Note this names the FIELD, not the wrapper `<div>`. */
73
+ id?: string;
68
74
  textTransformers?: TextTransformer[];
69
75
  textViewPresentation?: TextTransformer[];
70
76
  testId?: string;
@@ -0,0 +1,277 @@
1
+ <script lang="ts">
2
+ import Button from '../Button/Button.svelte';
3
+ import Img from '../Img/Img.svelte';
4
+ import playSvg from '../assets/play.svg?raw';
5
+ import pauseSvg from '../assets/pause.svg?raw';
6
+ import volumeSvg from '../assets/volume.svg?raw';
7
+ import muteSvg from '../assets/mute.svg?raw';
8
+ import type { MediaPlayerProperties } from './properties';
9
+
10
+ let {
11
+ src,
12
+ type,
13
+ alt = '',
14
+ autoplay = true,
15
+ loop = false,
16
+ controls = false,
17
+ fallback,
18
+ playing = $bindable(true),
19
+ muted = $bindable(true),
20
+ playIcon,
21
+ pauseIcon,
22
+ muteIcon,
23
+ unmuteIcon,
24
+ captionsSrc,
25
+ captionsLabel,
26
+ captionsSrcLang,
27
+ onplay,
28
+ onpause,
29
+ onvolumechange,
30
+ testId,
31
+ classes
32
+ }: MediaPlayerProperties = $props();
33
+
34
+ let videoPlayer: HTMLVideoElement | null = $state(null);
35
+
36
+ function togglePlayback(): void {
37
+ if (videoPlayer === null) {
38
+ return;
39
+ }
40
+ if (videoPlayer.paused) {
41
+ videoPlayer.play();
42
+ } else {
43
+ videoPlayer.pause();
44
+ }
45
+ }
46
+
47
+ // `playing` is bindable so a host can drive playback externally (e.g. pausing this
48
+ // player when another one starts), but the native onplay/onpause handlers below only
49
+ // ever WRITE to it (video state -> playing). Without this, a host setting playing
50
+ // itself had no effect on the actual video at all. Guarded so it only imperatively
51
+ // calls play()/pause() when the DOM element's real state actually disagrees with
52
+ // `playing` -- the native events settle it back in sync afterwards, so this can't loop.
53
+ // eslint-disable-next-line no-restricted-syntax
54
+ $effect(() => {
55
+ if (videoPlayer === null) {
56
+ return;
57
+ }
58
+ if (playing && videoPlayer.paused) {
59
+ videoPlayer.play();
60
+ } else if (!playing && !videoPlayer.paused) {
61
+ videoPlayer.pause();
62
+ }
63
+ });
64
+
65
+ function toggleMute(): void {
66
+ muted = !muted;
67
+ onvolumechange?.(muted);
68
+ }
69
+
70
+ function handlePlay(event: Event): void {
71
+ playing = true;
72
+ onplay?.(event);
73
+ }
74
+
75
+ function handlePause(event: Event): void {
76
+ playing = false;
77
+ onpause?.(event);
78
+ }
79
+
80
+ function handleVideoKeydown(event: KeyboardEvent): void {
81
+ if (event.key === 'Enter' || event.key === ' ') {
82
+ event.preventDefault();
83
+ togglePlayback();
84
+ }
85
+ }
86
+ </script>
87
+
88
+ <div class="media-player {classes ?? ''}" data-pw={typeof testId === 'string' ? testId : null}>
89
+ {#if type === 'image'}
90
+ <span class="media-image">
91
+ <Img {src} {alt} {fallback} />
92
+ </span>
93
+ {:else}
94
+ <video
95
+ bind:this={videoPlayer}
96
+ bind:muted
97
+ {src}
98
+ class="media"
99
+ {controls}
100
+ {autoplay}
101
+ {loop}
102
+ playsinline
103
+ onplay={handlePlay}
104
+ onpause={handlePause}
105
+ onclick={controls ? null : togglePlayback}
106
+ onkeydown={controls ? null : handleVideoKeydown}
107
+ role={controls ? null : 'button'}
108
+ tabindex={controls ? null : 0}
109
+ aria-label={controls ? null : playing ? 'Pause video' : 'Play video'}
110
+ >
111
+ {#if typeof captionsSrc === 'string' && captionsSrc.length > 0}
112
+ <track
113
+ kind="captions"
114
+ src={captionsSrc}
115
+ label={typeof captionsLabel === 'string' ? captionsLabel : null}
116
+ srclang={typeof captionsSrcLang === 'string' ? captionsSrcLang : null}
117
+ />
118
+ {/if}
119
+ </video>
120
+
121
+ {#if !controls}
122
+ <div class="overlay">
123
+ <div class="center-controls">
124
+ <div class="control center-control">
125
+ <Button onclick={togglePlayback} ariaLabel={playing ? 'Pause video' : 'Play video'}>
126
+ {#if playing}
127
+ {#if typeof pauseIcon === 'function'}
128
+ {@render pauseIcon()}
129
+ {:else}
130
+ <!-- eslint-disable-next-line svelte/no-at-html-tags -->
131
+ {@html pauseSvg}
132
+ {/if}
133
+ {:else if typeof playIcon === 'function'}
134
+ {@render playIcon()}
135
+ {:else}
136
+ <!-- eslint-disable-next-line svelte/no-at-html-tags -->
137
+ {@html playSvg}
138
+ {/if}
139
+ </Button>
140
+ </div>
141
+ </div>
142
+ <div class="bottom-controls">
143
+ <div class="control bottom-control">
144
+ <Button onclick={toggleMute} ariaLabel={muted ? 'Unmute' : 'Mute'}>
145
+ {#if muted}
146
+ {#if typeof muteIcon === 'function'}
147
+ {@render muteIcon()}
148
+ {:else}
149
+ <!-- eslint-disable-next-line svelte/no-at-html-tags -->
150
+ {@html muteSvg}
151
+ {/if}
152
+ {:else if typeof unmuteIcon === 'function'}
153
+ {@render unmuteIcon()}
154
+ {:else}
155
+ <!-- eslint-disable-next-line svelte/no-at-html-tags -->
156
+ {@html volumeSvg}
157
+ {/if}
158
+ </Button>
159
+ </div>
160
+ </div>
161
+ </div>
162
+ {/if}
163
+ {/if}
164
+ </div>
165
+
166
+ <style>
167
+ .media-player {
168
+ box-sizing: border-box;
169
+ display: flex;
170
+ position: relative;
171
+ height: var(--media-player-height, 400px);
172
+ width: var(--media-player-width, fit-content);
173
+ border-radius: var(--media-player-border-radius, 14px);
174
+ overflow: var(--media-player-overflow, hidden);
175
+ background: var(--media-player-background, transparent);
176
+ }
177
+
178
+ .media {
179
+ height: var(--media-player-media-height, 100%);
180
+ width: var(--media-player-media-width, fit-content);
181
+ object-fit: var(--media-player-media-object-fit, contain);
182
+ border-radius: var(--media-player-media-border-radius, inherit);
183
+ display: block;
184
+ }
185
+
186
+ video.media {
187
+ cursor: var(--media-player-media-cursor, pointer);
188
+ }
189
+
190
+ .media-image {
191
+ display: contents;
192
+ --image-height: var(--media-player-media-height, 100%);
193
+ --image-width: var(--media-player-media-width, fit-content);
194
+ --image-object-fit: var(--media-player-media-object-fit, contain);
195
+ --image-border-radius: var(--media-player-media-border-radius, 0px);
196
+ --image-padding: 0px;
197
+ --image-margin: 0px;
198
+ }
199
+
200
+ .overlay {
201
+ position: absolute;
202
+ inset: 0;
203
+ display: flex;
204
+ flex-direction: column;
205
+ justify-content: center;
206
+ align-items: center;
207
+ box-sizing: border-box;
208
+ z-index: var(--media-player-overlay-z-index, 20);
209
+ border-radius: inherit;
210
+ background-color: var(--media-player-overlay-color, transparent);
211
+ transition: var(--media-player-overlay-transition, background-color 0.2s ease);
212
+ --center-controls-visibility: var(--media-player-center-controls-visibility, hidden);
213
+ --bottom-controls-visibility: var(--media-player-bottom-controls-visibility, hidden);
214
+ }
215
+
216
+ /* :focus-within alongside :hover so the overlay controls (play/pause, mute) are
217
+ reachable for keyboard users too -- :hover alone left them visibility:hidden (and
218
+ so out of the tab order) for anyone not using a mouse. */
219
+ .overlay:hover,
220
+ .overlay:focus-within {
221
+ background-color: var(--media-player-overlay-hover-color, #0000004d);
222
+ --center-controls-visibility: visible;
223
+ --bottom-controls-visibility: visible;
224
+ }
225
+
226
+ .center-controls {
227
+ display: flex;
228
+ flex: 1;
229
+ justify-content: center;
230
+ align-items: center;
231
+ visibility: var(--center-controls-visibility);
232
+ }
233
+
234
+ .bottom-controls {
235
+ display: flex;
236
+ width: 100%;
237
+ height: fit-content;
238
+ justify-content: var(--media-player-bottom-controls-justify, flex-end);
239
+ box-sizing: border-box;
240
+ padding: var(--media-player-bottom-controls-padding, 12px);
241
+ visibility: var(--bottom-controls-visibility);
242
+ }
243
+
244
+ .control {
245
+ --button-padding: var(--media-player-control-padding, 0px);
246
+ --button-border: var(--media-player-control-border, none);
247
+ --button-border-radius: var(--media-player-control-border-radius, 50%);
248
+ --button-color: var(--media-player-control-background-color, transparent);
249
+ --button-text-color: var(--media-player-control-color, #ffffff);
250
+ --button-content-gap: 0px;
251
+ --button-hover-color: var(
252
+ --media-player-control-hover-background-color,
253
+ var(--media-player-control-background-color, transparent)
254
+ );
255
+ --button-hover-text-color: var(
256
+ --media-player-control-hover-color,
257
+ var(--media-player-control-color, #ffffff)
258
+ );
259
+ }
260
+
261
+ .center-control {
262
+ --button-width: var(--media-player-center-control-size, 64px);
263
+ --button-height: var(--media-player-center-control-size, 64px);
264
+ }
265
+
266
+ .bottom-control {
267
+ --button-width: var(--media-player-bottom-control-size, 24px);
268
+ --button-height: var(--media-player-bottom-control-size, 24px);
269
+ }
270
+
271
+ .control :global(svg),
272
+ .control :global(img) {
273
+ height: var(--media-player-control-icon-size, 100%);
274
+ width: var(--media-player-control-icon-size, 100%);
275
+ object-fit: contain;
276
+ }
277
+ </style>
@@ -0,0 +1,4 @@
1
+ import type { MediaPlayerProperties } from './properties';
2
+ declare const MediaPlayer: import("svelte").Component<MediaPlayerProperties, {}, "playing" | "muted">;
3
+ type MediaPlayer = ReturnType<typeof MediaPlayer>;
4
+ export default MediaPlayer;
@@ -0,0 +1,34 @@
1
+ import type { Snippet } from 'svelte';
2
+ export type MediaType = 'image' | 'video';
3
+ export type MediaPlayerProperties = MandatoryMediaPlayerProperties & OptionalMediaPlayerProperties & MediaPlayerEventProperties;
4
+ export type MandatoryMediaPlayerProperties = {
5
+ src: string;
6
+ type: MediaType;
7
+ };
8
+ export type OptionalMediaPlayerProperties = {
9
+ alt?: string;
10
+ fallback?: string;
11
+ autoplay?: boolean;
12
+ loop?: boolean;
13
+ controls?: boolean;
14
+ playing?: boolean;
15
+ muted?: boolean;
16
+ playIcon?: Snippet;
17
+ pauseIcon?: Snippet;
18
+ muteIcon?: Snippet;
19
+ unmuteIcon?: Snippet;
20
+ /** URL of a WebVTT captions file. Omit entirely to render no captions track at all
21
+ * (rather than an empty, non-functional one). */
22
+ captionsSrc?: string;
23
+ /** Label shown in the browser's caption/track menu. Only meaningful with captionsSrc. */
24
+ captionsLabel?: string;
25
+ /** BCP 47 language tag for the captions track, e.g. "en". Only meaningful with captionsSrc. */
26
+ captionsSrcLang?: string;
27
+ testId?: string;
28
+ classes?: string;
29
+ };
30
+ export type MediaPlayerEventProperties = {
31
+ onplay?: (event: Event) => void;
32
+ onpause?: (event: Event) => void;
33
+ onvolumechange?: (muted: boolean) => void;
34
+ };
@@ -0,0 +1 @@
1
+ export {};