@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
package/README.md CHANGED
@@ -153,6 +153,36 @@ This library takes a different approach: **components are unstyled by default**
153
153
 
154
154
  ---
155
155
 
156
+ ## Web Components
157
+
158
+ Every component also ships as a real Custom Element (Svelte 5's native `customElement`
159
+ compiler output, shadow DOM), tagged `sui-*` — usable from React, Vue, Angular, or plain
160
+ HTML, no separate Svelte installation required; the runtime is bundled with each
161
+ component.
162
+
163
+ ```html
164
+ <!-- Always the latest release, via GitHub Pages -->
165
+ <script type="module" src="https://juspay.github.io/svelte-ui-components/wc/index.js"></script>
166
+
167
+ <!-- Pinned to an npm version, via jsDelivr or unpkg -->
168
+ <script type="module" src="https://cdn.jsdelivr.net/npm/@juspay/svelte-ui-components@latest/dist-wc/index.js"></script>
169
+ <script type="module" src="https://unpkg.com/@juspay/svelte-ui-components@latest/dist-wc/index.js"></script>
170
+
171
+ <sui-button>Click me</sui-button>
172
+ <sui-input placeholder="Type here"></sui-input>
173
+ ```
174
+
175
+ Or from npm directly, via the package's `./wc` export:
176
+
177
+ ```ts
178
+ import '@juspay/svelte-ui-components/wc';
179
+ ```
180
+
181
+ Theming works identically to the Svelte components — the same `--{component}-{element}-{property}`
182
+ CSS custom properties apply across the shadow DOM boundary.
183
+
184
+ ---
185
+
156
186
  ## Theming
157
187
 
158
188
  ### How It Works
@@ -13,7 +13,8 @@
13
13
  indeterminateIcon,
14
14
  onclick,
15
15
  classes,
16
- ariaControls
16
+ ariaControls,
17
+ ariaLabel
17
18
  }: CheckboxProperties = $props();
18
19
 
19
20
  function handleClick(): void {
@@ -71,6 +72,7 @@
71
72
  aria-checked={indeterminate ? 'mixed' : checked}
72
73
  aria-disabled={disabled}
73
74
  aria-controls={ariaControls ?? null}
75
+ aria-label={text.length === 0 ? (ariaLabel ?? null) : null}
74
76
  onkeydown={handleKeyDown}
75
77
  data-pw={typeof testId === 'string' ? `${testId}-box` : null}
76
78
  testID={typeof testId === 'string' ? `${testId}-box` : null}
@@ -12,6 +12,11 @@ export type OptionalCheckboxProperties = {
12
12
  indeterminateIcon?: Snippet;
13
13
  classes?: string;
14
14
  ariaControls?: string;
15
+ /** Accessible name for the checkbox. Needed whenever the visible label sits
16
+ * outside this component (a table header cell, an icon-only row control),
17
+ * since name-from-content cannot reach it. Ignored when `text` is non-empty:
18
+ * a visible label must stay part of the accessible name (WCAG 2.5.3). */
19
+ ariaLabel?: string;
15
20
  };
16
21
  export type CheckboxEventProperties = {
17
22
  onclick?: (checked: boolean) => void;
@@ -0,0 +1,175 @@
1
+ <script lang="ts">
2
+ import type { DraggableProperties, DragPosition } from './properties';
3
+
4
+ let {
5
+ x = $bindable(0),
6
+ y = $bindable(0),
7
+ axis = 'both',
8
+ handle,
9
+ bounds = null,
10
+ disabled = false,
11
+ step = 16,
12
+ dragLabel = 'Drag to move',
13
+ children,
14
+ onMoveStart,
15
+ onMove,
16
+ onMoveEnd,
17
+ testId,
18
+ classes
19
+ }: DraggableProperties = $props();
20
+
21
+ let active: {
22
+ pointerId: number;
23
+ startX: number;
24
+ startY: number;
25
+ baseX: number;
26
+ baseY: number;
27
+ } | null = $state(null);
28
+
29
+ function isInteractive(target: EventTarget | null): boolean {
30
+ return (
31
+ target instanceof Element &&
32
+ target.closest('input, textarea, select, button, a, [contenteditable="true"]') !== null
33
+ );
34
+ }
35
+
36
+ function withinHandle(target: EventTarget | null): boolean {
37
+ if (typeof handle !== 'string' || handle.length === 0) {
38
+ return !isInteractive(target);
39
+ }
40
+ return target instanceof Element && target.closest(handle) !== null;
41
+ }
42
+
43
+ function clamp(node: HTMLElement, nextX: number, nextY: number): DragPosition {
44
+ if (bounds !== 'viewport' || typeof window === 'undefined') {
45
+ return { x: nextX, y: nextY };
46
+ }
47
+ const rect = node.getBoundingClientRect();
48
+ let resultX = nextX;
49
+ let resultY = nextY;
50
+ if (rect.left + (nextX - x) < 0) {
51
+ resultX = x - rect.left;
52
+ } else if (rect.right + (nextX - x) > window.innerWidth) {
53
+ resultX = x + (window.innerWidth - rect.right);
54
+ }
55
+ if (rect.top + (nextY - y) < 0) {
56
+ resultY = y - rect.top;
57
+ } else if (rect.bottom + (nextY - y) > window.innerHeight) {
58
+ resultY = y + (window.innerHeight - rect.bottom);
59
+ }
60
+ return { x: resultX, y: resultY };
61
+ }
62
+
63
+ function startDrag(event: PointerEvent & { currentTarget: HTMLElement }): void {
64
+ if (disabled || !withinHandle(event.target)) {
65
+ return;
66
+ }
67
+ event.preventDefault();
68
+ active = {
69
+ pointerId: event.pointerId,
70
+ startX: event.clientX,
71
+ startY: event.clientY,
72
+ baseX: x,
73
+ baseY: y
74
+ };
75
+ event.currentTarget.setPointerCapture(event.pointerId);
76
+ onMoveStart?.({ x, y });
77
+ }
78
+
79
+ function moveDrag(event: PointerEvent & { currentTarget: HTMLElement }): void {
80
+ if (active === null) {
81
+ return;
82
+ }
83
+ const nextX = axis === 'y' ? x : active.baseX + (event.clientX - active.startX);
84
+ const nextY = axis === 'x' ? y : active.baseY + (event.clientY - active.startY);
85
+ const clamped = clamp(event.currentTarget, nextX, nextY);
86
+ x = clamped.x;
87
+ y = clamped.y;
88
+ onMove?.({ x, y });
89
+ }
90
+
91
+ function endDrag(event: PointerEvent & { currentTarget: HTMLElement }): void {
92
+ if (active === null) {
93
+ return;
94
+ }
95
+ if (event.currentTarget.hasPointerCapture(event.pointerId)) {
96
+ event.currentTarget.releasePointerCapture(event.pointerId);
97
+ }
98
+ active = null;
99
+ onMoveEnd?.({ x, y });
100
+ }
101
+
102
+ function keyDrag(event: KeyboardEvent & { currentTarget: HTMLElement }): void {
103
+ if (disabled || event.target !== event.currentTarget) {
104
+ return;
105
+ }
106
+ let nextX = x;
107
+ let nextY = y;
108
+ let moved = false;
109
+ if (axis !== 'y' && event.key === 'ArrowLeft') {
110
+ nextX = x - step;
111
+ moved = true;
112
+ } else if (axis !== 'y' && event.key === 'ArrowRight') {
113
+ nextX = x + step;
114
+ moved = true;
115
+ } else if (axis !== 'x' && event.key === 'ArrowUp') {
116
+ nextY = y - step;
117
+ moved = true;
118
+ } else if (axis !== 'x' && event.key === 'ArrowDown') {
119
+ nextY = y + step;
120
+ moved = true;
121
+ }
122
+ if (moved) {
123
+ event.preventDefault();
124
+ const clamped = clamp(event.currentTarget, nextX, nextY);
125
+ x = clamped.x;
126
+ y = clamped.y;
127
+ onMove?.({ x, y });
128
+ }
129
+ }
130
+ </script>
131
+
132
+ <!-- svelte-ignore a11y_no_noninteractive_tabindex -->
133
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
134
+ <div
135
+ class="draggable {classes ?? ''}"
136
+ class:dragging={active !== null}
137
+ data-pw={typeof testId === 'string' ? testId : null}
138
+ tabindex={disabled ? -1 : 0}
139
+ aria-label={dragLabel}
140
+ style:transform={`translate(${x}px, ${y}px)`}
141
+ onpointerdown={startDrag}
142
+ onpointermove={moveDrag}
143
+ onpointerup={endDrag}
144
+ onkeydown={keyDrag}
145
+ >
146
+ {#if typeof children === 'function'}
147
+ {@render children()}
148
+ {/if}
149
+ </div>
150
+
151
+ <style>
152
+ .draggable {
153
+ box-sizing: border-box;
154
+ width: var(--draggable-width, fit-content);
155
+ height: var(--draggable-height, fit-content);
156
+ cursor: var(--draggable-cursor, grab);
157
+ touch-action: none;
158
+ }
159
+
160
+ .draggable.dragging {
161
+ cursor: var(--draggable-cursor-active, grabbing);
162
+ user-select: none;
163
+ }
164
+
165
+ .draggable:focus-visible {
166
+ outline: var(--draggable-focus-outline, 2px solid #3b5bdb);
167
+ outline-offset: var(--draggable-focus-outline-offset, 2px);
168
+ }
169
+
170
+ @media (prefers-reduced-motion: reduce) {
171
+ .draggable {
172
+ transition: none;
173
+ }
174
+ }
175
+ </style>
@@ -0,0 +1,4 @@
1
+ import type { DraggableProperties } from './properties';
2
+ declare const Draggable: import("svelte").Component<DraggableProperties, {}, "x" | "y">;
3
+ type Draggable = ReturnType<typeof Draggable>;
4
+ export default Draggable;
@@ -0,0 +1,26 @@
1
+ import type { Snippet } from 'svelte';
2
+ export type DragAxis = 'both' | 'x' | 'y';
3
+ export type DragBounds = 'viewport' | null;
4
+ export type DragPosition = {
5
+ x: number;
6
+ y: number;
7
+ };
8
+ export type DraggableProperties = OptionalDraggableProperties & DraggableEventProperties;
9
+ export type OptionalDraggableProperties = {
10
+ x?: number;
11
+ y?: number;
12
+ axis?: DragAxis;
13
+ handle?: string;
14
+ bounds?: DragBounds;
15
+ disabled?: boolean;
16
+ step?: number;
17
+ dragLabel?: string;
18
+ children?: Snippet;
19
+ testId?: string;
20
+ classes?: string;
21
+ };
22
+ export type DraggableEventProperties = {
23
+ onMoveStart?: (position: DragPosition) => void;
24
+ onMove?: (position: DragPosition) => void;
25
+ onMoveEnd?: (position: DragPosition) => void;
26
+ };
@@ -0,0 +1 @@
1
+ export {};