ui-svelte 0.2.11 → 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 (204) 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 +5 -9
  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 +23 -18
  51. package/dist/display/Avatar.svelte.d.ts +4 -1
  52. package/dist/display/AvatarGroup.svelte +20 -18
  53. package/dist/display/AvatarGroup.svelte.d.ts +6 -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 +30 -11
  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 -75
  83. package/dist/display/css/avatar.css +139 -121
  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/{PasswordStrength.svelte → PasswordField.svelte} +58 -24
  119. package/dist/form/{PasswordStrength.svelte.d.ts → PasswordField.svelte.d.ts} +6 -5
  120. package/dist/form/PhoneField.svelte +26 -14
  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 +1 -1
  135. package/dist/form/css/checkbox.css +18 -2
  136. package/dist/form/css/color-field.css +141 -0
  137. package/dist/form/css/control.css +193 -82
  138. package/dist/form/css/csv-field.css +226 -0
  139. package/dist/form/css/date-range.css +122 -0
  140. package/dist/form/css/date.css +24 -2
  141. package/dist/form/css/drag-drop.css +271 -0
  142. package/dist/form/css/dropzone.css +153 -34
  143. package/dist/form/css/editor.css +367 -0
  144. package/dist/form/css/field.css +4 -0
  145. package/dist/form/css/image-cropper.css +223 -22
  146. package/dist/form/css/radio-group.css +1 -1
  147. package/dist/form/css/select.css +2 -2
  148. package/dist/form/css/slider.css +1 -0
  149. package/dist/form/css/textarea.css +178 -75
  150. package/dist/form/css/toggle.css +3 -3
  151. package/dist/hooks/use-table.svelte.d.ts +1 -0
  152. package/dist/hooks/use-table.svelte.js +6 -0
  153. package/dist/icons/index.d.ts +30 -2
  154. package/dist/icons/index.js +32 -4
  155. package/dist/index.css +16 -1
  156. package/dist/index.d.ts +12 -4
  157. package/dist/index.js +11 -3
  158. package/dist/layout/AppBar.svelte +22 -14
  159. package/dist/layout/AppBar.svelte.d.ts +2 -1
  160. package/dist/layout/Footer.svelte +19 -11
  161. package/dist/layout/Footer.svelte.d.ts +2 -1
  162. package/dist/layout/Provider.svelte +27 -4
  163. package/dist/layout/Provider.svelte.d.ts +3 -1
  164. package/dist/layout/css/app-bar.css +63 -66
  165. package/dist/layout/css/footer.css +62 -65
  166. package/dist/navigation/BottomNav.svelte +41 -13
  167. package/dist/navigation/FooterGroup.svelte +1 -1
  168. package/dist/navigation/NavMenu.svelte +47 -23
  169. package/dist/navigation/NavMenu.svelte.d.ts +29 -0
  170. package/dist/navigation/Pagination.svelte +158 -0
  171. package/dist/navigation/Pagination.svelte.d.ts +18 -0
  172. package/dist/navigation/SideNav.svelte +30 -25
  173. package/dist/navigation/SideNav.svelte.d.ts +2 -3
  174. package/dist/navigation/Tabs.svelte +17 -7
  175. package/dist/navigation/Tabs.svelte.d.ts +2 -2
  176. package/dist/navigation/css/bottom-nav.css +279 -257
  177. package/dist/navigation/css/footer-group.css +1 -1
  178. package/dist/navigation/css/footer-nav.css +1 -1
  179. package/dist/navigation/css/nav-menu.css +332 -106
  180. package/dist/navigation/css/pagination.css +74 -0
  181. package/dist/navigation/css/side-nav.css +515 -75
  182. package/dist/navigation/css/tabs.css +246 -52
  183. package/dist/overlay/Command.svelte +340 -0
  184. package/dist/overlay/Command.svelte.d.ts +24 -25
  185. package/dist/overlay/Drawer.svelte +49 -21
  186. package/dist/overlay/Drawer.svelte.d.ts +2 -2
  187. package/dist/overlay/Dropdown.svelte +3 -3
  188. package/dist/overlay/Modal.svelte +51 -16
  189. package/dist/overlay/Modal.svelte.d.ts +3 -3
  190. package/dist/overlay/Toast.svelte +41 -17
  191. package/dist/overlay/Toast.svelte.d.ts +1 -1
  192. package/dist/overlay/Tooltip.svelte +40 -26
  193. package/dist/overlay/Tooltip.svelte.d.ts +2 -2
  194. package/dist/overlay/css/command.css +80 -0
  195. package/dist/overlay/css/drawer.css +63 -24
  196. package/dist/overlay/css/dropdown.css +1 -1
  197. package/dist/overlay/css/hovercard.css +1 -1
  198. package/dist/overlay/css/modal.css +27 -27
  199. package/dist/overlay/css/toast.css +17 -29
  200. package/dist/overlay/css/tooltip.css +83 -66
  201. package/dist/stores/theme.svelte.js +26 -1
  202. package/dist/stores/toast.svelte.d.ts +4 -4
  203. package/dist/stores/toast.svelte.js +2 -2
  204. package/package.json +1 -1
@@ -0,0 +1,543 @@
1
+ <script lang="ts">
2
+ import { cn } from '../utils/class-names.js';
3
+ import { onMount } from 'svelte';
4
+ import { Code } from '../index.js';
5
+
6
+ type Props = {
7
+ hex?: string;
8
+ rgb?: string;
9
+ cmyk?: string;
10
+ oklch?: string;
11
+ foreground?: string;
12
+ onHex?: (value: string) => void;
13
+ onRgb?: (value: string) => void;
14
+ onCmyk?: (value: string) => void;
15
+ onOklch?: (value: string) => void;
16
+ onForeground?: (value: string) => void;
17
+ showHex?: boolean;
18
+ showRgb?: boolean;
19
+ showCmyk?: boolean;
20
+ showOklch?: boolean;
21
+ color?: 'primary' | 'secondary' | 'muted' | 'success' | 'info' | 'danger' | 'warning';
22
+ variant?: 'solid' | 'soft' | 'outlined' | 'line';
23
+ size?: 'sm' | 'md' | 'lg';
24
+ name?: string;
25
+ rootClass?: string;
26
+ label?: string;
27
+ isFloatLabel?: boolean;
28
+ helpText?: string;
29
+ errorText?: string;
30
+ placeholder?: string;
31
+ };
32
+
33
+ let {
34
+ hex = $bindable('#3b82f6'),
35
+ rgb = $bindable('rgb(59, 130, 246)'),
36
+ cmyk = $bindable('cmyk(76%, 47%, 0%, 4%)'),
37
+ oklch = $bindable('oklch(0.62 0.21 255)'),
38
+ foreground = $bindable('#ffffff'),
39
+ onHex,
40
+ onRgb,
41
+ onCmyk,
42
+ onOklch,
43
+ onForeground,
44
+ showHex = false,
45
+ showRgb = false,
46
+ showCmyk = false,
47
+ showOklch = false,
48
+ variant = 'outlined',
49
+ color = 'muted',
50
+ size = 'md',
51
+ name,
52
+ rootClass,
53
+ label,
54
+ isFloatLabel,
55
+ helpText,
56
+ errorText,
57
+ placeholder = 'Select color'
58
+ }: Props = $props();
59
+
60
+ let isOpen = $state(false);
61
+ let controlElement = $state<HTMLElement>();
62
+ let popoverEl = $state<HTMLElement>();
63
+ let canvasEl = $state<HTMLCanvasElement>();
64
+ let hueSliderEl = $state<HTMLElement>();
65
+
66
+ let isActive = $state(false);
67
+ let isFocused = $state(false);
68
+
69
+ let hue = $state(220);
70
+ let saturation = $state(75);
71
+ let brightness = $state(96);
72
+ let alpha = $state(1);
73
+
74
+ let isDraggingCanvas = $state(false);
75
+ let isDraggingHue = $state(false);
76
+
77
+ let position = $state({
78
+ top: 0,
79
+ left: 0,
80
+ isBottomHalf: false
81
+ });
82
+
83
+ const style = $derived(
84
+ `top: ${position.top}px; left: ${position.left}px; transform-origin: ${position.isBottomHalf ? 'bottom' : 'top'} center;`
85
+ );
86
+
87
+ const colors = {
88
+ primary: 'is-primary',
89
+ secondary: 'is-secondary',
90
+ muted: 'is-muted',
91
+ success: 'is-success',
92
+ info: 'is-info',
93
+ danger: 'is-danger',
94
+ warning: 'is-warning'
95
+ };
96
+
97
+ const variants = {
98
+ solid: 'is-solid',
99
+ soft: 'is-soft',
100
+ outlined: 'is-outlined',
101
+ line: 'is-line'
102
+ };
103
+
104
+ const sizeClasses = {
105
+ sm: 'is-sm',
106
+ md: 'is-md',
107
+ lg: 'is-lg'
108
+ };
109
+
110
+ function hsvToRgb(h: number, s: number, v: number): [number, number, number] {
111
+ s /= 100;
112
+ v /= 100;
113
+ const c = v * s;
114
+ const x = c * (1 - Math.abs(((h / 60) % 2) - 1));
115
+ const m = v - c;
116
+
117
+ let r = 0,
118
+ g = 0,
119
+ b = 0;
120
+
121
+ if (h >= 0 && h < 60) {
122
+ r = c;
123
+ g = x;
124
+ b = 0;
125
+ } else if (h >= 60 && h < 120) {
126
+ r = x;
127
+ g = c;
128
+ b = 0;
129
+ } else if (h >= 120 && h < 180) {
130
+ r = 0;
131
+ g = c;
132
+ b = x;
133
+ } else if (h >= 180 && h < 240) {
134
+ r = 0;
135
+ g = x;
136
+ b = c;
137
+ } else if (h >= 240 && h < 300) {
138
+ r = x;
139
+ g = 0;
140
+ b = c;
141
+ } else {
142
+ r = c;
143
+ g = 0;
144
+ b = x;
145
+ }
146
+
147
+ return [Math.round((r + m) * 255), Math.round((g + m) * 255), Math.round((b + m) * 255)];
148
+ }
149
+
150
+ function rgbToHsv(r: number, g: number, b: number): [number, number, number] {
151
+ r /= 255;
152
+ g /= 255;
153
+ b /= 255;
154
+
155
+ const max = Math.max(r, g, b);
156
+ const min = Math.min(r, g, b);
157
+ const d = max - min;
158
+
159
+ let h = 0;
160
+ const s = max === 0 ? 0 : d / max;
161
+ const v = max;
162
+
163
+ if (d !== 0) {
164
+ switch (max) {
165
+ case r:
166
+ h = ((g - b) / d + (g < b ? 6 : 0)) * 60;
167
+ break;
168
+ case g:
169
+ h = ((b - r) / d + 2) * 60;
170
+ break;
171
+ case b:
172
+ h = ((r - g) / d + 4) * 60;
173
+ break;
174
+ }
175
+ }
176
+
177
+ return [Math.round(h), Math.round(s * 100), Math.round(v * 100)];
178
+ }
179
+
180
+ function rgbToHex(r: number, g: number, b: number): string {
181
+ return `#${[r, g, b].map((x) => x.toString(16).padStart(2, '0')).join('')}`;
182
+ }
183
+
184
+ function hexToRgb(hexColor: string): [number, number, number] | null {
185
+ const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hexColor);
186
+ return result
187
+ ? [parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16)]
188
+ : null;
189
+ }
190
+
191
+ function rgbToCmyk(r: number, g: number, b: number): [number, number, number, number] {
192
+ r /= 255;
193
+ g /= 255;
194
+ b /= 255;
195
+
196
+ const k = 1 - Math.max(r, g, b);
197
+ if (k === 1) return [0, 0, 0, 100];
198
+
199
+ const c = (1 - r - k) / (1 - k);
200
+ const m = (1 - g - k) / (1 - k);
201
+ const y = (1 - b - k) / (1 - k);
202
+
203
+ return [Math.round(c * 100), Math.round(m * 100), Math.round(y * 100), Math.round(k * 100)];
204
+ }
205
+
206
+ function rgbToOklch(r: number, g: number, b: number): [number, number, number] {
207
+ const linearize = (c: number) => {
208
+ c /= 255;
209
+ return c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
210
+ };
211
+
212
+ const lr = linearize(r);
213
+ const lg = linearize(g);
214
+ const lb = linearize(b);
215
+
216
+ const l_ = 0.4122214708 * lr + 0.5363325363 * lg + 0.0514459929 * lb;
217
+ const m_ = 0.2119034982 * lr + 0.6806995451 * lg + 0.1073969566 * lb;
218
+ const s_ = 0.0883024619 * lr + 0.2817188376 * lg + 0.6299787005 * lb;
219
+
220
+ const l = Math.cbrt(l_);
221
+ const m = Math.cbrt(m_);
222
+ const s = Math.cbrt(s_);
223
+
224
+ const L = 0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s;
225
+ const a = 1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s;
226
+ const bVal = 0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s;
227
+
228
+ const C = Math.sqrt(a * a + bVal * bVal);
229
+ let H = (Math.atan2(bVal, a) * 180) / Math.PI;
230
+ if (H < 0) H += 360;
231
+
232
+ return [parseFloat(L.toFixed(2)), parseFloat(C.toFixed(2)), Math.round(H)];
233
+ }
234
+
235
+ function getContrastColor(hexColor: string): string {
236
+ const rgbValues = hexToRgb(hexColor);
237
+ if (!rgbValues) return '#000000';
238
+
239
+ const [r, g, b] = rgbValues;
240
+ const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
241
+ return luminance > 0.5 ? '#000000' : '#ffffff';
242
+ }
243
+
244
+ function updateAllFormats() {
245
+ const [r, g, b] = hsvToRgb(hue, saturation, brightness);
246
+
247
+ hex = rgbToHex(r, g, b);
248
+ rgb = `rgb(${r}, ${g}, ${b})`;
249
+
250
+ const [c, m, y, k] = rgbToCmyk(r, g, b);
251
+ cmyk = `cmyk(${c}%, ${m}%, ${y}%, ${k}%)`;
252
+
253
+ const [l, ch, h] = rgbToOklch(r, g, b);
254
+ oklch = `oklch(${l} ${ch} ${h})`;
255
+
256
+ foreground = getContrastColor(hex);
257
+
258
+ onHex?.(hex);
259
+ onRgb?.(rgb);
260
+ onCmyk?.(cmyk);
261
+ onOklch?.(oklch);
262
+ onForeground?.(foreground);
263
+ }
264
+
265
+ function parseHexAndUpdateHsv(hexValue: string) {
266
+ const rgbValues = hexToRgb(hexValue);
267
+ if (rgbValues) {
268
+ const [r, g, b] = rgbValues;
269
+ const [h, s, v] = rgbToHsv(r, g, b);
270
+ hue = h;
271
+ saturation = s;
272
+ brightness = v;
273
+ }
274
+ }
275
+
276
+ function drawCanvas() {
277
+ if (!canvasEl) return;
278
+ const ctx = canvasEl.getContext('2d');
279
+ if (!ctx) return;
280
+
281
+ const width = canvasEl.width;
282
+ const height = canvasEl.height;
283
+
284
+ const baseColor = `hsl(${hue}, 100%, 50%)`;
285
+
286
+ const whiteGradient = ctx.createLinearGradient(0, 0, width, 0);
287
+ whiteGradient.addColorStop(0, 'white');
288
+ whiteGradient.addColorStop(1, baseColor);
289
+
290
+ ctx.fillStyle = whiteGradient;
291
+ ctx.fillRect(0, 0, width, height);
292
+
293
+ const blackGradient = ctx.createLinearGradient(0, 0, 0, height);
294
+ blackGradient.addColorStop(0, 'transparent');
295
+ blackGradient.addColorStop(1, 'black');
296
+
297
+ ctx.fillStyle = blackGradient;
298
+ ctx.fillRect(0, 0, width, height);
299
+ }
300
+
301
+ const updatePosition = () => {
302
+ if (!controlElement || !popoverEl) return;
303
+
304
+ const rect = controlElement.getBoundingClientRect();
305
+ const windowHeight = window.innerHeight;
306
+ const popoverHeight = popoverEl.getBoundingClientRect().height;
307
+ const isBottomHalf = rect.top + rect.height / 2 > windowHeight / 2;
308
+
309
+ const top = isBottomHalf ? rect.top - popoverHeight - 8 : rect.top + rect.height;
310
+ position = {
311
+ top: top,
312
+ left: rect.left + window.scrollX,
313
+ isBottomHalf
314
+ };
315
+ };
316
+
317
+ const togglePopover = () => {
318
+ if (!isOpen) {
319
+ parseHexAndUpdateHsv(hex);
320
+ startEventListeners();
321
+ updatePosition();
322
+ isOpen = true;
323
+ requestAnimationFrame(() => {
324
+ drawCanvas();
325
+ });
326
+ } else {
327
+ stopEventListeners();
328
+ isOpen = false;
329
+ }
330
+ };
331
+
332
+ const handleClickOutside = (event: Event) => {
333
+ if (
334
+ isOpen &&
335
+ !controlElement?.contains(event.target as Node) &&
336
+ !popoverEl?.contains(event.target as Node)
337
+ ) {
338
+ isOpen = false;
339
+ stopEventListeners();
340
+ }
341
+ };
342
+
343
+ const handleCanvasMouseDown = (event: MouseEvent) => {
344
+ isDraggingCanvas = true;
345
+ updateCanvasFromEvent(event);
346
+ };
347
+
348
+ const handleCanvasMouseMove = (event: MouseEvent) => {
349
+ if (!isDraggingCanvas) return;
350
+ updateCanvasFromEvent(event);
351
+ };
352
+
353
+ const handleCanvasMouseUp = () => {
354
+ isDraggingCanvas = false;
355
+ };
356
+
357
+ const updateCanvasFromEvent = (event: MouseEvent) => {
358
+ if (!canvasEl) return;
359
+ const rect = canvasEl.getBoundingClientRect();
360
+ const x = Math.max(0, Math.min(event.clientX - rect.left, rect.width));
361
+ const y = Math.max(0, Math.min(event.clientY - rect.top, rect.height));
362
+
363
+ saturation = Math.round((x / rect.width) * 100);
364
+ brightness = Math.round(100 - (y / rect.height) * 100);
365
+ updateAllFormats();
366
+ };
367
+
368
+ const handleHueMouseDown = (event: MouseEvent) => {
369
+ isDraggingHue = true;
370
+ updateHueFromEvent(event);
371
+ };
372
+
373
+ const handleHueMouseMove = (event: MouseEvent) => {
374
+ if (!isDraggingHue) return;
375
+ updateHueFromEvent(event);
376
+ };
377
+
378
+ const handleHueMouseUp = () => {
379
+ isDraggingHue = false;
380
+ };
381
+
382
+ const updateHueFromEvent = (event: MouseEvent) => {
383
+ if (!hueSliderEl) return;
384
+ const rect = hueSliderEl.getBoundingClientRect();
385
+ const x = Math.max(0, Math.min(event.clientX - rect.left, rect.width));
386
+ hue = Math.round((x / rect.width) * 360);
387
+ updateAllFormats();
388
+ drawCanvas();
389
+ };
390
+
391
+ const handleGlobalMouseUp = () => {
392
+ isDraggingCanvas = false;
393
+ isDraggingHue = false;
394
+ };
395
+
396
+ const handleGlobalMouseMove = (event: MouseEvent) => {
397
+ if (isDraggingCanvas) {
398
+ updateCanvasFromEvent(event);
399
+ } else if (isDraggingHue) {
400
+ updateHueFromEvent(event);
401
+ }
402
+ };
403
+
404
+ const startEventListeners = () => {
405
+ window.addEventListener('resize', updatePosition);
406
+ window.addEventListener('scroll', updatePosition, true);
407
+ document.addEventListener('click', handleClickOutside);
408
+ document.addEventListener('mouseup', handleGlobalMouseUp);
409
+ document.addEventListener('mousemove', handleGlobalMouseMove);
410
+ };
411
+
412
+ const stopEventListeners = () => {
413
+ window.removeEventListener('resize', updatePosition);
414
+ window.removeEventListener('scroll', updatePosition, true);
415
+ document.removeEventListener('click', handleClickOutside);
416
+ document.removeEventListener('mouseup', handleGlobalMouseUp);
417
+ document.removeEventListener('mousemove', handleGlobalMouseMove);
418
+ };
419
+
420
+ $effect(() => {
421
+ if (isOpen && canvasEl) {
422
+ drawCanvas();
423
+ }
424
+ });
425
+
426
+ onMount(() => {
427
+ parseHexAndUpdateHsv(hex);
428
+ updateAllFormats();
429
+ return () => stopEventListeners();
430
+ });
431
+
432
+ const cursorX = $derived((saturation / 100) * 100);
433
+ const cursorY = $derived(100 - (brightness / 100) * 100);
434
+ const hueThumbPosition = $derived((hue / 360) * 100);
435
+ </script>
436
+
437
+ <div class={cn('field', rootClass)}>
438
+ <input type="text" {name} bind:value={hex} hidden />
439
+
440
+ {#if !isFloatLabel && label}
441
+ <div class="field-label">{label}</div>
442
+ {/if}
443
+
444
+ <button
445
+ type="button"
446
+ bind:this={controlElement}
447
+ class={cn(
448
+ 'control',
449
+ colors[color],
450
+ variants[variant],
451
+ sizeClasses[size],
452
+ isFloatLabel && 'is-float',
453
+ (isActive || isFocused) && 'is-active'
454
+ )}
455
+ class:is-error={errorText}
456
+ onclick={togglePopover}
457
+ onmouseenter={() => (isActive = true)}
458
+ onmouseleave={() => (isActive = false)}
459
+ >
460
+ {#if isFloatLabel && label}
461
+ <span
462
+ class={cn('control-label', (isActive || isFocused || isOpen || hex !== '') && 'is-active')}
463
+ >
464
+ {label}
465
+ </span>
466
+ {/if}
467
+
468
+ <span class={cn('color-field-swatch', sizeClasses[size])} style="background-color: {hex};"
469
+ ></span>
470
+
471
+ <div class="control-selected">
472
+ {#if hex}
473
+ <span class="color-field-value">{hex}</span>
474
+ {:else if isFloatLabel}
475
+ {#if isActive || isOpen}
476
+ {placeholder}
477
+ {/if}
478
+ {:else}
479
+ {placeholder}
480
+ {/if}
481
+ </div>
482
+ </button>
483
+
484
+ {#if errorText || helpText}
485
+ <div class={cn('field-help', errorText && 'is-danger')}>{errorText || helpText}</div>
486
+ {/if}
487
+
488
+ <div class:is-active={isOpen} class="color-picker-popover" bind:this={popoverEl} {style}>
489
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
490
+ <div
491
+ class="color-picker-canvas-wrapper"
492
+ onmousedown={handleCanvasMouseDown}
493
+ onmousemove={handleCanvasMouseMove}
494
+ onmouseup={handleCanvasMouseUp}
495
+ >
496
+ <canvas bind:this={canvasEl} class="color-picker-canvas" width="240" height="140"></canvas>
497
+ <div
498
+ class="color-picker-cursor"
499
+ style="left: {cursorX}%; top: {cursorY}%; background-color: {hex};"
500
+ ></div>
501
+ </div>
502
+
503
+ <div class="color-picker-slider-wrapper">
504
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
505
+ <div
506
+ bind:this={hueSliderEl}
507
+ class="color-picker-slider color-picker-hue"
508
+ onmousedown={handleHueMouseDown}
509
+ onmousemove={handleHueMouseMove}
510
+ onmouseup={handleHueMouseUp}
511
+ >
512
+ <div class="color-picker-slider-thumb" style="left: {hueThumbPosition}%;"></div>
513
+ </div>
514
+ </div>
515
+
516
+ <div class="color-picker-preview">
517
+ <div class="color-picker-preview-swatch relative">
518
+ <div class="color-picker-preview-color" style="background-color: {hex};"></div>
519
+ </div>
520
+ <div class="color-picker-preview-info">
521
+ <span class="color-picker-preview-hex">{hex}</span>
522
+ <span class="color-picker-preview-foreground">Foreground: {foreground}</span>
523
+ </div>
524
+ </div>
525
+
526
+ {#if showHex || showRgb || showCmyk || showOklch}
527
+ <div class="color-picker-values">
528
+ {#if showHex}
529
+ <Code code={`hex: ${hex}`} copyContent={hex} lang="css" hideLang />
530
+ {/if}
531
+ {#if showRgb}
532
+ <Code code={`rgb: ${rgb}`} copyContent={rgb} lang="css" hideLang />
533
+ {/if}
534
+ {#if showCmyk}
535
+ <Code code={`cmyk: ${cmyk}`} copyContent={cmyk} lang="css" hideLang />
536
+ {/if}
537
+ {#if showOklch}
538
+ <Code code={`oklch: ${oklch}`} copyContent={oklch} lang="css" hideLang />
539
+ {/if}
540
+ </div>
541
+ {/if}
542
+ </div>
543
+ </div>
@@ -0,0 +1,29 @@
1
+ type Props = {
2
+ hex?: string;
3
+ rgb?: string;
4
+ cmyk?: string;
5
+ oklch?: string;
6
+ foreground?: string;
7
+ onHex?: (value: string) => void;
8
+ onRgb?: (value: string) => void;
9
+ onCmyk?: (value: string) => void;
10
+ onOklch?: (value: string) => void;
11
+ onForeground?: (value: string) => void;
12
+ showHex?: boolean;
13
+ showRgb?: boolean;
14
+ showCmyk?: boolean;
15
+ showOklch?: boolean;
16
+ color?: 'primary' | 'secondary' | 'muted' | 'success' | 'info' | 'danger' | 'warning';
17
+ variant?: 'solid' | 'soft' | 'outlined' | 'line';
18
+ size?: 'sm' | 'md' | 'lg';
19
+ name?: string;
20
+ rootClass?: string;
21
+ label?: string;
22
+ isFloatLabel?: boolean;
23
+ helpText?: string;
24
+ errorText?: string;
25
+ placeholder?: string;
26
+ };
27
+ declare const ColorField: import("svelte").Component<Props, {}, "hex" | "rgb" | "cmyk" | "oklch" | "foreground">;
28
+ type ColorField = ReturnType<typeof ColorField>;
29
+ export default ColorField;
@@ -20,7 +20,8 @@
20
20
  loadingText?: string;
21
21
  loadingMoreText?: string;
22
22
  onchange?: (value: string | number | null) => void;
23
- variant?: 'primary' | 'secondary' | 'muted' | 'outlined' | 'line';
23
+ color?: 'primary' | 'secondary' | 'muted' | 'success' | 'info' | 'danger' | 'warning';
24
+ variant?: 'solid' | 'soft' | 'outlined' | 'line';
24
25
  size?: 'sm' | 'md' | 'lg';
25
26
  name?: string;
26
27
  class?: string;
@@ -29,7 +30,6 @@
29
30
  helpText?: string;
30
31
  errorText?: string;
31
32
  isFloatLabel?: boolean;
32
- isSolid?: boolean;
33
33
  isClearable?: boolean;
34
34
  isDisabled?: boolean;
35
35
  arrowIcon?: IconData;
@@ -47,6 +47,7 @@
47
47
  loadingMoreText = 'Loading more...',
48
48
  onchange,
49
49
  variant = 'outlined',
50
+ color = 'muted',
50
51
  size = 'md',
51
52
  name,
52
53
  label,
@@ -54,16 +55,23 @@
54
55
  helpText,
55
56
  errorText,
56
57
  isFloatLabel,
57
- isSolid,
58
58
  isClearable = false,
59
59
  isDisabled = false,
60
60
  arrowIcon = ArrowDown24RegularIcon
61
61
  }: Props = $props();
62
-
63
- const variantClasses = {
62
+ const colors = {
64
63
  primary: 'is-primary',
65
64
  secondary: 'is-secondary',
66
65
  muted: 'is-muted',
66
+ success: 'is-success',
67
+ info: 'is-info',
68
+ danger: 'is-danger',
69
+ warning: 'is-warning'
70
+ };
71
+
72
+ const variants = {
73
+ solid: 'is-solid',
74
+ soft: 'is-soft',
67
75
  outlined: 'is-outlined',
68
76
  line: 'is-line'
69
77
  };
@@ -92,6 +100,7 @@
92
100
  let controlElement = $state<HTMLElement>();
93
101
  let contentEl = $state<HTMLElement>();
94
102
  let optionsEl = $state<HTMLElement>();
103
+ let searchInputEl = $state<HTMLInputElement>();
95
104
  let focusedIndex = $state(-1);
96
105
  let searchTerm = $state('');
97
106
  let searchTimeout: ReturnType<typeof setTimeout> | null = $state(null);
@@ -239,6 +248,7 @@
239
248
  if (isDisabled) return;
240
249
 
241
250
  if (!isOpen) {
251
+ search.setSearch('');
242
252
  startEventListeners();
243
253
  await initializeFocusedIndex();
244
254
  await scrollToSelectedItem();
@@ -246,6 +256,10 @@
246
256
  await updatePosition();
247
257
  isOpen = true;
248
258
  hasSearched = false;
259
+ await tick();
260
+ setTimeout(() => {
261
+ searchInputEl?.focus();
262
+ }, 100);
249
263
  } else {
250
264
  stopEventListeners();
251
265
  focusedIndex = -1;
@@ -335,10 +349,10 @@
335
349
  bind:this={controlElement}
336
350
  class={cn(
337
351
  'control',
338
- variantClasses[variant],
352
+ colors[color],
353
+ variants[variant],
339
354
  sizeClasses[size],
340
355
  isFloatLabel && 'is-float',
341
- isSolid && 'is-solid',
342
356
  (isActive || isFocused || isOpen) && 'is-active',
343
357
  isDisabled && 'opacity-50 cursor-not-allowed'
344
358
  )}
@@ -398,9 +412,10 @@
398
412
  {/if}
399
413
 
400
414
  <div class:is-active={isOpen} class="combo-box-popover" bind:this={contentEl} {style}>
401
- <div class={cn('combo-box-search', variantClasses[variant])}>
415
+ <div class={cn('combo-box-search', colors[color], variants[variant])}>
402
416
  <Icon icon={Search24RegularIcon} class="combo-box-search-icon" />
403
417
  <input
418
+ bind:this={searchInputEl}
404
419
  type="text"
405
420
  class="combo-box-search-input"
406
421
  placeholder={searchPlaceholder}
@@ -429,7 +444,7 @@
429
444
  isActive={value === item.id}
430
445
  isFocused={focusedIndex === index}
431
446
  isDisabled={item.disabled}
432
- variant={itemVariants[variant]}
447
+ {color}
433
448
  size="sm"
434
449
  isCompact
435
450
  />
@@ -10,7 +10,8 @@ type Props = {
10
10
  loadingText?: string;
11
11
  loadingMoreText?: string;
12
12
  onchange?: (value: string | number | null) => void;
13
- variant?: 'primary' | 'secondary' | 'muted' | 'outlined' | 'line';
13
+ color?: 'primary' | 'secondary' | 'muted' | 'success' | 'info' | 'danger' | 'warning';
14
+ variant?: 'solid' | 'soft' | 'outlined' | 'line';
14
15
  size?: 'sm' | 'md' | 'lg';
15
16
  name?: string;
16
17
  class?: string;
@@ -19,7 +20,6 @@ type Props = {
19
20
  helpText?: string;
20
21
  errorText?: string;
21
22
  isFloatLabel?: boolean;
22
- isSolid?: boolean;
23
23
  isClearable?: boolean;
24
24
  isDisabled?: boolean;
25
25
  arrowIcon?: IconData;