ui-svelte 0.2.10 → 0.2.12

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 (206) hide show
  1. package/dist/charts/ArcChart.svelte +9 -13
  2. package/dist/charts/ArcChart.svelte.d.ts +3 -3
  3. package/dist/charts/AreaChart.svelte +347 -118
  4. package/dist/charts/AreaChart.svelte.d.ts +33 -4
  5. package/dist/charts/BarChart.svelte +288 -66
  6. package/dist/charts/BarChart.svelte.d.ts +26 -1
  7. package/dist/charts/Candlestick.svelte +53 -50
  8. package/dist/charts/Candlestick.svelte.d.ts +8 -8
  9. package/dist/charts/LineChart.svelte +391 -91
  10. package/dist/charts/LineChart.svelte.d.ts +26 -3
  11. package/dist/charts/PieChart.svelte +333 -92
  12. package/dist/charts/PieChart.svelte.d.ts +33 -5
  13. package/dist/charts/css/arc-chart.css +3 -3
  14. package/dist/charts/css/area-chart.css +127 -29
  15. package/dist/charts/css/bar-chart.css +114 -8
  16. package/dist/charts/css/candlestick.css +2 -0
  17. package/dist/charts/css/line-chart.css +111 -13
  18. package/dist/charts/css/pie-chart.css +92 -20
  19. package/dist/control/Audio.svelte +86 -44
  20. package/dist/control/Audio.svelte.d.ts +4 -1
  21. package/dist/control/Button.svelte +18 -27
  22. package/dist/control/Button.svelte.d.ts +3 -2
  23. package/dist/control/IconButton.svelte +17 -27
  24. package/dist/control/IconButton.svelte.d.ts +3 -3
  25. package/dist/control/Image.svelte +123 -0
  26. package/dist/control/Image.svelte.d.ts +13 -0
  27. package/dist/control/Record.svelte +144 -98
  28. package/dist/control/Record.svelte.d.ts +2 -1
  29. package/dist/control/ToggleGroup.svelte +22 -8
  30. package/dist/control/ToggleGroup.svelte.d.ts +2 -1
  31. package/dist/control/ToggleTheme.svelte +13 -11
  32. package/dist/control/ToggleTheme.svelte.d.ts +3 -2
  33. package/dist/control/Video.svelte +55 -29
  34. package/dist/control/Video.svelte.d.ts +1 -0
  35. package/dist/control/css/btn.css +200 -152
  36. package/dist/control/css/image.css +56 -0
  37. package/dist/control/css/media.css +95 -30
  38. package/dist/control/css/toggle-group.css +269 -84
  39. package/dist/control/css/video.css +1 -14
  40. package/dist/css/animations.css +427 -2
  41. package/dist/css/base.css +13 -347
  42. package/dist/css/decorations.css +402 -0
  43. package/dist/css/rich-text.css +485 -0
  44. package/dist/css/transitions.css +158 -0
  45. package/dist/css/typography.css +291 -0
  46. package/dist/display/Accordion.svelte +28 -4
  47. package/dist/display/Accordion.svelte.d.ts +2 -1
  48. package/dist/display/Alert.svelte +32 -12
  49. package/dist/display/Alert.svelte.d.ts +2 -3
  50. package/dist/display/Avatar.svelte +54 -26
  51. package/dist/display/Avatar.svelte.d.ts +7 -1
  52. package/dist/display/AvatarGroup.svelte +26 -18
  53. package/dist/display/AvatarGroup.svelte.d.ts +9 -3
  54. package/dist/display/Badge.svelte +11 -4
  55. package/dist/display/Badge.svelte.d.ts +2 -1
  56. package/dist/display/Card.svelte +15 -14
  57. package/dist/display/Card.svelte.d.ts +2 -3
  58. package/dist/display/Carousel.svelte +130 -99
  59. package/dist/display/Carousel.svelte.d.ts +6 -4
  60. package/dist/display/ChatBox.svelte +245 -106
  61. package/dist/display/ChatBox.svelte.d.ts +32 -5
  62. package/dist/display/Chip.svelte +31 -17
  63. package/dist/display/Chip.svelte.d.ts +3 -2
  64. package/dist/display/Code.svelte +6 -3
  65. package/dist/display/Code.svelte.d.ts +1 -0
  66. package/dist/display/Collapsible.svelte +30 -4
  67. package/dist/display/Collapsible.svelte.d.ts +2 -1
  68. package/dist/display/Empty.svelte +37 -3
  69. package/dist/display/Empty.svelte.d.ts +3 -0
  70. package/dist/display/Item.svelte +31 -18
  71. package/dist/display/Item.svelte.d.ts +2 -2
  72. package/dist/display/Map.svelte +488 -0
  73. package/dist/display/Map.svelte.d.ts +44 -0
  74. package/dist/display/Section.svelte +14 -12
  75. package/dist/display/Section.svelte.d.ts +2 -3
  76. package/dist/display/Skeleton.svelte +32 -0
  77. package/dist/display/Skeleton.svelte.d.ts +10 -0
  78. package/dist/display/Table.svelte +94 -132
  79. package/dist/display/Table.svelte.d.ts +10 -1
  80. package/dist/display/css/accordion.css +349 -52
  81. package/dist/display/css/alert.css +18 -25
  82. package/dist/display/css/avatar-group.css +38 -44
  83. package/dist/display/css/avatar.css +152 -123
  84. package/dist/display/css/badge.css +50 -27
  85. package/dist/display/css/card.css +51 -71
  86. package/dist/display/css/carousel.css +25 -5
  87. package/dist/display/css/chat-box.css +158 -26
  88. package/dist/display/css/chip.css +142 -68
  89. package/dist/display/css/code.css +2 -6
  90. package/dist/display/css/collapsible.css +349 -45
  91. package/dist/display/css/divider.css +8 -6
  92. package/dist/display/css/empty.css +7 -0
  93. package/dist/display/css/item.css +311 -89
  94. package/dist/display/css/map.css +164 -0
  95. package/dist/display/css/section.css +78 -33
  96. package/dist/display/css/skeleton.css +58 -0
  97. package/dist/display/css/table.css +320 -189
  98. package/dist/form/Checkbox.svelte +11 -5
  99. package/dist/form/Checkbox.svelte.d.ts +2 -1
  100. package/dist/form/ColorField.svelte +543 -0
  101. package/dist/form/ColorField.svelte.d.ts +29 -0
  102. package/dist/form/ComboBox.svelte +24 -9
  103. package/dist/form/ComboBox.svelte.d.ts +2 -2
  104. package/dist/form/CsvField.svelte +62 -136
  105. package/dist/form/CsvField.svelte.d.ts +2 -2
  106. package/dist/form/DateField.svelte +33 -15
  107. package/dist/form/DateField.svelte.d.ts +2 -1
  108. package/dist/form/DateRange.svelte +436 -0
  109. package/dist/form/DateRange.svelte.d.ts +24 -0
  110. package/dist/form/DragDrop.svelte +348 -0
  111. package/dist/form/DragDrop.svelte.d.ts +32 -0
  112. package/dist/form/Dropzone.svelte +28 -8
  113. package/dist/form/Dropzone.svelte.d.ts +2 -2
  114. package/dist/form/Editor.svelte +626 -0
  115. package/dist/form/Editor.svelte.d.ts +50 -0
  116. package/dist/form/ImageCropper.svelte +291 -61
  117. package/dist/form/ImageCropper.svelte.d.ts +15 -1
  118. package/dist/form/PasswordField.svelte +120 -75
  119. package/dist/form/PasswordField.svelte.d.ts +9 -10
  120. package/dist/form/PhoneField.svelte +34 -16
  121. package/dist/form/PhoneField.svelte.d.ts +4 -3
  122. package/dist/form/PinField.svelte +39 -31
  123. package/dist/form/PinField.svelte.d.ts +3 -3
  124. package/dist/form/RadioGroup.svelte +4 -4
  125. package/dist/form/RadioGroup.svelte.d.ts +1 -1
  126. package/dist/form/Select.svelte +20 -19
  127. package/dist/form/Select.svelte.d.ts +2 -2
  128. package/dist/form/Slider.svelte +4 -2
  129. package/dist/form/Slider.svelte.d.ts +1 -0
  130. package/dist/form/TextField.svelte +16 -7
  131. package/dist/form/TextField.svelte.d.ts +2 -2
  132. package/dist/form/Textarea.svelte +15 -6
  133. package/dist/form/Textarea.svelte.d.ts +2 -2
  134. package/dist/form/Toggle.svelte +11 -1
  135. package/dist/form/Toggle.svelte.d.ts +2 -0
  136. package/dist/form/css/checkbox.css +18 -2
  137. package/dist/form/css/color-field.css +141 -0
  138. package/dist/form/css/control.css +193 -82
  139. package/dist/form/css/csv-field.css +226 -0
  140. package/dist/form/css/date-range.css +122 -0
  141. package/dist/form/css/date.css +24 -2
  142. package/dist/form/css/drag-drop.css +271 -0
  143. package/dist/form/css/dropzone.css +153 -34
  144. package/dist/form/css/editor.css +367 -0
  145. package/dist/form/css/field.css +4 -0
  146. package/dist/form/css/image-cropper.css +223 -22
  147. package/dist/form/css/password.css +1 -1
  148. package/dist/form/css/radio-group.css +1 -1
  149. package/dist/form/css/select.css +2 -2
  150. package/dist/form/css/slider.css +1 -0
  151. package/dist/form/css/textarea.css +178 -75
  152. package/dist/form/css/toggle.css +11 -2
  153. package/dist/hooks/use-table.svelte.d.ts +1 -0
  154. package/dist/hooks/use-table.svelte.js +6 -0
  155. package/dist/icons/index.d.ts +38 -2
  156. package/dist/icons/index.js +40 -4
  157. package/dist/index.css +16 -1
  158. package/dist/index.d.ts +11 -3
  159. package/dist/index.js +10 -2
  160. package/dist/layout/AppBar.svelte +22 -14
  161. package/dist/layout/AppBar.svelte.d.ts +2 -1
  162. package/dist/layout/Footer.svelte +19 -11
  163. package/dist/layout/Footer.svelte.d.ts +2 -1
  164. package/dist/layout/Provider.svelte +27 -4
  165. package/dist/layout/Provider.svelte.d.ts +3 -1
  166. package/dist/layout/css/app-bar.css +63 -66
  167. package/dist/layout/css/footer.css +62 -65
  168. package/dist/navigation/BottomNav.svelte +41 -13
  169. package/dist/navigation/FooterGroup.svelte +1 -1
  170. package/dist/navigation/NavMenu.svelte +47 -23
  171. package/dist/navigation/NavMenu.svelte.d.ts +29 -0
  172. package/dist/navigation/Pagination.svelte +158 -0
  173. package/dist/navigation/Pagination.svelte.d.ts +18 -0
  174. package/dist/navigation/SideNav.svelte +30 -25
  175. package/dist/navigation/SideNav.svelte.d.ts +2 -3
  176. package/dist/navigation/Tabs.svelte +17 -7
  177. package/dist/navigation/Tabs.svelte.d.ts +2 -2
  178. package/dist/navigation/css/bottom-nav.css +279 -257
  179. package/dist/navigation/css/footer-group.css +1 -1
  180. package/dist/navigation/css/footer-nav.css +1 -1
  181. package/dist/navigation/css/nav-menu.css +332 -106
  182. package/dist/navigation/css/pagination.css +74 -0
  183. package/dist/navigation/css/side-nav.css +515 -75
  184. package/dist/navigation/css/tabs.css +246 -52
  185. package/dist/overlay/Command.svelte +340 -0
  186. package/dist/overlay/Command.svelte.d.ts +24 -25
  187. package/dist/overlay/Drawer.svelte +49 -21
  188. package/dist/overlay/Drawer.svelte.d.ts +2 -2
  189. package/dist/overlay/Dropdown.svelte +4 -5
  190. package/dist/overlay/Modal.svelte +51 -16
  191. package/dist/overlay/Modal.svelte.d.ts +3 -3
  192. package/dist/overlay/Toast.svelte +41 -17
  193. package/dist/overlay/Toast.svelte.d.ts +1 -1
  194. package/dist/overlay/Tooltip.svelte +40 -26
  195. package/dist/overlay/Tooltip.svelte.d.ts +2 -2
  196. package/dist/overlay/css/command.css +80 -0
  197. package/dist/overlay/css/drawer.css +63 -24
  198. package/dist/overlay/css/dropdown.css +1 -1
  199. package/dist/overlay/css/hovercard.css +1 -1
  200. package/dist/overlay/css/modal.css +27 -27
  201. package/dist/overlay/css/toast.css +17 -29
  202. package/dist/overlay/css/tooltip.css +83 -66
  203. package/dist/stores/theme.svelte.js +26 -1
  204. package/dist/stores/toast.svelte.d.ts +4 -4
  205. package/dist/stores/toast.svelte.js +2 -2
  206. package/package.json +1 -1
@@ -1,36 +1,80 @@
1
1
  <script lang="ts">
2
- import { Icon } from '../index.js';
2
+ import type { IconData } from '../display/Icon.svelte';
3
+ import {
4
+ ImageAddRegularIcon,
5
+ ArrowResetRegularIcon,
6
+ CropRegularIcon,
7
+ Dismiss24RegularIcon
8
+ } from '../icons/index.js';
9
+ import { Icon, IconButton, Modal, Button } from '../index.js';
3
10
  import { cn } from '../utils/class-names.js';
4
11
 
5
12
  type Props = {
6
- src: string;
13
+ src?: string;
7
14
  alt?: string;
8
15
  aspectRatio?: number;
9
16
  minWidth?: number;
10
17
  minHeight?: number;
11
18
  maxWidth?: number;
12
19
  maxHeight?: number;
20
+ accept?: string;
21
+ placeholder?: string;
22
+ icon?: IconData;
23
+ size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
24
+ shape?: 'circle' | 'square';
25
+ color?: 'primary' | 'secondary' | 'muted' | 'success' | 'info' | 'danger' | 'warning';
26
+ variant?: 'solid' | 'soft' | 'outlined' | 'ghost';
27
+ disabled?: boolean;
13
28
  onCrop?: (croppedImage: string) => void;
29
+ onChange?: (file: File | null) => void;
14
30
  class?: string;
31
+ name?: string;
32
+ label?: string;
33
+ helpText?: string;
34
+ errorText?: string;
15
35
  };
16
36
 
17
37
  const {
18
- src,
19
- alt = 'Image to crop',
38
+ src: initialSrc,
39
+ alt = 'Avatar',
20
40
  aspectRatio,
21
41
  minWidth = 50,
22
42
  minHeight = 50,
23
43
  maxWidth,
24
44
  maxHeight,
45
+ accept = 'image/*',
46
+ placeholder = 'Upload',
47
+ icon = ImageAddRegularIcon,
48
+ size = 'md',
49
+ shape = 'circle',
50
+ color = 'muted',
51
+ variant = 'soft',
52
+ disabled = false,
25
53
  onCrop,
26
- class: className
54
+ onChange,
55
+ class: className,
56
+ name,
57
+ label,
58
+ helpText,
59
+ errorText
27
60
  }: Props = $props();
28
61
 
29
- let canvas: HTMLCanvasElement;
30
- let image: HTMLImageElement;
31
- let containerDiv: HTMLDivElement;
62
+ const uid = $props.id();
32
63
 
33
- let isDragging = $state(false);
64
+ let canvas = $state<HTMLCanvasElement>();
65
+ let image = $state<HTMLImageElement>();
66
+ let containerDiv = $state<HTMLDivElement>();
67
+ let fileInput = $state<HTMLInputElement>();
68
+
69
+ // svelte-ignore state_referenced_locally
70
+ let currentSrc = $state(initialSrc || '');
71
+ // svelte-ignore state_referenced_locally
72
+ let croppedSrc = $state(initialSrc || '');
73
+ let uploadedFile = $state<File | null>(null);
74
+
75
+ let showModal = $state(false);
76
+
77
+ let isCropDragging = $state(false);
34
78
  let isResizing = $state(false);
35
79
  let resizeHandle = $state<string>('');
36
80
 
@@ -51,6 +95,57 @@
51
95
  let imageHeight = $state(0);
52
96
  let scale = $state(1);
53
97
 
98
+ const sizeClasses = {
99
+ xs: 'is-xs',
100
+ sm: 'is-sm',
101
+ md: 'is-md',
102
+ lg: 'is-lg',
103
+ xl: 'is-xl'
104
+ };
105
+
106
+ const colorClasses = {
107
+ primary: 'is-primary',
108
+ secondary: 'is-secondary',
109
+ muted: 'is-muted',
110
+ success: 'is-success',
111
+ info: 'is-info',
112
+ danger: 'is-danger',
113
+ warning: 'is-warning'
114
+ };
115
+
116
+ const variantClasses = {
117
+ solid: 'is-solid',
118
+ soft: 'is-soft',
119
+ outlined: 'is-outlined',
120
+ ghost: 'is-ghost'
121
+ };
122
+
123
+ $effect(() => {
124
+ if (initialSrc && initialSrc !== currentSrc) {
125
+ currentSrc = initialSrc;
126
+ croppedSrc = initialSrc;
127
+ imageLoaded = false;
128
+ }
129
+ });
130
+
131
+ function handleFiles(fileList: FileList | null) {
132
+ if (!fileList || fileList.length === 0 || disabled) return;
133
+
134
+ const file = fileList[0];
135
+ if (!file.type.startsWith('image/')) return;
136
+
137
+ if (uploadedFile && currentSrc.startsWith('blob:')) {
138
+ URL.revokeObjectURL(currentSrc);
139
+ }
140
+
141
+ uploadedFile = file;
142
+ currentSrc = URL.createObjectURL(file);
143
+ imageLoaded = false;
144
+ onChange?.(file);
145
+
146
+ showModal = true;
147
+ }
148
+
54
149
  function handleImageLoad() {
55
150
  if (!image || !containerDiv) return;
56
151
 
@@ -67,7 +162,7 @@
67
162
  imageWidth = naturalWidth * scale;
68
163
  imageHeight = naturalHeight * scale;
69
164
 
70
- const initialSize = Math.min(imageWidth, imageHeight) * 0.6;
165
+ const initialSize = Math.min(imageWidth, imageHeight) * 0.8;
71
166
  cropWidth = aspectRatio ? initialSize : initialSize;
72
167
  cropHeight = aspectRatio ? initialSize / aspectRatio : initialSize;
73
168
  cropX = (imageWidth - cropWidth) / 2;
@@ -84,7 +179,7 @@
84
179
  isResizing = true;
85
180
  resizeHandle = handle;
86
181
  } else {
87
- isDragging = true;
182
+ isCropDragging = true;
88
183
  }
89
184
 
90
185
  startX = e.clientX;
@@ -102,7 +197,7 @@
102
197
  const deltaX = e.clientX - startX;
103
198
  const deltaY = e.clientY - startY;
104
199
 
105
- if (isDragging) {
200
+ if (isCropDragging) {
106
201
  cropX = Math.max(0, Math.min(imageWidth - cropWidth, startCropX + deltaX));
107
202
  cropY = Math.max(0, Math.min(imageHeight - cropHeight, startCropY + deltaY));
108
203
  } else if (isResizing) {
@@ -148,7 +243,7 @@
148
243
  }
149
244
 
150
245
  function handleMouseUp() {
151
- isDragging = false;
246
+ isCropDragging = false;
152
247
  isResizing = false;
153
248
  resizeHandle = '';
154
249
  document.removeEventListener('mousemove', handleMouseMove);
@@ -180,75 +275,210 @@
180
275
  );
181
276
 
182
277
  const croppedImageUrl = canvas.toDataURL('image/png');
278
+ croppedSrc = croppedImageUrl;
183
279
  onCrop?.(croppedImageUrl);
280
+ showModal = false;
184
281
  }
185
282
 
186
283
  function handleReset() {
187
284
  if (!imageLoaded) return;
188
- const initialSize = Math.min(imageWidth, imageHeight) * 0.6;
285
+ const initialSize = Math.min(imageWidth, imageHeight) * 0.8;
189
286
  cropWidth = aspectRatio ? initialSize : initialSize;
190
287
  cropHeight = aspectRatio ? initialSize / aspectRatio : initialSize;
191
288
  cropX = (imageWidth - cropWidth) / 2;
192
289
  cropY = (imageHeight - cropHeight) / 2;
193
290
  }
291
+
292
+ function handleRemoveImage() {
293
+ if (uploadedFile && currentSrc.startsWith('blob:')) {
294
+ URL.revokeObjectURL(currentSrc);
295
+ }
296
+ uploadedFile = null;
297
+ currentSrc = '';
298
+ croppedSrc = '';
299
+ imageLoaded = false;
300
+ onChange?.(null);
301
+ }
302
+
303
+ function openCropModal() {
304
+ if (currentSrc && !disabled) {
305
+ showModal = true;
306
+ }
307
+ }
308
+
309
+ function closeModal() {
310
+ showModal = false;
311
+ }
194
312
  </script>
195
313
 
196
- <div class={cn('image-cropper', className)}>
197
- <div class="image-cropper-container" bind:this={containerDiv}>
198
- <img
199
- bind:this={image}
200
- {src}
201
- {alt}
202
- class="image-cropper-image"
203
- onload={handleImageLoad}
204
- style="width: {imageWidth}px; height: {imageHeight}px;"
314
+ <div class={cn('field', className)}>
315
+ {#if label}
316
+ <span class="field-label">{label}</span>
317
+ {/if}
318
+
319
+ <div class="image-cropper-wrapper">
320
+ <input
321
+ bind:this={fileInput}
322
+ id={`${uid}-${name}`}
323
+ type="file"
324
+ hidden
325
+ {accept}
326
+ {disabled}
327
+ {name}
328
+ onchange={(e) => handleFiles((e.target as HTMLInputElement).files)}
205
329
  />
206
330
 
207
- {#if imageLoaded}
208
- <div class="image-cropper-overlay">
209
- <div class="overlay-top" style="height: {cropY}px;"></div>
210
- <div class="overlay-middle" style="top: {cropY}px; height: {cropHeight}px;">
211
- <div class="overlay-left" style="width: {cropX}px;"></div>
212
- <div
213
- class="overlay-right"
214
- style="left: {cropX + cropWidth}px; width: {imageWidth - cropX - cropWidth}px;"
215
- ></div>
331
+ <button
332
+ type="button"
333
+ class={cn(
334
+ 'image-cropper-avatar',
335
+ sizeClasses[size],
336
+ colorClasses[color],
337
+ variantClasses[variant],
338
+ shape === 'circle' && 'is-circle',
339
+ disabled && 'is-disabled'
340
+ )}
341
+ class:is-error={errorText}
342
+ onclick={() => (croppedSrc ? openCropModal() : fileInput?.click())}
343
+ {disabled}
344
+ >
345
+ {#if croppedSrc}
346
+ <img src={croppedSrc} {alt} class="image-cropper-preview" />
347
+ <div class="image-cropper-overlay-edit">
348
+ <Icon icon={CropRegularIcon} />
216
349
  </div>
217
- <div
218
- class="overlay-bottom"
219
- style="top: {cropY + cropHeight}px; height: {imageHeight - cropY - cropHeight}px;"
220
- ></div>
350
+ {:else}
351
+ <Icon {icon} class="image-cropper-icon" />
352
+ <span class="image-cropper-placeholder">{placeholder}</span>
353
+ {/if}
354
+ </button>
355
+
356
+ {#if croppedSrc}
357
+ <div class="image-cropper-actions">
358
+ <IconButton
359
+ icon={ImageAddRegularIcon}
360
+ variant="ghost"
361
+ {color}
362
+ size="sm"
363
+ onclick={() => fileInput?.click()}
364
+ />
365
+ {#if uploadedFile}
366
+ <IconButton
367
+ icon={Dismiss24RegularIcon}
368
+ variant="ghost"
369
+ color="danger"
370
+ size="sm"
371
+ onclick={handleRemoveImage}
372
+ />
373
+ {/if}
374
+ </div>
375
+ {/if}
376
+ </div>
221
377
 
222
- <!-- svelte-ignore a11y_no_static_element_interactions -->
378
+ {#if errorText || helpText}
379
+ <div class={cn('field-help', errorText && 'is-danger')}>
380
+ {errorText || helpText}
381
+ </div>
382
+ {/if}
383
+ </div>
384
+
385
+ <Modal bind:open={showModal} onclose={closeModal} color="surface" rootClass="image-cropper-modal">
386
+ {#snippet header()}
387
+ <h2 class="image-cropper-modal-title">Crop Image</h2>
388
+ {/snippet}
389
+
390
+ <div class="image-cropper-modal-body">
391
+ <div class="image-cropper-container" bind:this={containerDiv}>
392
+ <img
393
+ bind:this={image}
394
+ src={currentSrc}
395
+ {alt}
396
+ class="image-cropper-image"
397
+ onload={handleImageLoad}
398
+ style="width: {imageWidth}px; height: {imageHeight}px;"
399
+ />
400
+
401
+ {#if imageLoaded}
223
402
  <div
224
- class="crop-area"
225
- style="left: {cropX}px; top: {cropY}px; width: {cropWidth}px; height: {cropHeight}px;"
226
- onmousedown={(e) => handleMouseDown(e)}
403
+ class="image-cropper-crop-overlay"
404
+ style="width: {imageWidth}px; height: {imageHeight}px;"
227
405
  >
228
- <div class="crop-grid">
229
- <div class="grid-line grid-line-v" style="left: 33.33%;"></div>
230
- <div class="grid-line grid-line-v" style="left: 66.66%;"></div>
231
- <div class="grid-line grid-line-h" style="top: 33.33%;"></div>
232
- <div class="grid-line grid-line-h" style="top: 66.66%;"></div>
406
+ <div class="overlay-top" style="height: {cropY}px;"></div>
407
+ <div class="overlay-middle" style="top: {cropY}px; height: {cropHeight}px;">
408
+ <div class="overlay-left" style="width: {cropX}px;"></div>
409
+ <div
410
+ class="overlay-right"
411
+ style="left: {cropX + cropWidth}px; width: {imageWidth - cropX - cropWidth}px;"
412
+ ></div>
233
413
  </div>
414
+ <div
415
+ class="overlay-bottom"
416
+ style="top: {cropY + cropHeight}px; height: {imageHeight - cropY - cropHeight}px;"
417
+ ></div>
234
418
 
235
- <div class="resize-handle handle-nw" onmousedown={(e) => handleMouseDown(e, 'nw')}></div>
236
- <div class="resize-handle handle-n" onmousedown={(e) => handleMouseDown(e, 'n')}></div>
237
- <div class="resize-handle handle-ne" onmousedown={(e) => handleMouseDown(e, 'ne')}></div>
238
- <div class="resize-handle handle-e" onmousedown={(e) => handleMouseDown(e, 'e')}></div>
239
- <div class="resize-handle handle-se" onmousedown={(e) => handleMouseDown(e, 'se')}></div>
240
- <div class="resize-handle handle-s" onmousedown={(e) => handleMouseDown(e, 's')}></div>
241
- <div class="resize-handle handle-sw" onmousedown={(e) => handleMouseDown(e, 'sw')}></div>
242
- <div class="resize-handle handle-w" onmousedown={(e) => handleMouseDown(e, 'w')}></div>
419
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
420
+ <div
421
+ class="crop-area"
422
+ class:is-circle={shape === 'circle'}
423
+ style="left: {cropX}px; top: {cropY}px; width: {cropWidth}px; height: {cropHeight}px;"
424
+ onmousedown={(e) => handleMouseDown(e)}
425
+ >
426
+ <div class="crop-grid">
427
+ <div class="grid-line grid-line-v" style="left: 33.33%;"></div>
428
+ <div class="grid-line grid-line-v" style="left: 66.66%;"></div>
429
+ <div class="grid-line grid-line-h" style="top: 33.33%;"></div>
430
+ <div class="grid-line grid-line-h" style="top: 66.66%;"></div>
431
+ </div>
432
+
433
+ <div
434
+ class="resize-handle handle-nw"
435
+ onmousedown={(e) => handleMouseDown(e, 'nw')}
436
+ ></div>
437
+ <div class="resize-handle handle-n" onmousedown={(e) => handleMouseDown(e, 'n')}></div>
438
+ <div
439
+ class="resize-handle handle-ne"
440
+ onmousedown={(e) => handleMouseDown(e, 'ne')}
441
+ ></div>
442
+ <div class="resize-handle handle-e" onmousedown={(e) => handleMouseDown(e, 'e')}></div>
443
+ <div
444
+ class="resize-handle handle-se"
445
+ onmousedown={(e) => handleMouseDown(e, 'se')}
446
+ ></div>
447
+ <div class="resize-handle handle-s" onmousedown={(e) => handleMouseDown(e, 's')}></div>
448
+ <div
449
+ class="resize-handle handle-sw"
450
+ onmousedown={(e) => handleMouseDown(e, 'sw')}
451
+ ></div>
452
+ <div class="resize-handle handle-w" onmousedown={(e) => handleMouseDown(e, 'w')}></div>
453
+ </div>
243
454
  </div>
244
- </div>
245
- {/if}
246
- </div>
455
+ {/if}
456
+ </div>
247
457
 
248
- <div class="image-cropper-controls">
249
- <button class="btn is-md is-outlined" onclick={handleReset}> refresh icon </button>
250
- <button class="btn is-md is-primary is-solid" onclick={handleCrop}> crop icon </button>
458
+ <canvas bind:this={canvas} class="image-cropper-canvas"></canvas>
251
459
  </div>
252
460
 
253
- <canvas bind:this={canvas} class="image-cropper-canvas"></canvas>
254
- </div>
461
+ {#snippet footer()}
462
+ <div class="image-cropper-modal-footer">
463
+ <Button
464
+ color="muted"
465
+ variant="ghost"
466
+ size="sm"
467
+ onclick={handleReset}
468
+ startIcon={ArrowResetRegularIcon}
469
+ >
470
+ Reset
471
+ </Button>
472
+ <Button color="muted" variant="outlined" size="sm" onclick={closeModal}>Cancel</Button>
473
+ <Button
474
+ color="primary"
475
+ variant="solid"
476
+ size="sm"
477
+ onclick={handleCrop}
478
+ startIcon={CropRegularIcon}
479
+ >
480
+ Apply
481
+ </Button>
482
+ </div>
483
+ {/snippet}
484
+ </Modal>
@@ -1,13 +1,27 @@
1
+ import type { IconData } from '../display/Icon.svelte';
1
2
  type Props = {
2
- src: string;
3
+ src?: string;
3
4
  alt?: string;
4
5
  aspectRatio?: number;
5
6
  minWidth?: number;
6
7
  minHeight?: number;
7
8
  maxWidth?: number;
8
9
  maxHeight?: number;
10
+ accept?: string;
11
+ placeholder?: string;
12
+ icon?: IconData;
13
+ size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
14
+ shape?: 'circle' | 'square';
15
+ color?: 'primary' | 'secondary' | 'muted' | 'success' | 'info' | 'danger' | 'warning';
16
+ variant?: 'solid' | 'soft' | 'outlined' | 'ghost';
17
+ disabled?: boolean;
9
18
  onCrop?: (croppedImage: string) => void;
19
+ onChange?: (file: File | null) => void;
10
20
  class?: string;
21
+ name?: string;
22
+ label?: string;
23
+ helpText?: string;
24
+ errorText?: string;
11
25
  };
12
26
  declare const ImageCropper: import("svelte").Component<Props, {}, "">;
13
27
  type ImageCropper = ReturnType<typeof ImageCropper>;