polymorph-ui-components 0.1.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 (242) hide show
  1. package/README.md +354 -0
  2. package/dist/Accordion/Accordion.svelte +28 -0
  3. package/dist/Accordion/Accordion.svelte.d.ts +4 -0
  4. package/dist/Accordion/properties.d.ts +7 -0
  5. package/dist/Accordion/properties.js +1 -0
  6. package/dist/Animations/ModalAnimation.svelte +55 -0
  7. package/dist/Animations/ModalAnimation.svelte.d.ts +12 -0
  8. package/dist/Animations/OverlayAnimation.svelte +14 -0
  9. package/dist/Animations/OverlayAnimation.svelte.d.ts +7 -0
  10. package/dist/Avatar/Avatar.svelte +122 -0
  11. package/dist/Avatar/Avatar.svelte.d.ts +4 -0
  12. package/dist/Avatar/properties.d.ts +15 -0
  13. package/dist/Avatar/properties.js +1 -0
  14. package/dist/Badge/Badge.svelte +53 -0
  15. package/dist/Badge/Badge.svelte.d.ts +4 -0
  16. package/dist/Badge/properties.d.ts +6 -0
  17. package/dist/Badge/properties.js +1 -0
  18. package/dist/Banner/Banner.svelte +158 -0
  19. package/dist/Banner/Banner.svelte.d.ts +4 -0
  20. package/dist/Banner/properties.d.ts +19 -0
  21. package/dist/Banner/properties.js +1 -0
  22. package/dist/Book/Book.svelte +281 -0
  23. package/dist/Book/Book.svelte.d.ts +4 -0
  24. package/dist/Book/properties.d.ts +24 -0
  25. package/dist/Book/properties.js +1 -0
  26. package/dist/Browser/Browser.svelte +176 -0
  27. package/dist/Browser/Browser.svelte.d.ts +3 -0
  28. package/dist/Browser/properties.d.ts +14 -0
  29. package/dist/Browser/properties.js +1 -0
  30. package/dist/Button/Button.svelte +153 -0
  31. package/dist/Button/Button.svelte.d.ts +4 -0
  32. package/dist/Button/properties.d.ts +24 -0
  33. package/dist/Button/properties.js +1 -0
  34. package/dist/Calendar/Calendar.svelte +477 -0
  35. package/dist/Calendar/Calendar.svelte.d.ts +4 -0
  36. package/dist/Calendar/properties.d.ts +30 -0
  37. package/dist/Calendar/properties.js +1 -0
  38. package/dist/Carousel/Carousel.svelte +258 -0
  39. package/dist/Carousel/Carousel.svelte.d.ts +4 -0
  40. package/dist/Carousel/properties.d.ts +20 -0
  41. package/dist/Carousel/properties.js +1 -0
  42. package/dist/CheckListItem/CheckListItem.svelte +65 -0
  43. package/dist/CheckListItem/CheckListItem.svelte.d.ts +4 -0
  44. package/dist/CheckListItem/properties.d.ts +15 -0
  45. package/dist/CheckListItem/properties.js +1 -0
  46. package/dist/Checkbox/Checkbox.svelte +157 -0
  47. package/dist/Checkbox/Checkbox.svelte.d.ts +4 -0
  48. package/dist/Checkbox/properties.d.ts +17 -0
  49. package/dist/Checkbox/properties.js +1 -0
  50. package/dist/Choicebox/Choicebox.svelte +85 -0
  51. package/dist/Choicebox/Choicebox.svelte.d.ts +4 -0
  52. package/dist/Choicebox/properties.d.ts +14 -0
  53. package/dist/Choicebox/properties.js +1 -0
  54. package/dist/ColorPicker/ColorPicker.svelte +583 -0
  55. package/dist/ColorPicker/ColorPicker.svelte.d.ts +4 -0
  56. package/dist/ColorPicker/properties.d.ts +15 -0
  57. package/dist/ColorPicker/properties.js +1 -0
  58. package/dist/Combobox/Combobox.svelte +432 -0
  59. package/dist/Combobox/Combobox.svelte.d.ts +6 -0
  60. package/dist/Combobox/properties.d.ts +42 -0
  61. package/dist/Combobox/properties.js +1 -0
  62. package/dist/CommandMenu/CommandMenu.svelte +452 -0
  63. package/dist/CommandMenu/CommandMenu.svelte.d.ts +4 -0
  64. package/dist/CommandMenu/properties.d.ts +26 -0
  65. package/dist/CommandMenu/properties.js +1 -0
  66. package/dist/ContextMenu/ContextMenu.svelte +308 -0
  67. package/dist/ContextMenu/ContextMenu.svelte.d.ts +4 -0
  68. package/dist/ContextMenu/properties.d.ts +26 -0
  69. package/dist/ContextMenu/properties.js +1 -0
  70. package/dist/Gauge/Gauge.svelte +70 -0
  71. package/dist/Gauge/Gauge.svelte.d.ts +4 -0
  72. package/dist/Gauge/properties.d.ts +9 -0
  73. package/dist/Gauge/properties.js +1 -0
  74. package/dist/GridItem/GridItem.svelte +145 -0
  75. package/dist/GridItem/GridItem.svelte.d.ts +4 -0
  76. package/dist/GridItem/properties.d.ts +15 -0
  77. package/dist/GridItem/properties.js +1 -0
  78. package/dist/Icon/Icon.svelte +61 -0
  79. package/dist/Icon/Icon.svelte.d.ts +4 -0
  80. package/dist/Icon/properties.d.ts +12 -0
  81. package/dist/Icon/properties.js +1 -0
  82. package/dist/IconStack/IconStack.svelte +55 -0
  83. package/dist/IconStack/IconStack.svelte.d.ts +4 -0
  84. package/dist/IconStack/properties.d.ts +9 -0
  85. package/dist/IconStack/properties.js +1 -0
  86. package/dist/Img/Img.svelte +37 -0
  87. package/dist/Img/Img.svelte.d.ts +4 -0
  88. package/dist/Img/properties.d.ts +13 -0
  89. package/dist/Img/properties.js +1 -0
  90. package/dist/Input/Input.svelte +349 -0
  91. package/dist/Input/Input.svelte.d.ts +8 -0
  92. package/dist/Input/properties.d.ts +45 -0
  93. package/dist/Input/properties.js +1 -0
  94. package/dist/InputButton/InputButton.svelte +252 -0
  95. package/dist/InputButton/InputButton.svelte.d.ts +7 -0
  96. package/dist/InputButton/properties.d.ts +22 -0
  97. package/dist/InputButton/properties.js +1 -0
  98. package/dist/KeyboardInput/KeyboardInput.svelte +93 -0
  99. package/dist/KeyboardInput/KeyboardInput.svelte.d.ts +4 -0
  100. package/dist/KeyboardInput/properties.d.ts +12 -0
  101. package/dist/KeyboardInput/properties.js +1 -0
  102. package/dist/ListItem/ListItem.svelte +309 -0
  103. package/dist/ListItem/ListItem.svelte.d.ts +4 -0
  104. package/dist/ListItem/properties.d.ts +34 -0
  105. package/dist/ListItem/properties.js +1 -0
  106. package/dist/Loader/Loader.svelte +90 -0
  107. package/dist/Loader/Loader.svelte.d.ts +4 -0
  108. package/dist/Loader/properties.d.ts +4 -0
  109. package/dist/Loader/properties.js +1 -0
  110. package/dist/LoadingDots/LoadingDots.svelte +59 -0
  111. package/dist/LoadingDots/LoadingDots.svelte.d.ts +3 -0
  112. package/dist/LoadingDots/properties.d.ts +8 -0
  113. package/dist/LoadingDots/properties.js +1 -0
  114. package/dist/Menu/Menu.svelte +356 -0
  115. package/dist/Menu/Menu.svelte.d.ts +4 -0
  116. package/dist/Menu/properties.d.ts +28 -0
  117. package/dist/Menu/properties.js +1 -0
  118. package/dist/Modal/Modal.svelte +357 -0
  119. package/dist/Modal/Modal.svelte.d.ts +4 -0
  120. package/dist/Modal/properties.d.ts +39 -0
  121. package/dist/Modal/properties.js +1 -0
  122. package/dist/Pagination/Pagination.svelte +148 -0
  123. package/dist/Pagination/Pagination.svelte.d.ts +4 -0
  124. package/dist/Pagination/properties.d.ts +14 -0
  125. package/dist/Pagination/properties.js +1 -0
  126. package/dist/Phone/Phone.svelte +234 -0
  127. package/dist/Phone/Phone.svelte.d.ts +3 -0
  128. package/dist/Phone/properties.d.ts +11 -0
  129. package/dist/Phone/properties.js +1 -0
  130. package/dist/Pill/Pill.svelte +130 -0
  131. package/dist/Pill/Pill.svelte.d.ts +4 -0
  132. package/dist/Pill/properties.d.ts +16 -0
  133. package/dist/Pill/properties.js +1 -0
  134. package/dist/Progress/Progress.svelte +68 -0
  135. package/dist/Progress/Progress.svelte.d.ts +4 -0
  136. package/dist/Progress/properties.d.ts +10 -0
  137. package/dist/Progress/properties.js +1 -0
  138. package/dist/Radio/Radio.svelte +124 -0
  139. package/dist/Radio/Radio.svelte.d.ts +4 -0
  140. package/dist/Radio/properties.d.ts +15 -0
  141. package/dist/Radio/properties.js +1 -0
  142. package/dist/RelativeTime/RelativeTime.svelte +109 -0
  143. package/dist/RelativeTime/RelativeTime.svelte.d.ts +4 -0
  144. package/dist/RelativeTime/properties.d.ts +13 -0
  145. package/dist/RelativeTime/properties.js +1 -0
  146. package/dist/Scroller/Scroller.svelte +390 -0
  147. package/dist/Scroller/Scroller.svelte.d.ts +4 -0
  148. package/dist/Scroller/properties.d.ts +30 -0
  149. package/dist/Scroller/properties.js +1 -0
  150. package/dist/Select/Select.svelte +472 -0
  151. package/dist/Select/Select.svelte.d.ts +4 -0
  152. package/dist/Select/properties.d.ts +20 -0
  153. package/dist/Select/properties.js +1 -0
  154. package/dist/Sheet/Sheet.svelte +264 -0
  155. package/dist/Sheet/Sheet.svelte.d.ts +4 -0
  156. package/dist/Sheet/properties.d.ts +19 -0
  157. package/dist/Sheet/properties.js +1 -0
  158. package/dist/Shimmer/Shimmer.svelte +44 -0
  159. package/dist/Shimmer/Shimmer.svelte.d.ts +4 -0
  160. package/dist/Shimmer/properties.d.ts +4 -0
  161. package/dist/Shimmer/properties.js +1 -0
  162. package/dist/Slider/Slider.svelte +147 -0
  163. package/dist/Slider/Slider.svelte.d.ts +4 -0
  164. package/dist/Slider/properties.d.ts +17 -0
  165. package/dist/Slider/properties.js +1 -0
  166. package/dist/Snippet/Snippet.svelte +123 -0
  167. package/dist/Snippet/Snippet.svelte.d.ts +4 -0
  168. package/dist/Snippet/properties.d.ts +15 -0
  169. package/dist/Snippet/properties.js +1 -0
  170. package/dist/SplitButton/SplitButton.svelte +145 -0
  171. package/dist/SplitButton/SplitButton.svelte.d.ts +4 -0
  172. package/dist/SplitButton/properties.d.ts +17 -0
  173. package/dist/SplitButton/properties.js +1 -0
  174. package/dist/SplitInput/SplitInput.svelte +225 -0
  175. package/dist/SplitInput/SplitInput.svelte.d.ts +7 -0
  176. package/dist/SplitInput/properties.d.ts +20 -0
  177. package/dist/SplitInput/properties.js +1 -0
  178. package/dist/Stepper/Step.svelte +88 -0
  179. package/dist/Stepper/Step.svelte.d.ts +4 -0
  180. package/dist/Stepper/Stepper.svelte +64 -0
  181. package/dist/Stepper/Stepper.svelte.d.ts +4 -0
  182. package/dist/Stepper/properties.d.ts +27 -0
  183. package/dist/Stepper/properties.js +1 -0
  184. package/dist/Table/Table.svelte +357 -0
  185. package/dist/Table/Table.svelte.d.ts +4 -0
  186. package/dist/Table/properties.d.ts +26 -0
  187. package/dist/Table/properties.js +1 -0
  188. package/dist/Tabs/Tabs.svelte +303 -0
  189. package/dist/Tabs/Tabs.svelte.d.ts +4 -0
  190. package/dist/Tabs/properties.d.ts +30 -0
  191. package/dist/Tabs/properties.js +1 -0
  192. package/dist/ThemeSwitcher/ThemeSwitcher.svelte +249 -0
  193. package/dist/ThemeSwitcher/ThemeSwitcher.svelte.d.ts +4 -0
  194. package/dist/ThemeSwitcher/properties.d.ts +19 -0
  195. package/dist/ThemeSwitcher/properties.js +1 -0
  196. package/dist/Toast/Toast.svelte +220 -0
  197. package/dist/Toast/Toast.svelte.d.ts +4 -0
  198. package/dist/Toast/properties.d.ts +24 -0
  199. package/dist/Toast/properties.js +1 -0
  200. package/dist/Toggle/Toggle.svelte +99 -0
  201. package/dist/Toggle/Toggle.svelte.d.ts +4 -0
  202. package/dist/Toggle/properties.d.ts +9 -0
  203. package/dist/Toggle/properties.js +1 -0
  204. package/dist/Toolbar/Toolbar.svelte +142 -0
  205. package/dist/Toolbar/Toolbar.svelte.d.ts +4 -0
  206. package/dist/Toolbar/properties.d.ts +16 -0
  207. package/dist/Toolbar/properties.js +1 -0
  208. package/dist/Tooltip/Tooltip.svelte +153 -0
  209. package/dist/Tooltip/Tooltip.svelte.d.ts +4 -0
  210. package/dist/Tooltip/properties.d.ts +13 -0
  211. package/dist/Tooltip/properties.js +1 -0
  212. package/dist/assets/back.svg +3 -0
  213. package/dist/assets/battery.svg +5 -0
  214. package/dist/assets/checkmark.svg +3 -0
  215. package/dist/assets/chevron-down-sm.svg +3 -0
  216. package/dist/assets/chevron-down.svg +3 -0
  217. package/dist/assets/chevron-left-lg.svg +3 -0
  218. package/dist/assets/chevron-left.svg +3 -0
  219. package/dist/assets/chevron-right-lg.svg +3 -0
  220. package/dist/assets/chevron-right.svg +3 -0
  221. package/dist/assets/chevron-up.svg +3 -0
  222. package/dist/assets/close.svg +4 -0
  223. package/dist/assets/copy.svg +4 -0
  224. package/dist/assets/error-circle.svg +5 -0
  225. package/dist/assets/lock.svg +3 -0
  226. package/dist/assets/minus.svg +3 -0
  227. package/dist/assets/monitor.svg +5 -0
  228. package/dist/assets/moon.svg +3 -0
  229. package/dist/assets/palette.svg +7 -0
  230. package/dist/assets/search.svg +4 -0
  231. package/dist/assets/signal.svg +6 -0
  232. package/dist/assets/sort-default.svg +4 -0
  233. package/dist/assets/sun.svg +11 -0
  234. package/dist/assets/swap-vertical.svg +6 -0
  235. package/dist/assets/wifi.svg +3 -0
  236. package/dist/index.d.ts +103 -0
  237. package/dist/index.js +55 -0
  238. package/dist/types.d.ts +42 -0
  239. package/dist/types.js +1 -0
  240. package/dist/utils.d.ts +28 -0
  241. package/dist/utils.js +294 -0
  242. package/package.json +91 -0
@@ -0,0 +1,583 @@
1
+ <script lang="ts">
2
+ import Button from '../Button/Button.svelte';
3
+ import Input from '../Input/Input.svelte';
4
+ import Slider from '../Slider/Slider.svelte';
5
+ import SplitInput from '../SplitInput/SplitInput.svelte';
6
+ import swapVerticalSvg from '../assets/swap-vertical.svg?raw';
7
+ import type { ColorPickerProperties } from './properties';
8
+ import {
9
+ hexToHsv,
10
+ hsvToHex,
11
+ hsvToRgb,
12
+ hsvToHsl,
13
+ hslToHsv,
14
+ rgbToHsv,
15
+ isValidHex,
16
+ clampInt
17
+ } from '../utils';
18
+
19
+ let {
20
+ value = $bindable('#000000'),
21
+ label,
22
+ disabled = false,
23
+ showValue = false,
24
+ testId,
25
+ onchange,
26
+ oninput,
27
+ classes
28
+ }: ColorPickerProperties = $props();
29
+
30
+ // ── Internal state ──────────────────────────────────────────────
31
+
32
+ let open = $state(false);
33
+ let containerEl: HTMLDivElement | null = $state(null);
34
+
35
+ let hue = $state(0);
36
+ let sat = $state(1);
37
+ let val = $state(1);
38
+
39
+ type ColorMode = 'HEX' | 'RGB' | 'HSL';
40
+ const modes: ColorMode[] = ['HEX', 'RGB', 'HSL'];
41
+ let mode: ColorMode = $state('HEX');
42
+
43
+ // ── Derived values ──────────────────────────────────────────────
44
+
45
+ let hexInputValue = $derived(value);
46
+ let currentRgb = $derived(hsvToRgb(hue, sat, val));
47
+ let currentHsl = $derived(hsvToHsl(hue, sat, val));
48
+
49
+ let _syncTrigger = $derived.by(() => {
50
+ const hsv = hexToHsv(value);
51
+ if (hsv !== null) {
52
+ hue = hsv.h;
53
+ sat = hsv.s;
54
+ val = hsv.v;
55
+ }
56
+ return value;
57
+ });
58
+
59
+ // ── Color commit ────────────────────────────────────────────────
60
+
61
+ function commitColor() {
62
+ const hex = hsvToHex(hue, sat, val);
63
+ if (hex !== value) {
64
+ value = hex;
65
+ oninput?.(value);
66
+ onchange?.(value);
67
+ }
68
+ }
69
+
70
+ // ── Popover open/close ──────────────────────────────────────────
71
+
72
+ function togglePicker(_event: MouseEvent) {
73
+ if (disabled === false) {
74
+ open = !open;
75
+ }
76
+ }
77
+
78
+ function handleWindowClick(e: MouseEvent) {
79
+ if (
80
+ open &&
81
+ containerEl !== null &&
82
+ e.target instanceof Node &&
83
+ containerEl.contains(e.target) === false
84
+ ) {
85
+ open = false;
86
+ }
87
+ }
88
+
89
+ // ── Saturation panel drag ───────────────────────────────────────
90
+
91
+ let satPanelEl: HTMLDivElement | null = $state(null);
92
+ let draggingSat = $state(false);
93
+
94
+ function handleSatDown(e: PointerEvent) {
95
+ if (disabled) {
96
+ return;
97
+ }
98
+ draggingSat = true;
99
+ if (e.currentTarget instanceof HTMLElement) {
100
+ e.currentTarget.setPointerCapture(e.pointerId);
101
+ }
102
+ updateSatFromPointer(e);
103
+ }
104
+
105
+ function handleSatMove(e: PointerEvent) {
106
+ if (draggingSat === false) {
107
+ return;
108
+ }
109
+ updateSatFromPointer(e);
110
+ }
111
+
112
+ function handleSatUp() {
113
+ draggingSat = false;
114
+ }
115
+
116
+ function updateSatFromPointer(e: PointerEvent) {
117
+ if (satPanelEl === null) {
118
+ return;
119
+ }
120
+ const rect = satPanelEl.getBoundingClientRect();
121
+ sat = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width));
122
+ val = Math.max(0, Math.min(1, 1 - (e.clientY - rect.top) / rect.height));
123
+ commitColor();
124
+ }
125
+
126
+ // ── Hue slider ─────────────────────────────────────────────────
127
+
128
+ let hueDegrees = $derived(Math.round(hue * 360));
129
+
130
+ function handleHueInput(newHue: number) {
131
+ hue = newHue / 360;
132
+ commitColor();
133
+ }
134
+
135
+ // ── Input field handlers ────────────────────────────────────────
136
+
137
+ function handleTextInput(newValue: string) {
138
+ if (isValidHex(newValue)) {
139
+ value = newValue;
140
+ oninput?.(value);
141
+ onchange?.(value);
142
+ }
143
+ }
144
+
145
+ function handleHexFieldInput(newValue: string) {
146
+ let v = newValue.trim();
147
+ if (v.charAt(0) !== '#') {
148
+ v = '#' + v;
149
+ }
150
+ if (isValidHex(v)) {
151
+ value = v;
152
+ oninput?.(value);
153
+ onchange?.(value);
154
+ }
155
+ }
156
+
157
+ function handleRgbInput(vals: string[]) {
158
+ const r = clampInt(vals.at(0) ?? '0', 0, 255);
159
+ const g = clampInt(vals.at(1) ?? '0', 0, 255);
160
+ const b = clampInt(vals.at(2) ?? '0', 0, 255);
161
+ const hsv = rgbToHsv(r, g, b);
162
+ hue = hsv.h;
163
+ sat = hsv.s;
164
+ val = hsv.v;
165
+ commitColor();
166
+ }
167
+
168
+ function handleHslInput(vals: string[]) {
169
+ const h = clampInt(vals.at(0) ?? '0', 0, 360);
170
+ const s = clampInt(vals.at(1) ?? '0', 0, 100);
171
+ const l = clampInt(vals.at(2) ?? '0', 0, 100);
172
+ const hsv = hslToHsv(h, s, l);
173
+ hue = hsv.h;
174
+ sat = hsv.s;
175
+ val = hsv.v;
176
+ commitColor();
177
+ }
178
+
179
+ function cycleMode() {
180
+ const idx = modes.indexOf(mode);
181
+ mode = modes.at((idx + 1) % modes.length) ?? 'HEX';
182
+ }
183
+ </script>
184
+
185
+ <svelte:window onclick={handleWindowClick} />
186
+
187
+ <div
188
+ class="color-picker-container {classes ?? ''}"
189
+ class:disabled
190
+ data-pw={testId}
191
+ bind:this={containerEl}
192
+ >
193
+ {#if typeof label === 'string'}
194
+ <span class="color-picker-label">{label}</span>
195
+ {/if}
196
+
197
+ <!-- Trigger: swatch button + optional hex input -->
198
+ <div class="color-picker-row">
199
+ <div class="color-picker-swatch-btn" class:standalone={showValue === false}>
200
+ <Button onclick={togglePicker} {disabled} ariaLabel="Pick a color" ariaExpanded={open}>
201
+ <span class="color-picker-checkerboard">
202
+ <span class="color-picker-swatch" style="background-color: {value};"></span>
203
+ </span>
204
+ </Button>
205
+ </div>
206
+ {#if showValue}
207
+ <div class="color-picker-input-wrap">
208
+ <Input
209
+ bind:value
210
+ disable={disabled}
211
+ maxLength={7}
212
+ classes="color-picker-text-input"
213
+ oninput={handleTextInput}
214
+ />
215
+ </div>
216
+ {/if}
217
+ </div>
218
+
219
+ <!-- Popover panel -->
220
+ {#if open}
221
+ <div class="color-picker-popover" role="dialog" aria-label="Color picker">
222
+ <div
223
+ class="cp-sat-panel"
224
+ style="background-color: {hsvToHex(hue, 1, 1)};"
225
+ bind:this={satPanelEl}
226
+ onpointerdown={handleSatDown}
227
+ onpointermove={handleSatMove}
228
+ onpointerup={handleSatUp}
229
+ role="slider"
230
+ aria-label="Saturation and brightness"
231
+ aria-valuenow={Math.round(sat * 100)}
232
+ aria-valuemin={0}
233
+ aria-valuemax={100}
234
+ aria-valuetext="{Math.round(sat * 100)}% saturation, {Math.round(val * 100)}% brightness"
235
+ tabindex={0}
236
+ >
237
+ <div class="cp-sat-white"></div>
238
+ <div class="cp-sat-black"></div>
239
+ <div class="cp-sat-thumb" style="left: {sat * 100}%; top: {(1 - val) * 100}%;"></div>
240
+ </div>
241
+
242
+ <div class="cp-hue-slider">
243
+ <Slider
244
+ value={hueDegrees}
245
+ min={0}
246
+ max={360}
247
+ step={1}
248
+ {disabled}
249
+ classes="cp-hue-track"
250
+ oninput={handleHueInput}
251
+ onchange={handleHueInput}
252
+ />
253
+ </div>
254
+
255
+ <div class="cp-inputs">
256
+ <div class="cp-preview" style="background-color: {value};"></div>
257
+
258
+ {#if mode === 'HEX'}
259
+ <div class="cp-field-hex">
260
+ <Input
261
+ value={hexInputValue}
262
+ maxLength={7}
263
+ classes="cp-field-input"
264
+ oninput={handleHexFieldInput}
265
+ />
266
+ <span class="cp-field-label">HEX</span>
267
+ </div>
268
+ {:else if mode === 'RGB'}
269
+ <SplitInput
270
+ values={[String(currentRgb.r), String(currentRgb.g), String(currentRgb.b)]}
271
+ fields={[
272
+ { label: 'R', dataType: 'number', min: 0, max: 255 },
273
+ { label: 'G', dataType: 'number', min: 0, max: 255 },
274
+ { label: 'B', dataType: 'number', min: 0, max: 255 }
275
+ ]}
276
+ {disabled}
277
+ classes="cp-split-input"
278
+ oninput={handleRgbInput}
279
+ />
280
+ {:else}
281
+ <SplitInput
282
+ values={[String(currentHsl.h), String(currentHsl.s), String(currentHsl.l)]}
283
+ fields={[
284
+ { label: 'H', dataType: 'number', min: 0, max: 360 },
285
+ { label: 'S', dataType: 'number', min: 0, max: 100 },
286
+ { label: 'L', dataType: 'number', min: 0, max: 100 }
287
+ ]}
288
+ {disabled}
289
+ classes="cp-split-input"
290
+ oninput={handleHslInput}
291
+ />
292
+ {/if}
293
+
294
+ <div class="cp-mode-toggle">
295
+ <Button onclick={cycleMode} ariaLabel="Switch color mode">
296
+ <!-- eslint-disable-next-line svelte/no-at-html-tags -->
297
+ {@html swapVerticalSvg}
298
+ </Button>
299
+ </div>
300
+ </div>
301
+ </div>
302
+ {/if}
303
+ </div>
304
+
305
+ <style>
306
+ /* ── Container ─────────────────────────────────────────────── */
307
+
308
+ .color-picker-container {
309
+ display: flex;
310
+ flex-direction: column;
311
+ gap: var(--color-picker-gap, 8px);
312
+ width: var(--color-picker-width, fit-content);
313
+ position: relative;
314
+ }
315
+
316
+ .color-picker-container.disabled {
317
+ opacity: var(--color-picker-disabled-opacity, 0.5);
318
+ cursor: not-allowed;
319
+ }
320
+
321
+ .color-picker-label {
322
+ font-size: var(--color-picker-label-font-size, 14px);
323
+ font-weight: var(--color-picker-label-font-weight, 500);
324
+ color: var(--color-picker-label-color, currentColor);
325
+ letter-spacing: var(--color-picker-label-letter-spacing, 0.01em);
326
+ }
327
+
328
+ /* ── Trigger row ───────────────────────────────────────────── */
329
+
330
+ .color-picker-row {
331
+ display: flex;
332
+ align-items: center;
333
+ gap: var(--color-picker-row-gap, 0px);
334
+ }
335
+
336
+ .color-picker-swatch-btn {
337
+ --button-color: var(--color-picker-swatch-btn-background, transparent);
338
+ --button-border: var(--color-picker-swatch-btn-border, 1px solid #18181b);
339
+ --button-border-radius: var(--color-picker-swatch-btn-border-radius, 6px 0 0 6px);
340
+ --button-hover-color: var(--color-picker-swatch-btn-hover-background, transparent);
341
+ --button-padding: var(--color-picker-swatch-padding, 5px);
342
+ --button-width: fit-content;
343
+ flex-shrink: 0;
344
+ }
345
+
346
+ .color-picker-swatch-btn.standalone {
347
+ --button-border-radius: var(--color-picker-swatch-btn-border-radius, 6px);
348
+ }
349
+
350
+ .color-picker-checkerboard {
351
+ display: block;
352
+ width: var(--color-picker-swatch-size, 26px);
353
+ height: var(--color-picker-swatch-size, 26px);
354
+ border-radius: var(--color-picker-swatch-border-radius, 6px);
355
+ overflow: hidden;
356
+ background-image:
357
+ linear-gradient(45deg, #ccc 25%, transparent 25%),
358
+ linear-gradient(-45deg, #ccc 25%, transparent 25%),
359
+ linear-gradient(45deg, transparent 75%, #ccc 75%),
360
+ linear-gradient(-45deg, transparent 75%, #ccc 75%);
361
+ background-size: 8px 8px;
362
+ background-position:
363
+ 0 0,
364
+ 0 4px,
365
+ 4px -4px,
366
+ -4px 0px;
367
+ flex-shrink: 0;
368
+ }
369
+
370
+ .color-picker-swatch {
371
+ display: block;
372
+ width: 100%;
373
+ height: 100%;
374
+ border-radius: inherit;
375
+ box-shadow: var(--color-picker-swatch-inner-shadow, inset 0 0 0 1px rgba(0, 0, 0, 0.08));
376
+ }
377
+
378
+ .color-picker-input-wrap {
379
+ flex: 1;
380
+ min-width: 0;
381
+ }
382
+
383
+ .color-picker-input-wrap :global(.color-picker-text-input) {
384
+ --input-border: 1px solid currentColor;
385
+ --input-radius: 0 6px 6px 0;
386
+ --input-margin: 0;
387
+ --input-padding: 8px 12px;
388
+ --input-font-size: 14px;
389
+ --input-font-weight: 500;
390
+ --input-font-family: var(
391
+ --color-picker-mono-font,
392
+ ui-monospace,
393
+ SFMono-Regular,
394
+ Menlo,
395
+ Monaco,
396
+ Consolas,
397
+ monospace
398
+ );
399
+ --input-box-shadow: none;
400
+ --input-width: 100%;
401
+ --input-height: 38px;
402
+ margin-left: -1px;
403
+ }
404
+
405
+ /* ── Popover ───────────────────────────────────────────────── */
406
+
407
+ .color-picker-popover {
408
+ position: absolute;
409
+ top: 100%;
410
+ left: 0;
411
+ z-index: var(--color-picker-popover-z-index, 50);
412
+ margin-top: 6px;
413
+ width: var(--color-picker-popover-width, 280px);
414
+ padding: var(--color-picker-popover-padding, 12px);
415
+ background: var(--color-picker-popover-background, #ffffff);
416
+ border: var(--color-picker-popover-border, 1px solid currentColor);
417
+ border-radius: var(--color-picker-popover-border-radius, 8px);
418
+ box-shadow: var(
419
+ --color-picker-popover-shadow,
420
+ 0 4px 24px rgba(0, 0, 0, 0.12),
421
+ 0 1px 4px rgba(0, 0, 0, 0.06)
422
+ );
423
+ display: flex;
424
+ flex-direction: column;
425
+ gap: 12px;
426
+ touch-action: none;
427
+ }
428
+
429
+ /* ── Saturation / brightness panel ─────────────────────────── */
430
+
431
+ .cp-sat-panel {
432
+ position: relative;
433
+ width: 100%;
434
+ aspect-ratio: 1 / 0.7;
435
+ border-radius: var(--color-picker-panel-border-radius, 8px);
436
+ cursor: crosshair;
437
+ overflow: hidden;
438
+ user-select: none;
439
+ }
440
+
441
+ .cp-sat-white {
442
+ position: absolute;
443
+ inset: 0;
444
+ background: linear-gradient(to right, #ffffff, transparent);
445
+ border-radius: inherit;
446
+ }
447
+
448
+ .cp-sat-black {
449
+ position: absolute;
450
+ inset: 0;
451
+ background: linear-gradient(to bottom, transparent, #000000);
452
+ border-radius: inherit;
453
+ }
454
+
455
+ .cp-sat-thumb {
456
+ position: absolute;
457
+ width: 16px;
458
+ height: 16px;
459
+ border-radius: 50%;
460
+ border: 2.5px solid #ffffff;
461
+ box-shadow:
462
+ 0 0 0 1px rgba(0, 0, 0, 0.15),
463
+ 0 1px 4px rgba(0, 0, 0, 0.3);
464
+ transform: translate(-50%, -50%);
465
+ pointer-events: none;
466
+ }
467
+
468
+ /* ── Hue slider ────────────────────────────────────────────── */
469
+
470
+ .cp-hue-slider {
471
+ --slider-container-padding: 0;
472
+ --slider-track: linear-gradient(
473
+ to right,
474
+ #ff0000 0%,
475
+ #ffff00 16.67%,
476
+ #00ff00 33.33%,
477
+ #00ffff 50%,
478
+ #0000ff 66.67%,
479
+ #ff00ff 83.33%,
480
+ #ff0000 100%
481
+ );
482
+ --slider-track-height: 14px;
483
+ --slider-track-border-radius: 7px;
484
+ --slider-thumb-size: 18px;
485
+ --slider-thumb-background: #ffffff;
486
+ --slider-thumb-border: 2.5px solid #ffffff;
487
+ --slider-thumb-shadow: 0 0 0 1px rgba(0, 0, 0, 0.15), 0 1px 4px rgba(0, 0, 0, 0.25);
488
+ }
489
+
490
+ /* ── Input fields ──────────────────────────────────────────── */
491
+
492
+ .cp-inputs {
493
+ display: flex;
494
+ align-items: flex-start;
495
+ gap: 6px;
496
+ }
497
+
498
+ .cp-preview {
499
+ width: 36px;
500
+ height: 36px;
501
+ border-radius: 6px;
502
+ border: 1px solid rgba(0, 0, 0, 0.08);
503
+ flex-shrink: 0;
504
+ }
505
+
506
+ .cp-field-hex {
507
+ display: flex;
508
+ flex-direction: column;
509
+ align-items: center;
510
+ gap: 3px;
511
+ flex: 3;
512
+ min-width: 0;
513
+ }
514
+
515
+ .cp-field-hex :global(.cp-field-input) {
516
+ --input-border: 1px solid var(--color-picker-field-border, currentColor);
517
+ --input-radius: 6px;
518
+ --input-margin: 0;
519
+ --input-padding: 0 6px;
520
+ --input-font-size: 12px;
521
+ --input-font-weight: 500;
522
+ --input-font-family: var(
523
+ --color-picker-mono-font,
524
+ ui-monospace,
525
+ SFMono-Regular,
526
+ Menlo,
527
+ Monaco,
528
+ Consolas,
529
+ monospace
530
+ );
531
+ --input-text-color: var(--color-picker-field-color, currentColor);
532
+ --input-background: var(--color-picker-field-background, #ffffff);
533
+ --input-box-shadow: none;
534
+ --input-width: 100%;
535
+ --input-height: 32px;
536
+ --input-text-align: center;
537
+ --input-focus-border: 1px solid var(--color-picker-field-focus-border, currentColor);
538
+ }
539
+
540
+ .cp-split-input {
541
+ --field-group-gap: 6px;
542
+ --field-group-border: 1px solid var(--color-picker-field-border, currentColor);
543
+ --field-group-border-radius: 6px;
544
+ --field-group-focus-border: 1px solid var(--color-picker-field-focus-border, currentColor);
545
+ --field-group-input-height: 32px;
546
+ --field-group-font-size: 12px;
547
+ --field-group-font-weight: 500;
548
+ --field-group-font-family: var(
549
+ --color-picker-mono-font,
550
+ ui-monospace,
551
+ SFMono-Regular,
552
+ Menlo,
553
+ Monaco,
554
+ Consolas,
555
+ monospace
556
+ );
557
+ --field-group-label-color: var(--color-picker-field-label-color, currentColor);
558
+ flex: 1;
559
+ min-width: 0;
560
+ }
561
+
562
+ .cp-field-label {
563
+ font-size: 12px;
564
+ font-weight: 500;
565
+ color: var(--color-picker-field-label-color, currentColor);
566
+ text-transform: uppercase;
567
+ letter-spacing: 0.05em;
568
+ }
569
+
570
+ .cp-mode-toggle {
571
+ --button-color: var(--color-picker-field-background, #ffffff);
572
+ --button-border: 1px solid var(--color-picker-field-border, currentColor);
573
+ --button-border-radius: 6px;
574
+ --button-padding: 0;
575
+ --button-width: 28px;
576
+ --button-height: 32px;
577
+ --button-text-color: var(--color-picker-field-label-color, currentColor);
578
+ --button-hover-color: var(--color-picker-field-background, #ffffff);
579
+ --button-hover-border: 1px solid var(--color-picker-field-focus-border, currentColor);
580
+ --button-hover-text-color: var(--color-picker-field-color, currentColor);
581
+ flex-shrink: 0;
582
+ }
583
+ </style>
@@ -0,0 +1,4 @@
1
+ import type { ColorPickerProperties } from './properties';
2
+ declare const ColorPicker: import("svelte").Component<ColorPickerProperties, {}, "value">;
3
+ type ColorPicker = ReturnType<typeof ColorPicker>;
4
+ export default ColorPicker;
@@ -0,0 +1,15 @@
1
+ export type ColorPickerProperties = MandatoryColorPickerProperties & OptionalColorPickerProperties & ColorPickerEventProperties;
2
+ export type MandatoryColorPickerProperties = {
3
+ value: string;
4
+ };
5
+ export type OptionalColorPickerProperties = {
6
+ label?: string;
7
+ disabled?: boolean;
8
+ showValue?: boolean;
9
+ testId?: string;
10
+ classes?: string;
11
+ };
12
+ export type ColorPickerEventProperties = {
13
+ onchange?: (value: string) => void;
14
+ oninput?: (value: string) => void;
15
+ };
@@ -0,0 +1 @@
1
+ export {};