@finsweet/webflow-apps-utils 1.0.8 → 1.0.10
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.
- package/dist/types/customCode.d.ts +1 -1
- package/dist/ui/components/Loader.svelte +0 -2
- package/dist/ui/components/LoadingScreen.svelte +6 -2
- package/dist/ui/components/LoadingScreen.svelte.d.ts +1 -0
- package/dist/ui/components/breakpoints/BreakpointItem.svelte +2 -2
- package/dist/ui/components/button/Button.stories.svelte +0 -8
- package/dist/ui/components/button/Button.svelte +68 -76
- package/dist/ui/components/button/index.d.ts +1 -1
- package/dist/ui/components/button/index.js +1 -0
- package/dist/ui/components/color-picker/ColorPicker.stories.svelte +42 -0
- package/dist/ui/components/color-picker/ColorPicker.stories.svelte.d.ts +19 -0
- package/dist/ui/components/color-picker/ColorPicker.svelte +155 -0
- package/dist/ui/components/color-picker/ColorPicker.svelte.d.ts +8 -0
- package/dist/ui/components/color-picker/ColorSelect.stories.svelte +61 -0
- package/dist/ui/components/color-picker/ColorSelect.stories.svelte.d.ts +27 -0
- package/dist/ui/components/color-picker/ColorSelect.svelte +940 -0
- package/dist/ui/components/color-picker/ColorSelect.svelte.d.ts +7 -0
- package/dist/ui/components/color-picker/index.d.ts +1 -0
- package/dist/ui/components/color-picker/index.js +1 -0
- package/dist/ui/components/controlled-buttons/ControlledButtons.svelte +17 -7
- package/dist/ui/components/copy-text/CopyText.svelte +48 -39
- package/dist/ui/components/divider/Divider.stories.svelte +0 -4
- package/dist/ui/components/input/index.d.ts +1 -1
- package/dist/ui/components/input/index.js +1 -0
- package/dist/ui/components/layout/Layout.svelte +0 -5
- package/dist/ui/components/layout/examples/ExampleLayout.svelte +9 -8
- package/dist/ui/components/modal/Example.svelte +0 -7
- package/dist/ui/components/modal/Modal.stories.svelte +0 -2
- package/dist/ui/components/modal/Modal.svelte +1 -1
- package/dist/ui/components/notification/Notification.stories.svelte +0 -8
- package/dist/ui/components/notification/Notification.svelte +2 -2
- package/dist/ui/components/section/Section.stories.svelte +0 -1
- package/dist/ui/components/text/README.md +0 -2
- package/dist/ui/components/text/Text.stories.svelte +0 -6
- package/dist/ui/components/text/Text.svelte +0 -19
- package/dist/ui/components/tooltip/Tooltip.svelte +9 -5
- package/dist/ui/icons/FinsweetLogoOutlineIcon.svelte +17 -0
- package/dist/ui/icons/FinsweetLogoOutlineIcon.svelte.d.ts +26 -0
- package/dist/ui/icons/TriangleDownIconToggle.svelte +0 -1
- package/dist/ui/icons/index.d.ts +2 -1
- package/dist/ui/icons/index.js +2 -1
- package/dist/ui/index.css +1 -1
- package/dist/ui/providers/GlobalProviderDemo.svelte +0 -2
- package/dist/ui/router/Router.stories.js +7 -7
- package/dist/ui/router/examples/RouterExample.svelte +0 -9
- package/dist/ui/router/examples/pages/AboutPage.svelte +0 -4
- package/dist/ui/router/providers/Link.svelte +0 -2
- package/dist/ui/router/providers/Route.svelte +0 -3
- package/dist/ui/stores/form.d.ts +136 -3
- package/dist/ui/stores/form.js +310 -2
- package/package.json +1 -1
|
@@ -0,0 +1,940 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { onMount } from 'svelte';
|
|
3
|
+
|
|
4
|
+
let { color = $bindable('#fff'), onchange } = $props<{
|
|
5
|
+
color?: string;
|
|
6
|
+
onchange?: (color: string) => void;
|
|
7
|
+
}>();
|
|
8
|
+
|
|
9
|
+
function setColor(newColor: string) {
|
|
10
|
+
color = newColor;
|
|
11
|
+
onchange?.(newColor);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
let hue = $state(0);
|
|
15
|
+
let saturation = $state(0);
|
|
16
|
+
let brightness = $state(0);
|
|
17
|
+
let alpha = $state(100);
|
|
18
|
+
let hexValue = $state(color);
|
|
19
|
+
let mode = $state<'HSB' | 'RGB'>('HSB');
|
|
20
|
+
|
|
21
|
+
// RGB values for RGB mode
|
|
22
|
+
let rgbRed = $state(0);
|
|
23
|
+
let rgbGreen = $state(0);
|
|
24
|
+
let rgbBlue = $state(0);
|
|
25
|
+
|
|
26
|
+
// DOM references
|
|
27
|
+
let colorWell: HTMLElement;
|
|
28
|
+
let colorPicker: HTMLElement;
|
|
29
|
+
let hueBar: HTMLElement;
|
|
30
|
+
let alphaBar: HTMLElement;
|
|
31
|
+
|
|
32
|
+
// Interaction state
|
|
33
|
+
let isDragging = $state(false);
|
|
34
|
+
let dragTarget = $state<'well' | 'hue' | 'alpha' | null>(null);
|
|
35
|
+
|
|
36
|
+
// Drag detection state
|
|
37
|
+
let dragStartPosition = $state<{ x: number; y: number } | null>(null);
|
|
38
|
+
const DRAG_THRESHOLD = 3; // pixels of movement before considering it a drag
|
|
39
|
+
|
|
40
|
+
// Color conversion utilities
|
|
41
|
+
function hsbToRgb(h: number, s: number, b: number): [number, number, number] {
|
|
42
|
+
h = h / 360;
|
|
43
|
+
s = s / 100;
|
|
44
|
+
b = b / 100;
|
|
45
|
+
const c = b * s;
|
|
46
|
+
const x = c * (1 - Math.abs(((h * 6) % 2) - 1));
|
|
47
|
+
const m = b - c;
|
|
48
|
+
let r = 0,
|
|
49
|
+
g = 0,
|
|
50
|
+
bl = 0;
|
|
51
|
+
|
|
52
|
+
if (0 <= h && h < 1 / 6) {
|
|
53
|
+
r = c;
|
|
54
|
+
g = x;
|
|
55
|
+
bl = 0;
|
|
56
|
+
} else if (1 / 6 <= h && h < 2 / 6) {
|
|
57
|
+
r = x;
|
|
58
|
+
g = c;
|
|
59
|
+
bl = 0;
|
|
60
|
+
} else if (2 / 6 <= h && h < 3 / 6) {
|
|
61
|
+
r = 0;
|
|
62
|
+
g = c;
|
|
63
|
+
bl = x;
|
|
64
|
+
} else if (3 / 6 <= h && h < 4 / 6) {
|
|
65
|
+
r = 0;
|
|
66
|
+
g = x;
|
|
67
|
+
bl = c;
|
|
68
|
+
} else if (4 / 6 <= h && h < 5 / 6) {
|
|
69
|
+
r = x;
|
|
70
|
+
g = 0;
|
|
71
|
+
bl = c;
|
|
72
|
+
} else if (5 / 6 <= h && h < 1) {
|
|
73
|
+
r = c;
|
|
74
|
+
g = 0;
|
|
75
|
+
bl = x;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return [Math.round((r + m) * 255), Math.round((g + m) * 255), Math.round((bl + m) * 255)];
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function rgbToHex(r: number, g: number, b: number): string {
|
|
82
|
+
return (
|
|
83
|
+
'#' +
|
|
84
|
+
[r, g, b]
|
|
85
|
+
.map((x) => {
|
|
86
|
+
const hex = x.toString(16);
|
|
87
|
+
return hex.length === 1 ? '0' + hex : hex;
|
|
88
|
+
})
|
|
89
|
+
.join('')
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function hexToHsb(hex: string): [number, number, number] {
|
|
94
|
+
// Handle different hex formats
|
|
95
|
+
let normalizedHex = hex;
|
|
96
|
+
if (hex.startsWith('#')) {
|
|
97
|
+
// Expand 3-digit hex to 6-digit
|
|
98
|
+
if (hex.length === 4) {
|
|
99
|
+
normalizedHex = '#' + hex[1] + hex[1] + hex[2] + hex[2] + hex[3] + hex[3];
|
|
100
|
+
}
|
|
101
|
+
// Remove alpha channel if present (8-digit hex)
|
|
102
|
+
if (hex.length === 9) {
|
|
103
|
+
normalizedHex = hex.substring(0, 7);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const r = parseInt(normalizedHex.slice(1, 3), 16) / 255;
|
|
108
|
+
const g = parseInt(normalizedHex.slice(3, 5), 16) / 255;
|
|
109
|
+
const b = parseInt(normalizedHex.slice(5, 7), 16) / 255;
|
|
110
|
+
const max = Math.max(r, g, b);
|
|
111
|
+
const min = Math.min(r, g, b);
|
|
112
|
+
const diff = max - min;
|
|
113
|
+
let h = 0;
|
|
114
|
+
let s = max === 0 ? 0 : diff / max;
|
|
115
|
+
let v = max;
|
|
116
|
+
|
|
117
|
+
if (diff !== 0) {
|
|
118
|
+
if (max === r) {
|
|
119
|
+
h = ((g - b) / diff) % 6;
|
|
120
|
+
} else if (max === g) {
|
|
121
|
+
h = (b - r) / diff + 2;
|
|
122
|
+
} else {
|
|
123
|
+
h = (r - g) / diff + 4;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
h = Math.round(h * 60);
|
|
128
|
+
if (h < 0) h += 360;
|
|
129
|
+
return [h, Math.round(s * 100), Math.round(v * 100)];
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Color validation utility using CSS.supports()
|
|
133
|
+
function isValidColor(value: unknown): boolean {
|
|
134
|
+
// Ensure value is a string
|
|
135
|
+
if (typeof value !== 'string') {
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Handle hex colors specifically
|
|
140
|
+
if (value.startsWith('#')) {
|
|
141
|
+
// Check for valid hex format: #RGB, #RRGGBB, #RRGGBBAA
|
|
142
|
+
const hexRegex = /^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{4}|[0-9A-Fa-f]{6}|[0-9A-Fa-f]{8})$/;
|
|
143
|
+
const result = hexRegex.test(value);
|
|
144
|
+
return result;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// For non-hex colors, only accept valid hex patterns (without #)
|
|
148
|
+
const hexRegex = /^([0-9A-Fa-f]{3}|[0-9A-Fa-f]{4}|[0-9A-Fa-f]{6}|[0-9A-Fa-f]{8})$/;
|
|
149
|
+
const result = hexRegex.test(value);
|
|
150
|
+
return result;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function rgbToHsb(r: number, g: number, b: number): [number, number, number] {
|
|
154
|
+
return hexToHsb(rgbToHex(r, g, b));
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Update functions
|
|
158
|
+
function updateColor() {
|
|
159
|
+
let r, g, b;
|
|
160
|
+
if (mode === 'HSB') {
|
|
161
|
+
[r, g, b] = hsbToRgb(hue, saturation, brightness);
|
|
162
|
+
} else {
|
|
163
|
+
r = rgbRed;
|
|
164
|
+
g = rgbGreen;
|
|
165
|
+
b = rgbBlue;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
hexValue = rgbToHex(r, g, b).toUpperCase();
|
|
169
|
+
setColor(hexValue);
|
|
170
|
+
updateColorPickerPosition();
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function syncModeValues(newMode: 'HSB' | 'RGB') {
|
|
174
|
+
if (newMode === 'RGB') {
|
|
175
|
+
[rgbRed, rgbGreen, rgbBlue] = hsbToRgb(hue, saturation, brightness);
|
|
176
|
+
} else {
|
|
177
|
+
[hue, saturation, brightness] = rgbToHsb(rgbRed, rgbGreen, rgbBlue);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function toggleMode() {
|
|
182
|
+
mode = mode === 'HSB' ? 'RGB' : 'HSB';
|
|
183
|
+
syncModeValues(mode);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function updateColorPickerPosition() {
|
|
187
|
+
if (!colorPicker || !colorWell) return;
|
|
188
|
+
const wellRect = colorWell.getBoundingClientRect();
|
|
189
|
+
const x = (saturation / 100) * wellRect.width;
|
|
190
|
+
const y = ((100 - brightness) / 100) * wellRect.height;
|
|
191
|
+
colorPicker.style.left = `${x - 6}px`;
|
|
192
|
+
colorPicker.style.top = `${y - 6}px`;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function handleColorWellInteraction(event: MouseEvent) {
|
|
196
|
+
if (!colorWell) return;
|
|
197
|
+
const rect = colorWell.getBoundingClientRect();
|
|
198
|
+
const x = Math.max(0, Math.min(rect.width, event.clientX - rect.left));
|
|
199
|
+
const y = Math.max(0, Math.min(rect.height, event.clientY - rect.top));
|
|
200
|
+
saturation = Math.round((x / rect.width) * 100);
|
|
201
|
+
brightness = Math.round(100 - (y / rect.height) * 100);
|
|
202
|
+
updateColor();
|
|
203
|
+
updateColorPickerPosition();
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function handleHueBarInteraction(event: MouseEvent) {
|
|
207
|
+
if (!hueBar) return;
|
|
208
|
+
const rect = hueBar.getBoundingClientRect();
|
|
209
|
+
const x = Math.max(0, Math.min(rect.width, event.clientX - rect.left));
|
|
210
|
+
hue = Math.round((x / rect.width) * 360);
|
|
211
|
+
updateColor();
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function handleAlphaBarInteraction(event: MouseEvent) {
|
|
215
|
+
if (!alphaBar) return;
|
|
216
|
+
const rect = alphaBar.getBoundingClientRect();
|
|
217
|
+
const x = Math.max(0, Math.min(rect.width, event.clientX - rect.left));
|
|
218
|
+
alpha = Math.round((x / rect.width) * 100);
|
|
219
|
+
if (onchange) onchange(hexValue);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function handleHexChange(event: Event) {
|
|
223
|
+
const target = event.target as HTMLInputElement;
|
|
224
|
+
let value = target.value;
|
|
225
|
+
|
|
226
|
+
if (!value.startsWith('#')) {
|
|
227
|
+
value = '#' + value;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (isValidColor(value)) {
|
|
231
|
+
hexValue = value.toUpperCase();
|
|
232
|
+
setColor(hexValue);
|
|
233
|
+
const [h, s, b] = hexToHsb(value);
|
|
234
|
+
hue = h;
|
|
235
|
+
saturation = s;
|
|
236
|
+
brightness = b;
|
|
237
|
+
[rgbRed, rgbGreen, rgbBlue] = hsbToRgb(hue, saturation, brightness);
|
|
238
|
+
updateColorPickerPosition();
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
let hexInputValue = $state('');
|
|
243
|
+
let isHexEditing = $state(false);
|
|
244
|
+
let prevHexValue = $state('');
|
|
245
|
+
|
|
246
|
+
function handleHexFocus(event: FocusEvent) {
|
|
247
|
+
prevHexValue = hexValue;
|
|
248
|
+
hexInputValue = hexValue;
|
|
249
|
+
isHexEditing = true;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function handleHexInput(event: Event) {
|
|
253
|
+
hexInputValue = (event.target as HTMLInputElement).value;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function handleHexBlur(event: FocusEvent) {
|
|
257
|
+
isHexEditing = false;
|
|
258
|
+
const value = hexInputValue.trim();
|
|
259
|
+
|
|
260
|
+
if (!value || !isValidColor(value)) {
|
|
261
|
+
hexInputValue = prevHexValue;
|
|
262
|
+
isHexEditing = true;
|
|
263
|
+
|
|
264
|
+
import('svelte').then(({ tick }) => {
|
|
265
|
+
tick().then(() => {
|
|
266
|
+
isHexEditing = false;
|
|
267
|
+
});
|
|
268
|
+
});
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
const normalizedValue = value.startsWith('#') ? value : `#${value}`;
|
|
272
|
+
|
|
273
|
+
hexValue = normalizedValue.toUpperCase();
|
|
274
|
+
|
|
275
|
+
setColor(hexValue);
|
|
276
|
+
prevHexValue = hexValue;
|
|
277
|
+
|
|
278
|
+
const hsb = hexToHsb(hexValue);
|
|
279
|
+
|
|
280
|
+
if (Array.isArray(hsb)) {
|
|
281
|
+
const [h, s, b] = hsb;
|
|
282
|
+
hue = h;
|
|
283
|
+
saturation = s;
|
|
284
|
+
brightness = b;
|
|
285
|
+
const rgb = hsbToRgb(hue, saturation, brightness);
|
|
286
|
+
if (Array.isArray(rgb)) {
|
|
287
|
+
[rgbRed, rgbGreen, rgbBlue] = rgb;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
updateColorPickerPosition();
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
function handleHexKeydown(event: KeyboardEvent) {
|
|
294
|
+
if (event.key === 'Enter') {
|
|
295
|
+
(event.target as HTMLInputElement).blur();
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
$effect(() => {
|
|
300
|
+
if (!isHexEditing) {
|
|
301
|
+
hexInputValue = hexValue;
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
// Mouse event handlers with improved drag detection
|
|
306
|
+
function handleMouseDown(event: MouseEvent, target: 'well' | 'hue' | 'alpha') {
|
|
307
|
+
// Record the starting position for drag detection
|
|
308
|
+
dragStartPosition = { x: event.clientX, y: event.clientY };
|
|
309
|
+
|
|
310
|
+
// Always handle the initial interaction
|
|
311
|
+
if (target === 'well') {
|
|
312
|
+
handleColorWellInteraction(event);
|
|
313
|
+
} else if (target === 'hue') {
|
|
314
|
+
handleHueBarInteraction(event);
|
|
315
|
+
} else if (target === 'alpha') {
|
|
316
|
+
handleAlphaBarInteraction(event);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
function handleMouseMove(event: MouseEvent) {
|
|
321
|
+
if (!dragStartPosition) return;
|
|
322
|
+
|
|
323
|
+
// Calculate distance moved
|
|
324
|
+
const deltaX = Math.abs(event.clientX - dragStartPosition.x);
|
|
325
|
+
const deltaY = Math.abs(event.clientY - dragStartPosition.y);
|
|
326
|
+
const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
|
|
327
|
+
|
|
328
|
+
// If we haven't started dragging yet and we've moved beyond threshold
|
|
329
|
+
if (!isDragging && distance > DRAG_THRESHOLD) {
|
|
330
|
+
isDragging = true;
|
|
331
|
+
// Determine drag target based on which element was initially clicked
|
|
332
|
+
if (dragTarget === null) {
|
|
333
|
+
// This shouldn't happen, but fallback to well
|
|
334
|
+
dragTarget = 'well';
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// If we're dragging, handle the interaction
|
|
339
|
+
if (isDragging && dragTarget) {
|
|
340
|
+
if (dragTarget === 'well') {
|
|
341
|
+
handleColorWellInteraction(event);
|
|
342
|
+
} else if (dragTarget === 'hue') {
|
|
343
|
+
handleHueBarInteraction(event);
|
|
344
|
+
} else if (dragTarget === 'alpha') {
|
|
345
|
+
handleAlphaBarInteraction(event);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
function handleMouseUp(event: MouseEvent) {
|
|
351
|
+
// If we were dragging, this is the end of the drag
|
|
352
|
+
if (isDragging) {
|
|
353
|
+
isDragging = false;
|
|
354
|
+
dragTarget = null;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// Reset drag detection state
|
|
358
|
+
dragStartPosition = null;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Calculate the position of the handle on the color bar
|
|
363
|
+
* @param value
|
|
364
|
+
* @param min
|
|
365
|
+
* @param max
|
|
366
|
+
* @param range
|
|
367
|
+
*/
|
|
368
|
+
function percentHandlePosition(value: number, min: number, max: number, range: number): number {
|
|
369
|
+
return min + (value * (max - min)) / range;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// Watch for prop changes
|
|
373
|
+
$effect(() => {
|
|
374
|
+
if (color !== hexValue) {
|
|
375
|
+
if (isValidColor(color)) {
|
|
376
|
+
hexValue = color;
|
|
377
|
+
const [h, s, b] = hexToHsb(color);
|
|
378
|
+
hue = h;
|
|
379
|
+
saturation = s;
|
|
380
|
+
brightness = b;
|
|
381
|
+
[rgbRed, rgbGreen, rgbBlue] = hsbToRgb(hue, saturation, brightness);
|
|
382
|
+
updateColorPickerPosition();
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
let currentColor = $derived(
|
|
388
|
+
`rgba(${hsbToRgb(hue, saturation, brightness).join(', ')}, ${alpha / 100})`
|
|
389
|
+
);
|
|
390
|
+
|
|
391
|
+
onMount(() => {
|
|
392
|
+
// Initialize from color prop
|
|
393
|
+
if (isValidColor(color)) {
|
|
394
|
+
hexValue = color;
|
|
395
|
+
const [h, s, b] = hexToHsb(color);
|
|
396
|
+
hue = h;
|
|
397
|
+
saturation = s;
|
|
398
|
+
brightness = b;
|
|
399
|
+
[rgbRed, rgbGreen, rgbBlue] = hsbToRgb(hue, saturation, brightness);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
updateColor();
|
|
403
|
+
updateColorPickerPosition();
|
|
404
|
+
|
|
405
|
+
document.addEventListener('mousemove', handleMouseMove);
|
|
406
|
+
document.addEventListener('mouseup', handleMouseUp);
|
|
407
|
+
|
|
408
|
+
return () => {
|
|
409
|
+
document.removeEventListener('mousemove', handleMouseMove);
|
|
410
|
+
document.removeEventListener('mouseup', handleMouseUp);
|
|
411
|
+
};
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
// EyeDropper API handler
|
|
415
|
+
async function handleEyedropper() {
|
|
416
|
+
if ('EyeDropper' in window) {
|
|
417
|
+
try {
|
|
418
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
419
|
+
const eyeDropper = new (window as any).EyeDropper();
|
|
420
|
+
const result = await eyeDropper.open();
|
|
421
|
+
if (result && result.sRGBHex) {
|
|
422
|
+
hexValue = result.sRGBHex.toUpperCase();
|
|
423
|
+
setColor(hexValue);
|
|
424
|
+
const [h, s, b] = hexToHsb(hexValue);
|
|
425
|
+
hue = h;
|
|
426
|
+
saturation = s;
|
|
427
|
+
brightness = b;
|
|
428
|
+
[rgbRed, rgbGreen, rgbBlue] = hsbToRgb(hue, saturation, brightness);
|
|
429
|
+
updateColorPickerPosition();
|
|
430
|
+
}
|
|
431
|
+
} catch (e) {
|
|
432
|
+
// User cancelled or error
|
|
433
|
+
}
|
|
434
|
+
} else {
|
|
435
|
+
alert('EyeDropper API is not supported in this browser.');
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
$effect(() => {
|
|
440
|
+
updateColorPickerPosition();
|
|
441
|
+
});
|
|
442
|
+
</script>
|
|
443
|
+
|
|
444
|
+
<div class="color-picker">
|
|
445
|
+
<div class="color-picker__container">
|
|
446
|
+
<!-- Color Well -->
|
|
447
|
+
<div
|
|
448
|
+
class="color-well"
|
|
449
|
+
tabindex="0"
|
|
450
|
+
bind:this={colorWell}
|
|
451
|
+
onmousedown={(e) => {
|
|
452
|
+
dragTarget = 'well';
|
|
453
|
+
handleMouseDown(e, 'well');
|
|
454
|
+
}}
|
|
455
|
+
role="button"
|
|
456
|
+
aria-label="Color selection well"
|
|
457
|
+
style={`background: linear-gradient(rgba(0, 0, 0, 0), black), linear-gradient(to right, white, rgba(255, 255, 255, 0)) rgb(${hsbToRgb(hue, 100, 100).join(',')});`}
|
|
458
|
+
>
|
|
459
|
+
<div class="color-well__picker" bind:this={colorPicker}></div>
|
|
460
|
+
</div>
|
|
461
|
+
|
|
462
|
+
<!-- Color Bars Section -->
|
|
463
|
+
<div class="color-bars">
|
|
464
|
+
<button
|
|
465
|
+
class="eyedropper-btn"
|
|
466
|
+
type="button"
|
|
467
|
+
onpointerdown={() => {
|
|
468
|
+
handleEyedropper();
|
|
469
|
+
}}
|
|
470
|
+
aria-label="Pick color from screen"
|
|
471
|
+
>
|
|
472
|
+
<div class="eyedropper-btn__icon">
|
|
473
|
+
<svg
|
|
474
|
+
data-wf-icon="EyedropperMediumIcon"
|
|
475
|
+
width="16"
|
|
476
|
+
height="16"
|
|
477
|
+
viewBox="0 0 16 16"
|
|
478
|
+
fill="none"
|
|
479
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
480
|
+
><path
|
|
481
|
+
d="M6.85355 4.14664C6.65829 4.3419 6.65829 4.65848 6.85355 4.85374L11.1464 9.14664C11.3417 9.3419 11.6583 9.3419 11.8536 9.14664L12.1464 8.85374C12.3417 8.65848 12.3417 8.3419 12.1464 8.14664L11 7.00019L12.75 5.25019C13.4404 4.55983 13.4404 3.44055 12.75 2.75019C12.0596 2.05983 10.9404 2.05983 10.25 2.75019L8.5 4.50019L7.85355 3.85374C7.65829 3.65848 7.34171 3.65848 7.14645 3.85374L6.85355 4.14664Z"
|
|
482
|
+
fill="currentColor"
|
|
483
|
+
></path><path
|
|
484
|
+
d="M3 12.0002L2.5 12.5002L3.5 13.5002L4 13.0002H5L9 9.00019L7 7.00019L3 11.0002V12.0002Z"
|
|
485
|
+
fill="currentColor"
|
|
486
|
+
></path></svg
|
|
487
|
+
>
|
|
488
|
+
</div>
|
|
489
|
+
</button>
|
|
490
|
+
|
|
491
|
+
<div class="color-bars__container">
|
|
492
|
+
<!-- Hue Bar -->
|
|
493
|
+
<div class="color-bar">
|
|
494
|
+
<div
|
|
495
|
+
class="color-bar__hue"
|
|
496
|
+
bind:this={hueBar}
|
|
497
|
+
onmousedown={(e) => {
|
|
498
|
+
dragTarget = 'hue';
|
|
499
|
+
handleMouseDown(e, 'hue');
|
|
500
|
+
}}
|
|
501
|
+
role="slider"
|
|
502
|
+
aria-label="Hue slider"
|
|
503
|
+
aria-valuenow={hue}
|
|
504
|
+
aria-valuemin="0"
|
|
505
|
+
aria-valuemax="360"
|
|
506
|
+
tabindex="0"
|
|
507
|
+
style="pointer-events: auto; position: relative;"
|
|
508
|
+
>
|
|
509
|
+
<div
|
|
510
|
+
class="color-bar__hue-handle color-bar__handle"
|
|
511
|
+
style="left: {percentHandlePosition(hue, 2, 98, 360)}%;
|
|
512
|
+
"
|
|
513
|
+
></div>
|
|
514
|
+
</div>
|
|
515
|
+
</div>
|
|
516
|
+
|
|
517
|
+
<!-- Alpha Bar -->
|
|
518
|
+
<div class="color-bar">
|
|
519
|
+
<div
|
|
520
|
+
class="color-bar__alpha"
|
|
521
|
+
bind:this={alphaBar}
|
|
522
|
+
onmousedown={(e) => {
|
|
523
|
+
dragTarget = 'alpha';
|
|
524
|
+
handleMouseDown(e, 'alpha');
|
|
525
|
+
}}
|
|
526
|
+
role="slider"
|
|
527
|
+
aria-label="Alpha slider"
|
|
528
|
+
aria-valuenow={alpha}
|
|
529
|
+
aria-valuemin="0"
|
|
530
|
+
aria-valuemax="100"
|
|
531
|
+
tabindex="0"
|
|
532
|
+
style="pointer-events: auto; position: relative;"
|
|
533
|
+
>
|
|
534
|
+
<div class="color-bar__alpha-bg" style="pointer-events: none;"></div>
|
|
535
|
+
<div
|
|
536
|
+
class="color-bar__alpha-gradient"
|
|
537
|
+
style="background: linear-gradient(90deg, transparent 0%, {`rgba(${hsbToRgb(hue, saturation, brightness).join(',')},1)`} 100%); pointer-events: none;"
|
|
538
|
+
></div>
|
|
539
|
+
<div
|
|
540
|
+
class="color-bar__alpha-handle color-bar__handle"
|
|
541
|
+
style="left: {percentHandlePosition(alpha, 2, 98, 100)}%;
|
|
542
|
+
|
|
543
|
+
"
|
|
544
|
+
></div>
|
|
545
|
+
</div>
|
|
546
|
+
</div>
|
|
547
|
+
</div>
|
|
548
|
+
</div>
|
|
549
|
+
|
|
550
|
+
<div class="divider"></div>
|
|
551
|
+
|
|
552
|
+
<!-- Controls Section -->
|
|
553
|
+
<div class="controls">
|
|
554
|
+
<!-- Hex Input -->
|
|
555
|
+
<div class="control-group">
|
|
556
|
+
<div class="input-wrapper">
|
|
557
|
+
<input
|
|
558
|
+
id="hex-input"
|
|
559
|
+
type="text"
|
|
560
|
+
class="input input--hex"
|
|
561
|
+
value={hexInputValue}
|
|
562
|
+
oninput={handleHexInput}
|
|
563
|
+
onfocus={handleHexFocus}
|
|
564
|
+
onblur={handleHexBlur}
|
|
565
|
+
onkeydown={handleHexKeydown}
|
|
566
|
+
placeholder="#000000"
|
|
567
|
+
/>
|
|
568
|
+
</div>
|
|
569
|
+
<label class="label" for="hex-input">HEX</label>
|
|
570
|
+
</div>
|
|
571
|
+
|
|
572
|
+
<!-- HSB/RGB Inputs -->
|
|
573
|
+
<div class="control-group control-group--main">
|
|
574
|
+
<div class="input-row">
|
|
575
|
+
<div class="input-wrapper">
|
|
576
|
+
<input
|
|
577
|
+
class="input input--number"
|
|
578
|
+
value={mode === 'HSB' ? hue : rgbRed}
|
|
579
|
+
min="0"
|
|
580
|
+
max={mode === 'HSB' ? 360 : 255}
|
|
581
|
+
role="spinbutton"
|
|
582
|
+
aria-label={mode === 'HSB' ? 'Hue' : 'Red'}
|
|
583
|
+
oninput={(e) => {
|
|
584
|
+
const target = e.target as HTMLInputElement;
|
|
585
|
+
if (!target) return;
|
|
586
|
+
if (mode === 'HSB') {
|
|
587
|
+
hue = +target.value;
|
|
588
|
+
} else {
|
|
589
|
+
rgbRed = +target.value;
|
|
590
|
+
}
|
|
591
|
+
updateColor();
|
|
592
|
+
}}
|
|
593
|
+
/>
|
|
594
|
+
</div>
|
|
595
|
+
<div class="input-wrapper">
|
|
596
|
+
<input
|
|
597
|
+
class="input input--number"
|
|
598
|
+
value={mode === 'HSB' ? saturation : rgbGreen}
|
|
599
|
+
min="0"
|
|
600
|
+
max={mode === 'HSB' ? 100 : 255}
|
|
601
|
+
role="spinbutton"
|
|
602
|
+
aria-label={mode === 'HSB' ? 'Saturation' : 'Green'}
|
|
603
|
+
oninput={(e) => {
|
|
604
|
+
const target = e.target as HTMLInputElement;
|
|
605
|
+
if (!target) return;
|
|
606
|
+
if (mode === 'HSB') {
|
|
607
|
+
saturation = +target.value;
|
|
608
|
+
} else {
|
|
609
|
+
rgbGreen = +target.value;
|
|
610
|
+
}
|
|
611
|
+
updateColor();
|
|
612
|
+
}}
|
|
613
|
+
/>
|
|
614
|
+
</div>
|
|
615
|
+
<div class="input-wrapper">
|
|
616
|
+
<input
|
|
617
|
+
class="input input--number"
|
|
618
|
+
value={mode === 'HSB' ? brightness : rgbBlue}
|
|
619
|
+
min="0"
|
|
620
|
+
max={mode === 'HSB' ? 100 : 255}
|
|
621
|
+
role="spinbutton"
|
|
622
|
+
aria-label={mode === 'HSB' ? 'Brightness' : 'Blue'}
|
|
623
|
+
oninput={(e) => {
|
|
624
|
+
const target = e.target as HTMLInputElement;
|
|
625
|
+
if (!target) return;
|
|
626
|
+
if (mode === 'HSB') {
|
|
627
|
+
brightness = +target.value;
|
|
628
|
+
} else {
|
|
629
|
+
rgbBlue = +target.value;
|
|
630
|
+
}
|
|
631
|
+
updateColor();
|
|
632
|
+
}}
|
|
633
|
+
/>
|
|
634
|
+
</div>
|
|
635
|
+
</div>
|
|
636
|
+
|
|
637
|
+
<div class="label-row--wrapper">
|
|
638
|
+
<div
|
|
639
|
+
class="label-row"
|
|
640
|
+
onpointerdown={toggleMode}
|
|
641
|
+
role="button"
|
|
642
|
+
tabindex="0"
|
|
643
|
+
onkeydown={() => {}}
|
|
644
|
+
aria-label="Mode toggle"
|
|
645
|
+
>
|
|
646
|
+
<span class="label label--clickable">
|
|
647
|
+
{mode === 'HSB' ? 'H' : 'R'}
|
|
648
|
+
</span>
|
|
649
|
+
<span class="label label--clickable">
|
|
650
|
+
{mode === 'HSB' ? 'S' : 'G'}
|
|
651
|
+
</span>
|
|
652
|
+
<span class="label label--clickable">
|
|
653
|
+
{mode === 'HSB' ? 'B' : 'B'}
|
|
654
|
+
</span>
|
|
655
|
+
</div>
|
|
656
|
+
</div>
|
|
657
|
+
</div>
|
|
658
|
+
|
|
659
|
+
<!-- Alpha Input -->
|
|
660
|
+
<div class="control-group">
|
|
661
|
+
<div class="input-wrapper">
|
|
662
|
+
<input
|
|
663
|
+
class="input input--number"
|
|
664
|
+
bind:value={alpha}
|
|
665
|
+
min="0"
|
|
666
|
+
max="100"
|
|
667
|
+
role="spinbutton"
|
|
668
|
+
aria-label="Alpha"
|
|
669
|
+
/>
|
|
670
|
+
</div>
|
|
671
|
+
<span class="label">A</span>
|
|
672
|
+
</div>
|
|
673
|
+
</div>
|
|
674
|
+
</div>
|
|
675
|
+
</div>
|
|
676
|
+
|
|
677
|
+
<style>
|
|
678
|
+
/* Main Container */
|
|
679
|
+
.color-picker {
|
|
680
|
+
width: 241px;
|
|
681
|
+
height: auto;
|
|
682
|
+
box-shadow: 0px 3px 6px -2px rgba(0, 0, 0, 0.36);
|
|
683
|
+
display: inline-flex;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
.color-picker__container {
|
|
687
|
+
width: 241px;
|
|
688
|
+
padding: 8px;
|
|
689
|
+
background: var(--background4);
|
|
690
|
+
border-radius: 4px;
|
|
691
|
+
display: flex;
|
|
692
|
+
flex-direction: column;
|
|
693
|
+
gap: 8px;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
/* Color Well */
|
|
697
|
+
.color-well {
|
|
698
|
+
width: 225px;
|
|
699
|
+
height: 150px;
|
|
700
|
+
position: relative;
|
|
701
|
+
border-radius: 2px;
|
|
702
|
+
outline: 1px solid var(--border1, rgba(255, 255, 255, 0.1));
|
|
703
|
+
outline-offset: -1px;
|
|
704
|
+
cursor: crosshair;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
.color-well__picker {
|
|
708
|
+
position: absolute;
|
|
709
|
+
width: 12px;
|
|
710
|
+
height: 12px;
|
|
711
|
+
border: 2px solid white;
|
|
712
|
+
border-radius: 50%;
|
|
713
|
+
box-shadow: 0 0 3px rgba(0, 0, 0, 0.5);
|
|
714
|
+
pointer-events: none;
|
|
715
|
+
z-index: 10;
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
/* Color Bars */
|
|
719
|
+
.color-bars {
|
|
720
|
+
width: 225px;
|
|
721
|
+
display: flex;
|
|
722
|
+
align-items: center;
|
|
723
|
+
gap: 6px;
|
|
724
|
+
}
|
|
725
|
+
.color-bar__handle {
|
|
726
|
+
position: absolute;
|
|
727
|
+
top: 1px !important;
|
|
728
|
+
transform: translateX(-50%);
|
|
729
|
+
pointer-events: none;
|
|
730
|
+
height: 11px;
|
|
731
|
+
width: 6px;
|
|
732
|
+
border-radius: 1px;
|
|
733
|
+
box-shadow:
|
|
734
|
+
0 0 0 2px var(--text1),
|
|
735
|
+
0 0 0 3px rgba(0, 0, 0, 0.3),
|
|
736
|
+
inset 0 0 0 1px rgba(0, 0, 0, 0.3);
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
.eyedropper-btn {
|
|
740
|
+
width: 32px;
|
|
741
|
+
height: 32px;
|
|
742
|
+
padding: 4px;
|
|
743
|
+
background:
|
|
744
|
+
linear-gradient(180deg, rgba(255, 255, 255, 0.12) 0%, rgba(255, 255, 255, 0.1) 100%),
|
|
745
|
+
rgba(255, 255, 255, 0.08);
|
|
746
|
+
box-shadow: 0px 0.5px 1px black;
|
|
747
|
+
border-radius: 4px;
|
|
748
|
+
border: none;
|
|
749
|
+
cursor: pointer;
|
|
750
|
+
display: flex;
|
|
751
|
+
align-items: center;
|
|
752
|
+
justify-content: center;
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
.eyedropper-btn__icon {
|
|
756
|
+
width: 16px;
|
|
757
|
+
height: 16px;
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
.eyedropper-btn__icon svg {
|
|
761
|
+
color: var(--text1, #ebebeb);
|
|
762
|
+
}
|
|
763
|
+
.color-bars__container {
|
|
764
|
+
flex: 1;
|
|
765
|
+
display: flex;
|
|
766
|
+
flex-direction: column;
|
|
767
|
+
gap: 4px;
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
.color-bar {
|
|
771
|
+
padding: 1px 0;
|
|
772
|
+
display: flex;
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
.color-bar__hue {
|
|
776
|
+
width: 186px;
|
|
777
|
+
height: 12px;
|
|
778
|
+
background: linear-gradient(
|
|
779
|
+
90deg,
|
|
780
|
+
#ff0000 0%,
|
|
781
|
+
#ff8a00 8%,
|
|
782
|
+
#fff500 18%,
|
|
783
|
+
#00ff47 39%,
|
|
784
|
+
#00f0ff 51%,
|
|
785
|
+
#0019fb 64%,
|
|
786
|
+
#fa00ff 84%,
|
|
787
|
+
#ff0000 100%
|
|
788
|
+
);
|
|
789
|
+
border-radius: 2px;
|
|
790
|
+
outline: 1px solid var(--border1, rgba(255, 255, 255, 0.1));
|
|
791
|
+
cursor: pointer;
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
.color-bar__alpha {
|
|
795
|
+
width: 186px;
|
|
796
|
+
border-radius: 2px;
|
|
797
|
+
height: 12px;
|
|
798
|
+
position: relative;
|
|
799
|
+
cursor: pointer;
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
.color-bar__alpha-bg {
|
|
803
|
+
position: absolute;
|
|
804
|
+
width: 186px;
|
|
805
|
+
inset: 0;
|
|
806
|
+
border-radius: 2px;
|
|
807
|
+
overflow: hidden;
|
|
808
|
+
background-image:
|
|
809
|
+
linear-gradient(45deg, #ccc 25%, transparent 25%),
|
|
810
|
+
linear-gradient(-45deg, #ccc 25%, transparent 25%),
|
|
811
|
+
linear-gradient(45deg, transparent 75%, #ccc 75%),
|
|
812
|
+
linear-gradient(-45deg, transparent 75%, #ccc 75%);
|
|
813
|
+
background-size: 8px 8px;
|
|
814
|
+
background-position:
|
|
815
|
+
0 0,
|
|
816
|
+
0 4px,
|
|
817
|
+
4px -4px,
|
|
818
|
+
-4px 0px;
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
.color-bar__alpha-gradient {
|
|
822
|
+
position: absolute;
|
|
823
|
+
inset: 0;
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
.color-bar__hue-handle {
|
|
827
|
+
position: absolute;
|
|
828
|
+
top: -1px;
|
|
829
|
+
transform: translateX(-50%);
|
|
830
|
+
pointer-events: none;
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
.color-bar__alpha-handle {
|
|
834
|
+
position: absolute;
|
|
835
|
+
top: -1px;
|
|
836
|
+
transform: translateX(-50%);
|
|
837
|
+
pointer-events: none;
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
/* Divider */
|
|
841
|
+
.divider {
|
|
842
|
+
width: 225px;
|
|
843
|
+
height: 1px;
|
|
844
|
+
background: var(--border1);
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
/* Controls */
|
|
848
|
+
.controls {
|
|
849
|
+
display: grid;
|
|
850
|
+
grid-template-columns: 70px 1fr 30px;
|
|
851
|
+
gap: 7px;
|
|
852
|
+
width: 100%;
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
.control-group {
|
|
856
|
+
display: grid;
|
|
857
|
+
grid-template-rows: 26px 20px;
|
|
858
|
+
gap: 8px;
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
.control-group--main {
|
|
862
|
+
flex: 1;
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
.input-row {
|
|
866
|
+
display: flex;
|
|
867
|
+
gap: 4px;
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
.label-row {
|
|
871
|
+
display: flex;
|
|
872
|
+
background: #4e4e4e;
|
|
873
|
+
border-radius: 4px;
|
|
874
|
+
cursor: pointer;
|
|
875
|
+
width: 100%;
|
|
876
|
+
box-shadow:
|
|
877
|
+
0px 0.5px 1px 0px #000,
|
|
878
|
+
0px 0.5px 0.5px 0px rgba(255, 255, 255, 0.12) inset;
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
.label-row--wrapper {
|
|
882
|
+
display: flex;
|
|
883
|
+
gap: 4px;
|
|
884
|
+
width: 100%;
|
|
885
|
+
flex: 1;
|
|
886
|
+
align-self: stretch;
|
|
887
|
+
justify-content: space-between;
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
.input-wrapper {
|
|
891
|
+
flex: 1;
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
.input {
|
|
895
|
+
width: 100%;
|
|
896
|
+
padding: 4px;
|
|
897
|
+
background: var(--backgroundInput);
|
|
898
|
+
border: 1px solid var(--border2);
|
|
899
|
+
border-radius: 4px;
|
|
900
|
+
color: var(--text1, #ebebeb);
|
|
901
|
+
font-size: 11px;
|
|
902
|
+
font-family: Inter, sans-serif;
|
|
903
|
+
font-weight: 400;
|
|
904
|
+
line-height: 16px;
|
|
905
|
+
outline: none;
|
|
906
|
+
box-shadow: 0px 1px 1px -1px rgba(0, 0, 0, 0.13) inset;
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
.input--hex {
|
|
910
|
+
width: 70px;
|
|
911
|
+
text-align: left;
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
.input--number {
|
|
915
|
+
width: 30px;
|
|
916
|
+
text-align: center;
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
.label {
|
|
920
|
+
color: var(--text1, #ebebeb);
|
|
921
|
+
font-size: 11px;
|
|
922
|
+
font-family: Inter, sans-serif;
|
|
923
|
+
font-weight: 400;
|
|
924
|
+
line-height: 16px;
|
|
925
|
+
text-align: center;
|
|
926
|
+
display: flex;
|
|
927
|
+
align-items: center;
|
|
928
|
+
justify-content: center;
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
.label--clickable {
|
|
932
|
+
flex: 1;
|
|
933
|
+
padding: 4px;
|
|
934
|
+
cursor: pointer;
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
.control-group--main .input--number {
|
|
938
|
+
width: 100%;
|
|
939
|
+
}
|
|
940
|
+
</style>
|