ui-svelte 0.2.11 → 0.2.13

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 (225) hide show
  1. package/README.md +2 -2
  2. package/dist/charts/ArcChart.svelte +9 -14
  3. package/dist/charts/ArcChart.svelte.d.ts +3 -3
  4. package/dist/charts/AreaChart.svelte +347 -118
  5. package/dist/charts/AreaChart.svelte.d.ts +33 -4
  6. package/dist/charts/BarChart.svelte +288 -66
  7. package/dist/charts/BarChart.svelte.d.ts +26 -1
  8. package/dist/charts/Candlestick.svelte +53 -50
  9. package/dist/charts/Candlestick.svelte.d.ts +8 -8
  10. package/dist/charts/LineChart.svelte +391 -91
  11. package/dist/charts/LineChart.svelte.d.ts +26 -3
  12. package/dist/charts/PieChart.svelte +333 -92
  13. package/dist/charts/PieChart.svelte.d.ts +33 -5
  14. package/dist/charts/css/arc-chart.css +3 -3
  15. package/dist/charts/css/area-chart.css +127 -29
  16. package/dist/charts/css/bar-chart.css +114 -8
  17. package/dist/charts/css/candlestick.css +2 -0
  18. package/dist/charts/css/line-chart.css +111 -13
  19. package/dist/charts/css/pie-chart.css +92 -20
  20. package/dist/control/Audio.svelte +86 -44
  21. package/dist/control/Audio.svelte.d.ts +4 -1
  22. package/dist/control/Button.svelte +18 -27
  23. package/dist/control/Button.svelte.d.ts +3 -2
  24. package/dist/control/Fab.svelte +103 -0
  25. package/dist/control/Fab.svelte.d.ts +25 -0
  26. package/dist/control/IconButton.svelte +17 -27
  27. package/dist/control/IconButton.svelte.d.ts +3 -3
  28. package/dist/control/Image.svelte +123 -0
  29. package/dist/control/Image.svelte.d.ts +13 -0
  30. package/dist/control/Record.svelte +141 -98
  31. package/dist/control/Record.svelte.d.ts +2 -1
  32. package/dist/control/ToggleGroup.svelte +22 -8
  33. package/dist/control/ToggleGroup.svelte.d.ts +2 -1
  34. package/dist/control/ToggleTheme.svelte +13 -11
  35. package/dist/control/ToggleTheme.svelte.d.ts +3 -2
  36. package/dist/control/Video.svelte +57 -29
  37. package/dist/control/Video.svelte.d.ts +1 -0
  38. package/dist/control/css/btn.css +200 -152
  39. package/dist/control/css/fab.css +84 -0
  40. package/dist/control/css/image.css +56 -0
  41. package/dist/control/css/media.css +95 -30
  42. package/dist/control/css/toggle-group.css +253 -84
  43. package/dist/control/css/video.css +1 -14
  44. package/dist/css/animations.css +5 -9
  45. package/dist/css/base.css +13 -347
  46. package/dist/css/decorations.css +561 -0
  47. package/dist/css/rich-text.css +485 -0
  48. package/dist/css/transitions.css +158 -0
  49. package/dist/css/typography.css +291 -0
  50. package/dist/css/utilities.css +0 -4
  51. package/dist/display/Accordion.svelte +28 -4
  52. package/dist/display/Accordion.svelte.d.ts +2 -1
  53. package/dist/display/Alert.svelte +32 -12
  54. package/dist/display/Alert.svelte.d.ts +2 -3
  55. package/dist/display/Avatar.svelte +23 -18
  56. package/dist/display/Avatar.svelte.d.ts +4 -1
  57. package/dist/display/AvatarGroup.svelte +20 -18
  58. package/dist/display/AvatarGroup.svelte.d.ts +6 -3
  59. package/dist/display/Badge.svelte +11 -4
  60. package/dist/display/Badge.svelte.d.ts +2 -1
  61. package/dist/display/Card.svelte +15 -14
  62. package/dist/display/Card.svelte.d.ts +2 -3
  63. package/dist/display/Carousel.svelte +130 -99
  64. package/dist/display/Carousel.svelte.d.ts +6 -4
  65. package/dist/display/ChatBox.svelte +245 -106
  66. package/dist/display/ChatBox.svelte.d.ts +32 -5
  67. package/dist/display/Chip.svelte +31 -17
  68. package/dist/display/Chip.svelte.d.ts +3 -2
  69. package/dist/display/Code.svelte +7 -4
  70. package/dist/display/Code.svelte.d.ts +1 -0
  71. package/dist/display/Collapsible.svelte +30 -4
  72. package/dist/display/Collapsible.svelte.d.ts +2 -1
  73. package/dist/display/Countdown.svelte +169 -0
  74. package/dist/display/Countdown.svelte.d.ts +21 -0
  75. package/dist/display/Empty.svelte +37 -3
  76. package/dist/display/Empty.svelte.d.ts +3 -0
  77. package/dist/display/Item.svelte +42 -11
  78. package/dist/display/Item.svelte.d.ts +4 -2
  79. package/dist/display/Map.svelte +488 -0
  80. package/dist/display/Map.svelte.d.ts +44 -0
  81. package/dist/display/Marquee.svelte +0 -2
  82. package/dist/display/Section.svelte +14 -12
  83. package/dist/display/Section.svelte.d.ts +2 -3
  84. package/dist/display/Skeleton.svelte +32 -0
  85. package/dist/display/Skeleton.svelte.d.ts +10 -0
  86. package/dist/display/Table.svelte +94 -132
  87. package/dist/display/Table.svelte.d.ts +10 -1
  88. package/dist/display/css/accordion.css +349 -52
  89. package/dist/display/css/alert.css +38 -18
  90. package/dist/display/css/avatar-group.css +38 -75
  91. package/dist/display/css/avatar.css +139 -121
  92. package/dist/display/css/badge.css +50 -27
  93. package/dist/display/css/card.css +123 -71
  94. package/dist/display/css/carousel.css +25 -5
  95. package/dist/display/css/chat-box.css +158 -26
  96. package/dist/display/css/chip.css +142 -68
  97. package/dist/display/css/code.css +2 -6
  98. package/dist/display/css/collapsible.css +349 -45
  99. package/dist/display/css/countdown.css +206 -0
  100. package/dist/display/css/divider.css +8 -6
  101. package/dist/display/css/empty.css +7 -0
  102. package/dist/display/css/item.css +330 -84
  103. package/dist/display/css/map.css +164 -0
  104. package/dist/display/css/marquee.css +0 -3
  105. package/dist/display/css/section.css +89 -65
  106. package/dist/display/css/skeleton.css +58 -0
  107. package/dist/display/css/table.css +309 -193
  108. package/dist/form/Checkbox.svelte +11 -5
  109. package/dist/form/Checkbox.svelte.d.ts +2 -1
  110. package/dist/form/ColorField.svelte +601 -0
  111. package/dist/form/ColorField.svelte.d.ts +29 -0
  112. package/dist/form/ComboBox.svelte +24 -9
  113. package/dist/form/ComboBox.svelte.d.ts +2 -2
  114. package/dist/form/CsvField.svelte +62 -136
  115. package/dist/form/CsvField.svelte.d.ts +2 -2
  116. package/dist/form/DateField.svelte +33 -15
  117. package/dist/form/DateField.svelte.d.ts +2 -1
  118. package/dist/form/DateRange.svelte +436 -0
  119. package/dist/form/DateRange.svelte.d.ts +24 -0
  120. package/dist/form/DragDrop.svelte +578 -0
  121. package/dist/form/DragDrop.svelte.d.ts +33 -0
  122. package/dist/form/Dropzone.svelte +28 -8
  123. package/dist/form/Dropzone.svelte.d.ts +2 -2
  124. package/dist/form/Editor.svelte +626 -0
  125. package/dist/form/Editor.svelte.d.ts +50 -0
  126. package/dist/form/ImageCropper.svelte +422 -61
  127. package/dist/form/ImageCropper.svelte.d.ts +15 -1
  128. package/dist/form/{PasswordStrength.svelte → PasswordField.svelte} +58 -24
  129. package/dist/form/{PasswordStrength.svelte.d.ts → PasswordField.svelte.d.ts} +6 -5
  130. package/dist/form/PhoneField.svelte +26 -14
  131. package/dist/form/PhoneField.svelte.d.ts +4 -3
  132. package/dist/form/PinField.svelte +39 -31
  133. package/dist/form/PinField.svelte.d.ts +3 -3
  134. package/dist/form/RadioGroup.svelte +9 -5
  135. package/dist/form/RadioGroup.svelte.d.ts +1 -1
  136. package/dist/form/Select.svelte +20 -19
  137. package/dist/form/Select.svelte.d.ts +2 -2
  138. package/dist/form/Slider.svelte +10 -4
  139. package/dist/form/Slider.svelte.d.ts +2 -1
  140. package/dist/form/TextField.svelte +29 -11
  141. package/dist/form/TextField.svelte.d.ts +5 -4
  142. package/dist/form/Textarea.svelte +15 -6
  143. package/dist/form/Textarea.svelte.d.ts +2 -2
  144. package/dist/form/Toggle.svelte +7 -3
  145. package/dist/form/Toggle.svelte.d.ts +1 -1
  146. package/dist/form/css/checkbox.css +18 -2
  147. package/dist/form/css/color-field.css +141 -0
  148. package/dist/form/css/control.css +193 -82
  149. package/dist/form/css/csv-field.css +221 -0
  150. package/dist/form/css/date-range.css +122 -0
  151. package/dist/form/css/date.css +24 -2
  152. package/dist/form/css/drag-drop.css +234 -0
  153. package/dist/form/css/dropzone.css +153 -34
  154. package/dist/form/css/editor.css +367 -0
  155. package/dist/form/css/field.css +4 -0
  156. package/dist/form/css/image-cropper.css +242 -20
  157. package/dist/form/css/radio-group.css +26 -1
  158. package/dist/form/css/select.css +2 -2
  159. package/dist/form/css/slider.css +37 -0
  160. package/dist/form/css/textarea.css +178 -75
  161. package/dist/form/css/toggle.css +15 -3
  162. package/dist/hooks/use-chat.svelte.js +1 -1
  163. package/dist/hooks/use-form.svelte.js +3 -3
  164. package/dist/hooks/use-search.svelte.js +0 -3
  165. package/dist/hooks/use-table.svelte.d.ts +1 -0
  166. package/dist/hooks/use-table.svelte.js +6 -0
  167. package/dist/icons/index.d.ts +34 -2
  168. package/dist/icons/index.js +36 -4
  169. package/dist/index.css +44 -49
  170. package/dist/index.d.ts +14 -4
  171. package/dist/index.js +13 -3
  172. package/dist/layout/AppBar.svelte +22 -14
  173. package/dist/layout/AppBar.svelte.d.ts +2 -1
  174. package/dist/layout/Footer.svelte +19 -11
  175. package/dist/layout/Footer.svelte.d.ts +2 -1
  176. package/dist/layout/Provider.svelte +32 -9
  177. package/dist/layout/Provider.svelte.d.ts +3 -1
  178. package/dist/layout/Sidebar.svelte +17 -8
  179. package/dist/layout/Sidebar.svelte.d.ts +2 -1
  180. package/dist/layout/css/app-bar.css +63 -66
  181. package/dist/layout/css/footer.css +62 -65
  182. package/dist/layout/css/sidebar.css +120 -59
  183. package/dist/navigation/BottomNav.svelte +51 -14
  184. package/dist/navigation/FooterGroup.svelte +1 -1
  185. package/dist/navigation/NavMenu.svelte +47 -23
  186. package/dist/navigation/NavMenu.svelte.d.ts +29 -0
  187. package/dist/navigation/Pagination.svelte +158 -0
  188. package/dist/navigation/Pagination.svelte.d.ts +18 -0
  189. package/dist/navigation/SideNav.svelte +30 -25
  190. package/dist/navigation/SideNav.svelte.d.ts +2 -3
  191. package/dist/navigation/Tabs.svelte +17 -7
  192. package/dist/navigation/Tabs.svelte.d.ts +2 -2
  193. package/dist/navigation/css/bottom-nav.css +319 -257
  194. package/dist/navigation/css/footer-group.css +1 -1
  195. package/dist/navigation/css/footer-nav.css +1 -1
  196. package/dist/navigation/css/nav-menu.css +331 -106
  197. package/dist/navigation/css/pagination.css +74 -0
  198. package/dist/navigation/css/side-nav.css +514 -75
  199. package/dist/navigation/css/tabs.css +246 -52
  200. package/dist/overlay/AlertDialog.svelte +58 -0
  201. package/dist/overlay/AlertDialog.svelte.d.ts +14 -25
  202. package/dist/overlay/Command.svelte +347 -0
  203. package/dist/overlay/Command.svelte.d.ts +33 -25
  204. package/dist/overlay/Drawer.svelte +49 -21
  205. package/dist/overlay/Drawer.svelte.d.ts +2 -2
  206. package/dist/overlay/Dropdown.svelte +3 -3
  207. package/dist/overlay/Modal.svelte +51 -16
  208. package/dist/overlay/Modal.svelte.d.ts +3 -3
  209. package/dist/overlay/Toast.svelte +41 -17
  210. package/dist/overlay/Toast.svelte.d.ts +1 -1
  211. package/dist/overlay/Tooltip.svelte +36 -27
  212. package/dist/overlay/Tooltip.svelte.d.ts +2 -2
  213. package/dist/overlay/css/command.css +68 -0
  214. package/dist/overlay/css/drawer.css +63 -24
  215. package/dist/overlay/css/dropdown.css +1 -1
  216. package/dist/overlay/css/hovercard.css +1 -1
  217. package/dist/overlay/css/modal.css +79 -27
  218. package/dist/overlay/css/toast.css +40 -24
  219. package/dist/overlay/css/tooltip.css +110 -67
  220. package/dist/stores/theme.svelte.js +44 -12
  221. package/dist/stores/toast.svelte.d.ts +4 -4
  222. package/dist/stores/toast.svelte.js +2 -2
  223. package/package.json +1 -1
  224. package/dist/utils/charts.d.ts +0 -27
  225. package/dist/utils/charts.js +0 -140
@@ -0,0 +1,601 @@
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 oklchToRgb(l: number, c: number, h: number): [number, number, number] {
236
+ const hRad = (h * Math.PI) / 180;
237
+ const a = c * Math.cos(hRad);
238
+ const b = c * Math.sin(hRad);
239
+
240
+ const l_ = l + 0.3963377774 * a + 0.2158037573 * b;
241
+ const m_ = l - 0.1055613458 * a - 0.0638541728 * b;
242
+ const s_ = l - 0.0894841775 * a - 1.291485548 * b;
243
+
244
+ const l3 = l_ * l_ * l_;
245
+ const m3 = m_ * m_ * m_;
246
+ const s3 = s_ * s_ * s_;
247
+
248
+ const lr = 4.0767416621 * l3 - 3.3077115913 * m3 + 0.2309699292 * s3;
249
+ const lg = -1.2684380046 * l3 + 2.6097574011 * m3 - 0.3413193965 * s3;
250
+ const lb = -0.0041960863 * l3 - 0.7034186147 * m3 + 1.707614701 * s3;
251
+
252
+ const gammaCorrect = (c: number) => {
253
+ if (c <= 0.0031308) return c * 12.92;
254
+ return 1.055 * Math.pow(c, 1 / 2.4) - 0.055;
255
+ };
256
+
257
+ const r = Math.max(0, Math.min(255, Math.round(gammaCorrect(lr) * 255)));
258
+ const g = Math.max(0, Math.min(255, Math.round(gammaCorrect(lg) * 255)));
259
+ const bVal = Math.max(0, Math.min(255, Math.round(gammaCorrect(lb) * 255)));
260
+
261
+ return [r, g, bVal];
262
+ }
263
+
264
+ function parseOklchString(oklchStr: string): [number, number, number] | null {
265
+ const match = oklchStr.match(/oklch\(([\d.]+)%?\s+([\d.]+)\s+([\d.]+)\)/);
266
+ if (!match) return null;
267
+ let l = parseFloat(match[1]);
268
+ if (l > 1) l = l / 100;
269
+ const c = parseFloat(match[2]);
270
+ const h = parseFloat(match[3]);
271
+ return [l, c, h];
272
+ }
273
+
274
+ function parseOklchAndUpdateHsv(oklchStr: string) {
275
+ const parsed = parseOklchString(oklchStr);
276
+ if (parsed) {
277
+ const [l, c, h] = parsed;
278
+ const [r, g, b] = oklchToRgb(l, c, h);
279
+ const [hsvH, hsvS, hsvV] = rgbToHsv(r, g, b);
280
+ hue = hsvH;
281
+ saturation = hsvS;
282
+ brightness = hsvV;
283
+ return true;
284
+ }
285
+ return false;
286
+ }
287
+
288
+ function getContrastColor(hexColor: string): string {
289
+ const rgbValues = hexToRgb(hexColor);
290
+ if (!rgbValues) return '#000000';
291
+
292
+ const [r, g, b] = rgbValues;
293
+ const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
294
+ return luminance > 0.5 ? '#000000' : '#ffffff';
295
+ }
296
+
297
+ function updateAllFormats() {
298
+ const [r, g, b] = hsvToRgb(hue, saturation, brightness);
299
+
300
+ hex = rgbToHex(r, g, b);
301
+ rgb = `rgb(${r}, ${g}, ${b})`;
302
+
303
+ const [c, m, y, k] = rgbToCmyk(r, g, b);
304
+ cmyk = `cmyk(${c}%, ${m}%, ${y}%, ${k}%)`;
305
+
306
+ const [l, ch, h] = rgbToOklch(r, g, b);
307
+ oklch = `oklch(${l} ${ch} ${h})`;
308
+
309
+ foreground = getContrastColor(hex);
310
+
311
+ onHex?.(hex);
312
+ onRgb?.(rgb);
313
+ onCmyk?.(cmyk);
314
+ onOklch?.(oklch);
315
+ onForeground?.(foreground);
316
+ }
317
+
318
+ function parseHexAndUpdateHsv(hexValue: string) {
319
+ const rgbValues = hexToRgb(hexValue);
320
+ if (rgbValues) {
321
+ const [r, g, b] = rgbValues;
322
+ const [h, s, v] = rgbToHsv(r, g, b);
323
+ hue = h;
324
+ saturation = s;
325
+ brightness = v;
326
+ }
327
+ }
328
+
329
+ function drawCanvas() {
330
+ if (!canvasEl) return;
331
+ const ctx = canvasEl.getContext('2d');
332
+ if (!ctx) return;
333
+
334
+ const width = canvasEl.width;
335
+ const height = canvasEl.height;
336
+
337
+ const baseColor = `hsl(${hue}, 100%, 50%)`;
338
+
339
+ const whiteGradient = ctx.createLinearGradient(0, 0, width, 0);
340
+ whiteGradient.addColorStop(0, 'white');
341
+ whiteGradient.addColorStop(1, baseColor);
342
+
343
+ ctx.fillStyle = whiteGradient;
344
+ ctx.fillRect(0, 0, width, height);
345
+
346
+ const blackGradient = ctx.createLinearGradient(0, 0, 0, height);
347
+ blackGradient.addColorStop(0, 'transparent');
348
+ blackGradient.addColorStop(1, 'black');
349
+
350
+ ctx.fillStyle = blackGradient;
351
+ ctx.fillRect(0, 0, width, height);
352
+ }
353
+
354
+ const updatePosition = () => {
355
+ if (!controlElement || !popoverEl) return;
356
+
357
+ const rect = controlElement.getBoundingClientRect();
358
+ const windowHeight = window.innerHeight;
359
+ const popoverHeight = popoverEl.getBoundingClientRect().height;
360
+ const isBottomHalf = rect.top + rect.height / 2 > windowHeight / 2;
361
+
362
+ const top = isBottomHalf ? rect.top - popoverHeight - 8 : rect.top + rect.height;
363
+ position = {
364
+ top: top,
365
+ left: rect.left + window.scrollX,
366
+ isBottomHalf
367
+ };
368
+ };
369
+
370
+ const togglePopover = () => {
371
+ if (!isOpen) {
372
+ parseHexAndUpdateHsv(hex);
373
+ startEventListeners();
374
+ updatePosition();
375
+ isOpen = true;
376
+ requestAnimationFrame(() => {
377
+ drawCanvas();
378
+ });
379
+ } else {
380
+ stopEventListeners();
381
+ isOpen = false;
382
+ }
383
+ };
384
+
385
+ const handleClickOutside = (event: Event) => {
386
+ if (
387
+ isOpen &&
388
+ !controlElement?.contains(event.target as Node) &&
389
+ !popoverEl?.contains(event.target as Node)
390
+ ) {
391
+ isOpen = false;
392
+ stopEventListeners();
393
+ }
394
+ };
395
+
396
+ const handleCanvasMouseDown = (event: MouseEvent) => {
397
+ isDraggingCanvas = true;
398
+ updateCanvasFromEvent(event);
399
+ };
400
+
401
+ const handleCanvasMouseMove = (event: MouseEvent) => {
402
+ if (!isDraggingCanvas) return;
403
+ updateCanvasFromEvent(event);
404
+ };
405
+
406
+ const handleCanvasMouseUp = () => {
407
+ isDraggingCanvas = false;
408
+ };
409
+
410
+ const updateCanvasFromEvent = (event: MouseEvent) => {
411
+ if (!canvasEl) return;
412
+ const rect = canvasEl.getBoundingClientRect();
413
+ const x = Math.max(0, Math.min(event.clientX - rect.left, rect.width));
414
+ const y = Math.max(0, Math.min(event.clientY - rect.top, rect.height));
415
+
416
+ saturation = Math.round((x / rect.width) * 100);
417
+ brightness = Math.round(100 - (y / rect.height) * 100);
418
+ updateAllFormats();
419
+ };
420
+
421
+ const handleHueMouseDown = (event: MouseEvent) => {
422
+ isDraggingHue = true;
423
+ updateHueFromEvent(event);
424
+ };
425
+
426
+ const handleHueMouseMove = (event: MouseEvent) => {
427
+ if (!isDraggingHue) return;
428
+ updateHueFromEvent(event);
429
+ };
430
+
431
+ const handleHueMouseUp = () => {
432
+ isDraggingHue = false;
433
+ };
434
+
435
+ const updateHueFromEvent = (event: MouseEvent) => {
436
+ if (!hueSliderEl) return;
437
+ const rect = hueSliderEl.getBoundingClientRect();
438
+ const x = Math.max(0, Math.min(event.clientX - rect.left, rect.width));
439
+ hue = Math.round((x / rect.width) * 360);
440
+ updateAllFormats();
441
+ drawCanvas();
442
+ };
443
+
444
+ const handleGlobalMouseUp = () => {
445
+ isDraggingCanvas = false;
446
+ isDraggingHue = false;
447
+ };
448
+
449
+ const handleGlobalMouseMove = (event: MouseEvent) => {
450
+ if (isDraggingCanvas) {
451
+ updateCanvasFromEvent(event);
452
+ } else if (isDraggingHue) {
453
+ updateHueFromEvent(event);
454
+ }
455
+ };
456
+
457
+ const startEventListeners = () => {
458
+ window.addEventListener('resize', updatePosition);
459
+ window.addEventListener('scroll', updatePosition, true);
460
+ document.addEventListener('click', handleClickOutside);
461
+ document.addEventListener('mouseup', handleGlobalMouseUp);
462
+ document.addEventListener('mousemove', handleGlobalMouseMove);
463
+ };
464
+
465
+ const stopEventListeners = () => {
466
+ window.removeEventListener('resize', updatePosition);
467
+ window.removeEventListener('scroll', updatePosition, true);
468
+ document.removeEventListener('click', handleClickOutside);
469
+ document.removeEventListener('mouseup', handleGlobalMouseUp);
470
+ document.removeEventListener('mousemove', handleGlobalMouseMove);
471
+ };
472
+
473
+ $effect(() => {
474
+ if (isOpen && canvasEl) {
475
+ drawCanvas();
476
+ }
477
+ });
478
+
479
+ onMount(() => {
480
+ if (oklch && oklch.startsWith('oklch(')) {
481
+ parseOklchAndUpdateHsv(oklch);
482
+ updateAllFormats();
483
+ } else if (hex && hex.startsWith('#')) {
484
+ parseHexAndUpdateHsv(hex);
485
+ updateAllFormats();
486
+ }
487
+ return () => stopEventListeners();
488
+ });
489
+
490
+ const cursorX = $derived((saturation / 100) * 100);
491
+ const cursorY = $derived(100 - (brightness / 100) * 100);
492
+ const hueThumbPosition = $derived((hue / 360) * 100);
493
+ </script>
494
+
495
+ <div class={cn('field', rootClass)}>
496
+ <input type="text" {name} bind:value={hex} hidden />
497
+
498
+ {#if !isFloatLabel && label}
499
+ <div class="field-label">{label}</div>
500
+ {/if}
501
+
502
+ <button
503
+ type="button"
504
+ bind:this={controlElement}
505
+ class={cn(
506
+ 'control',
507
+ colors[color],
508
+ variants[variant],
509
+ sizeClasses[size],
510
+ isFloatLabel && 'is-float',
511
+ (isActive || isFocused) && 'is-active'
512
+ )}
513
+ class:is-error={errorText}
514
+ onclick={togglePopover}
515
+ onmouseenter={() => (isActive = true)}
516
+ onmouseleave={() => (isActive = false)}
517
+ >
518
+ {#if isFloatLabel && label}
519
+ <span
520
+ class={cn('control-label', (isActive || isFocused || isOpen || hex !== '') && 'is-active')}
521
+ >
522
+ {label}
523
+ </span>
524
+ {/if}
525
+
526
+ <span class={cn('color-field-swatch', sizeClasses[size])} style="background-color: {hex};"
527
+ ></span>
528
+
529
+ <div class="control-selected">
530
+ {#if hex}
531
+ <span class="color-field-value">{hex}</span>
532
+ {:else if isFloatLabel}
533
+ {#if isActive || isOpen}
534
+ {placeholder}
535
+ {/if}
536
+ {:else}
537
+ {placeholder}
538
+ {/if}
539
+ </div>
540
+ </button>
541
+
542
+ {#if errorText || helpText}
543
+ <div class={cn('field-help', errorText && 'is-danger')}>{errorText || helpText}</div>
544
+ {/if}
545
+
546
+ <div class:is-active={isOpen} class="color-picker-popover" bind:this={popoverEl} {style}>
547
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
548
+ <div
549
+ class="color-picker-canvas-wrapper"
550
+ onmousedown={handleCanvasMouseDown}
551
+ onmousemove={handleCanvasMouseMove}
552
+ onmouseup={handleCanvasMouseUp}
553
+ >
554
+ <canvas bind:this={canvasEl} class="color-picker-canvas" width="240" height="140"></canvas>
555
+ <div
556
+ class="color-picker-cursor"
557
+ style="left: {cursorX}%; top: {cursorY}%; background-color: {hex};"
558
+ ></div>
559
+ </div>
560
+
561
+ <div class="color-picker-slider-wrapper">
562
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
563
+ <div
564
+ bind:this={hueSliderEl}
565
+ class="color-picker-slider color-picker-hue"
566
+ onmousedown={handleHueMouseDown}
567
+ onmousemove={handleHueMouseMove}
568
+ onmouseup={handleHueMouseUp}
569
+ >
570
+ <div class="color-picker-slider-thumb" style="left: {hueThumbPosition}%;"></div>
571
+ </div>
572
+ </div>
573
+
574
+ <div class="color-picker-preview">
575
+ <div class="color-picker-preview-swatch relative">
576
+ <div class="color-picker-preview-color" style="background-color: {hex};"></div>
577
+ </div>
578
+ <div class="color-picker-preview-info">
579
+ <span class="color-picker-preview-hex">{hex}</span>
580
+ <span class="color-picker-preview-foreground">Foreground: {foreground}</span>
581
+ </div>
582
+ </div>
583
+
584
+ {#if showHex || showRgb || showCmyk || showOklch}
585
+ <div class="color-picker-values">
586
+ {#if showHex}
587
+ <Code code={`hex: ${hex}`} copyContent={hex} lang="css" hideLang />
588
+ {/if}
589
+ {#if showRgb}
590
+ <Code code={`rgb: ${rgb}`} copyContent={rgb} lang="css" hideLang />
591
+ {/if}
592
+ {#if showCmyk}
593
+ <Code code={`cmyk: ${cmyk}`} copyContent={cmyk} lang="css" hideLang />
594
+ {/if}
595
+ {#if showOklch}
596
+ <Code code={`oklch: ${oklch}`} copyContent={oklch} lang="css" hideLang />
597
+ {/if}
598
+ </div>
599
+ {/if}
600
+ </div>
601
+ </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;