@finsweet/webflow-apps-utils 1.0.17 → 1.0.19
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/ui/components/LoadingScreen.svelte +0 -1
- package/dist/ui/components/button/Button.svelte +0 -1
- package/dist/ui/components/color-picker/ColorPicker.stories.svelte +16 -15
- package/dist/ui/components/color-picker/ColorPicker.svelte +93 -32
- package/dist/ui/components/color-picker/ColorPicker.svelte.d.ts +8 -0
- package/dist/ui/components/color-picker/ColorPickerWrapper.svelte +14 -0
- package/dist/ui/components/color-picker/ColorPickerWrapper.svelte.d.ts +6 -0
- package/dist/ui/components/color-picker/ColorSelect.svelte +100 -34
- package/dist/ui/components/copy-text/CopyText.svelte +0 -2
- package/dist/ui/components/input/Input.svelte +0 -1
- package/dist/ui/components/layout/Layout.svelte +1 -2
- package/dist/ui/components/layout/examples/ExampleLayout.svelte +3 -3
- package/dist/ui/components/modal/Modal.svelte +0 -1
- package/dist/ui/components/notification/Notification.svelte +2 -2
- package/dist/ui/components/select/Select.svelte +4 -4
- package/dist/ui/components/text/Text.svelte +1 -6
- package/dist/ui/components/tooltip/Tooltip.svelte +1 -1
- package/dist/ui/index.css +1 -0
- package/dist/ui/providers/GlobalProviderDemo.svelte +1 -3
- package/dist/ui/router/examples/RouterExample.svelte +0 -1
- package/dist/ui/router/examples/pages/AboutPage.svelte +0 -2
- package/dist/ui/router/examples/pages/HomePage.svelte +0 -2
- package/dist/ui/router/examples/pages/NotFoundPage.svelte +0 -2
- package/dist/ui/router/providers/Link.svelte +0 -1
- package/dist/ui/stores/forms/FormDemo.svelte +1 -5
- package/dist/ui/utils/color-utils.d.ts +12 -0
- package/dist/ui/utils/color-utils.js +50 -0
- package/dist/ui/utils/diff-mapper/DiffMapperDemo.svelte +2 -3
- package/dist/ui/utils/index.d.ts +1 -0
- package/dist/ui/utils/index.js +1 -0
- package/package.json +1 -1
|
@@ -39,19 +39,28 @@
|
|
|
39
39
|
});
|
|
40
40
|
</script>
|
|
41
41
|
|
|
42
|
-
<Story name="Default" args={{}} />
|
|
42
|
+
<Story name="Default" args={{ oncolorchange: handleFullColorChange }} />
|
|
43
43
|
|
|
44
|
-
<Story
|
|
44
|
+
<Story
|
|
45
|
+
name="With Initial Color"
|
|
46
|
+
args={{ color: '#00ff00', oncolorchange: handleFullColorChange }}
|
|
47
|
+
/>
|
|
45
48
|
|
|
46
|
-
<Story
|
|
49
|
+
<Story
|
|
50
|
+
name="Edge: Invalid Color"
|
|
51
|
+
args={{ color: '#xyzxyz', oncolorchange: handleFullColorChange }}
|
|
52
|
+
/>
|
|
47
53
|
|
|
48
|
-
<Story name="Edge: No Color" args={{ color: undefined }} />
|
|
54
|
+
<Story name="Edge: No Color" args={{ color: undefined, oncolorchange: handleFullColorChange }} />
|
|
49
55
|
|
|
50
|
-
<Story
|
|
56
|
+
<Story
|
|
57
|
+
name="Disabled Picker"
|
|
58
|
+
args={{ color: '#ebebeb', disabled: true, oncolorchange: handleFullColorChange }}
|
|
59
|
+
/>
|
|
51
60
|
|
|
52
61
|
<Story
|
|
53
62
|
name="Full Color Object Demo"
|
|
54
|
-
args={{ color: '#ff6600' }}
|
|
63
|
+
args={{ color: '#ff6600', oncolorchange: handleFullColorChange }}
|
|
55
64
|
story={{
|
|
56
65
|
parameters: {
|
|
57
66
|
docs: {
|
|
@@ -68,15 +77,7 @@
|
|
|
68
77
|
name="Alpha Channel Demo"
|
|
69
78
|
args={{
|
|
70
79
|
color: '#ff0000',
|
|
71
|
-
oncolorchange:
|
|
72
|
-
hex: string;
|
|
73
|
-
rgb: { r: number; g: number; b: number; value: string };
|
|
74
|
-
rgba: { r: number; g: number; b: number; a: number; value: string };
|
|
75
|
-
hsb: { h: number; s: number; b: number; value: string };
|
|
76
|
-
alpha: number;
|
|
77
|
-
}) => {
|
|
78
|
-
console.log('Full color object:', fullColor);
|
|
79
|
-
}
|
|
80
|
+
oncolorchange: handleFullColorChange
|
|
80
81
|
}}
|
|
81
82
|
story={{
|
|
82
83
|
parameters: {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { normalizeHex } from '../../utils';
|
|
2
3
|
import Tooltip from '../tooltip/Tooltip.svelte';
|
|
3
4
|
import ColorSelect from './ColorSelect.svelte';
|
|
4
5
|
|
|
@@ -28,23 +29,48 @@
|
|
|
28
29
|
* Whether the picker is disabled.
|
|
29
30
|
*/
|
|
30
31
|
disabled?: boolean;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* The id of the picker.
|
|
35
|
+
*/
|
|
36
|
+
id?: string;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Whether the color select should be shown by default.
|
|
40
|
+
*/
|
|
41
|
+
defaultShowColorSelect?: boolean;
|
|
31
42
|
}
|
|
32
43
|
|
|
33
44
|
let {
|
|
34
45
|
color = $bindable('#fff'),
|
|
35
46
|
oncolorchange,
|
|
36
47
|
width = '80px',
|
|
37
|
-
disabled = false
|
|
48
|
+
disabled = false,
|
|
49
|
+
defaultShowColorSelect = false,
|
|
50
|
+
id
|
|
38
51
|
}: Props = $props();
|
|
39
52
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
53
|
+
// Remove local inputValue state
|
|
54
|
+
// let inputValue = $state(color);
|
|
55
|
+
|
|
56
|
+
// Helper: normalize hex to 6-digit uppercase
|
|
57
|
+
// function normalizeHex(value: string): string {
|
|
58
|
+
// if (/^#[A-Fa-f0-9]{3}$/.test(value)) {
|
|
59
|
+
// return (
|
|
60
|
+
// '#' +
|
|
61
|
+
// value
|
|
62
|
+
// .slice(1)
|
|
63
|
+
// .split('')
|
|
64
|
+
// .map((c) => c + c)
|
|
65
|
+
// .join('')
|
|
66
|
+
// .toUpperCase()
|
|
67
|
+
// );
|
|
68
|
+
// }
|
|
69
|
+
// if (/^#[A-Fa-f0-9]{6}$/.test(value)) {
|
|
70
|
+
// return value.toUpperCase();
|
|
71
|
+
// }
|
|
72
|
+
// return value;
|
|
73
|
+
// }
|
|
48
74
|
|
|
49
75
|
function isValidColor(value: string): boolean {
|
|
50
76
|
const hexRegex = /^#?([A-Fa-f0-9]{3}|[A-Fa-f0-9]{6}|[A-Fa-f0-9]{8})$/;
|
|
@@ -107,6 +133,41 @@
|
|
|
107
133
|
};
|
|
108
134
|
}
|
|
109
135
|
|
|
136
|
+
function normalizeHexTo6Upper(value: string): string {
|
|
137
|
+
const hex = value.startsWith('#') ? value : `#${value}`;
|
|
138
|
+
if (/^#[A-Fa-f0-9]{3}$/.test(hex)) {
|
|
139
|
+
return (
|
|
140
|
+
'#' +
|
|
141
|
+
hex
|
|
142
|
+
.slice(1)
|
|
143
|
+
.split('')
|
|
144
|
+
.map((c) => c + c)
|
|
145
|
+
.join('')
|
|
146
|
+
.toUpperCase()
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
if (/^#[A-Fa-f0-9]{6}$/.test(hex)) {
|
|
150
|
+
return hex.toUpperCase();
|
|
151
|
+
}
|
|
152
|
+
return value;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
$effect(() => {
|
|
156
|
+
// Only update inputValue if color changes externally (not from input)
|
|
157
|
+
// if (
|
|
158
|
+
// color !== inputValue &&
|
|
159
|
+
// document.activeElement !== null &&
|
|
160
|
+
// document.activeElement !== inputEl
|
|
161
|
+
// ) {
|
|
162
|
+
// inputValue = color;
|
|
163
|
+
// }
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
function handleInput(event: Event) {
|
|
167
|
+
const target = event.target as HTMLInputElement;
|
|
168
|
+
color = target.value;
|
|
169
|
+
}
|
|
170
|
+
|
|
110
171
|
function handleInputPaste(event: ClipboardEvent) {
|
|
111
172
|
event.preventDefault();
|
|
112
173
|
|
|
@@ -116,23 +177,9 @@
|
|
|
116
177
|
|
|
117
178
|
cleanText = cleanText.substring(0, 9);
|
|
118
179
|
|
|
119
|
-
|
|
120
|
-
|
|
180
|
+
const normalizedValue = normalizeHexTo6Upper(cleanText);
|
|
181
|
+
if (/^#[A-F0-9]{6}$/.test(normalizedValue)) {
|
|
121
182
|
color = normalizedValue;
|
|
122
|
-
// Call oncolorchange with the new color
|
|
123
|
-
const colorObject = createColorObject(normalizedValue);
|
|
124
|
-
oncolorchange?.(colorObject);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
function handleInputChange(event: Event) {
|
|
129
|
-
const target = event.target as HTMLInputElement;
|
|
130
|
-
const value = target.value.trim();
|
|
131
|
-
|
|
132
|
-
if (isValidColor(value)) {
|
|
133
|
-
const normalizedValue = normalizeHex(value);
|
|
134
|
-
color = normalizedValue;
|
|
135
|
-
// Call oncolorchange with the new color
|
|
136
183
|
const colorObject = createColorObject(normalizedValue);
|
|
137
184
|
oncolorchange?.(colorObject);
|
|
138
185
|
}
|
|
@@ -140,18 +187,27 @@
|
|
|
140
187
|
|
|
141
188
|
function handleInputKeydown(event: KeyboardEvent) {
|
|
142
189
|
if (event.key === 'Enter') {
|
|
143
|
-
(event.target as HTMLInputElement).blur();
|
|
190
|
+
// (event.target as HTMLInputElement).blur(); // Removed local inputValue update
|
|
144
191
|
}
|
|
145
192
|
}
|
|
146
193
|
|
|
147
|
-
function
|
|
148
|
-
const
|
|
149
|
-
|
|
194
|
+
function handleBlur(event: Event) {
|
|
195
|
+
const target = event.target as HTMLInputElement;
|
|
196
|
+
const normalized = normalizeHex(target.value);
|
|
197
|
+
if (/^#[A-F0-9]{6}$/.test(normalized)) {
|
|
198
|
+
color = normalized;
|
|
199
|
+
const colorObject = createColorObject(normalized);
|
|
200
|
+
oncolorchange?.(colorObject);
|
|
201
|
+
}
|
|
150
202
|
}
|
|
151
203
|
|
|
152
204
|
function handleFullColorChange(fullColor: ColorObject) {
|
|
153
205
|
oncolorchange?.(fullColor);
|
|
206
|
+
const normalizedValue = normalizeHex(fullColor.hex);
|
|
207
|
+
color = normalizedValue;
|
|
154
208
|
}
|
|
209
|
+
|
|
210
|
+
let showColorSelect = $state(defaultShowColorSelect);
|
|
155
211
|
</script>
|
|
156
212
|
|
|
157
213
|
<div class="color-picker">
|
|
@@ -164,6 +220,8 @@
|
|
|
164
220
|
stopPropagation={true}
|
|
165
221
|
width="241px"
|
|
166
222
|
placement="bottom"
|
|
223
|
+
onshow={() => (showColorSelect = true)}
|
|
224
|
+
onclose={() => (showColorSelect = false)}
|
|
167
225
|
fallbackPlacements={['top-end', 'top', 'bottom-end', 'bottom', 'top-start', 'bottom-start']}
|
|
168
226
|
>
|
|
169
227
|
{#snippet target()}
|
|
@@ -172,7 +230,9 @@
|
|
|
172
230
|
</div>
|
|
173
231
|
{/snippet}
|
|
174
232
|
{#snippet tooltip()}
|
|
175
|
-
|
|
233
|
+
{#if showColorSelect}
|
|
234
|
+
<ColorSelect bind:color oncolorchange={handleFullColorChange} />
|
|
235
|
+
{/if}
|
|
176
236
|
{/snippet}
|
|
177
237
|
</Tooltip>
|
|
178
238
|
|
|
@@ -183,12 +243,14 @@
|
|
|
183
243
|
bind:value={color}
|
|
184
244
|
{disabled}
|
|
185
245
|
readonly={disabled}
|
|
186
|
-
oninput={
|
|
246
|
+
oninput={handleInput}
|
|
187
247
|
onkeydown={handleInputKeydown}
|
|
188
248
|
onpaste={handleInputPaste}
|
|
249
|
+
onblur={handleBlur}
|
|
189
250
|
placeholder="#ffffff"
|
|
190
251
|
aria-label="Color hex value"
|
|
191
252
|
style="width: {width}"
|
|
253
|
+
{id}
|
|
192
254
|
/>
|
|
193
255
|
</div>
|
|
194
256
|
|
|
@@ -228,7 +290,6 @@
|
|
|
228
290
|
width: 80px;
|
|
229
291
|
padding: 4px 8px 4px 0px;
|
|
230
292
|
border-radius: 4px;
|
|
231
|
-
font-family: monospace;
|
|
232
293
|
font-size: 12px;
|
|
233
294
|
border: none;
|
|
234
295
|
background: transparent;
|
|
@@ -38,6 +38,14 @@ interface Props {
|
|
|
38
38
|
* Whether the picker is disabled.
|
|
39
39
|
*/
|
|
40
40
|
disabled?: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* The id of the picker.
|
|
43
|
+
*/
|
|
44
|
+
id?: string;
|
|
45
|
+
/**
|
|
46
|
+
* Whether the color select should be shown by default.
|
|
47
|
+
*/
|
|
48
|
+
defaultShowColorSelect?: boolean;
|
|
41
49
|
}
|
|
42
50
|
declare const ColorPicker: import("svelte").Component<Props, {}, "color">;
|
|
43
51
|
type ColorPicker = ReturnType<typeof ColorPicker>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import ColorPicker from './ColorPicker.svelte';
|
|
3
|
+
let { initialColor = '#000000', oncolorchange } = $props();
|
|
4
|
+
let color = $state(initialColor);
|
|
5
|
+
|
|
6
|
+
//eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
7
|
+
function handleColorChange(fullColor: any) {
|
|
8
|
+
color = fullColor.hex;
|
|
9
|
+
oncolorchange?.(fullColor);
|
|
10
|
+
}
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<label for="color-input">Color hex value</label>
|
|
14
|
+
<ColorPicker id="color-input" bind:color oncolorchange={handleColorChange} />
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { onMount } from 'svelte';
|
|
2
|
+
import { onMount, tick } from 'svelte';
|
|
3
|
+
|
|
4
|
+
import { normalizeHex } from '../../utils/color-utils';
|
|
3
5
|
|
|
4
6
|
// Color object type definition
|
|
5
7
|
interface ColorObject {
|
|
@@ -83,6 +85,29 @@
|
|
|
83
85
|
let dragStartPosition = $state<{ x: number; y: number } | null>(null);
|
|
84
86
|
const DRAG_THRESHOLD = 3; // pixels of movement before considering it a drag
|
|
85
87
|
|
|
88
|
+
// Helper function to normalize color input to hex
|
|
89
|
+
function normalizeColorToHex(colorInput: string): string {
|
|
90
|
+
// If it's already a valid hex, normalize it
|
|
91
|
+
if (colorInput.startsWith('#')) {
|
|
92
|
+
return normalizeHex(colorInput);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// For named colors, use a canvas to convert to hex
|
|
96
|
+
const canvas = document.createElement('canvas');
|
|
97
|
+
const ctx = canvas.getContext('2d');
|
|
98
|
+
if (ctx) {
|
|
99
|
+
ctx.fillStyle = colorInput;
|
|
100
|
+
const computedColor = ctx.fillStyle;
|
|
101
|
+
// ctx.fillStyle returns hex format for valid colors
|
|
102
|
+
if (computedColor.startsWith('#')) {
|
|
103
|
+
return computedColor.toUpperCase();
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Fallback to original value if conversion fails
|
|
108
|
+
return normalizeHex(colorInput);
|
|
109
|
+
}
|
|
110
|
+
|
|
86
111
|
// Color conversion utilities
|
|
87
112
|
function hsbToRgb(h: number, s: number, b: number): [number, number, number] {
|
|
88
113
|
h = h / 360;
|
|
@@ -211,10 +236,26 @@
|
|
|
211
236
|
return result;
|
|
212
237
|
}
|
|
213
238
|
|
|
214
|
-
// For non-hex colors,
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
239
|
+
// For non-hex colors, try to validate using canvas
|
|
240
|
+
try {
|
|
241
|
+
const canvas = document.createElement('canvas');
|
|
242
|
+
const ctx = canvas.getContext('2d');
|
|
243
|
+
if (ctx) {
|
|
244
|
+
ctx.fillStyle = value;
|
|
245
|
+
return (
|
|
246
|
+
ctx.fillStyle !== '#000000' ||
|
|
247
|
+
value === 'black' ||
|
|
248
|
+
value === '#000000' ||
|
|
249
|
+
value === '#000'
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
} catch (e) {
|
|
253
|
+
// Fallback to regex for hex without #
|
|
254
|
+
const hexRegex = /^([0-9A-Fa-f]{3}|[0-9A-Fa-f]{4}|[0-9A-Fa-f]{6}|[0-9A-Fa-f]{8})$/;
|
|
255
|
+
return hexRegex.test(value);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return false;
|
|
218
259
|
}
|
|
219
260
|
|
|
220
261
|
function rgbToHsb(r: number, g: number, b: number): [number, number, number] {
|
|
@@ -266,8 +307,16 @@
|
|
|
266
307
|
const rect = colorWell.getBoundingClientRect();
|
|
267
308
|
const x = Math.max(0, Math.min(rect.width, event.clientX - rect.left));
|
|
268
309
|
const y = Math.max(0, Math.min(rect.height, event.clientY - rect.top));
|
|
310
|
+
|
|
311
|
+
// Always update HSB values first
|
|
269
312
|
saturation = Math.round((x / rect.width) * 100);
|
|
270
313
|
brightness = Math.round(100 - (y / rect.height) * 100);
|
|
314
|
+
|
|
315
|
+
// If in RGB mode, sync the RGB values with the new HSB values
|
|
316
|
+
if (mode === 'RGB') {
|
|
317
|
+
[rgbRed, rgbGreen, rgbBlue] = hsbToRgb(hue, saturation, brightness);
|
|
318
|
+
}
|
|
319
|
+
|
|
271
320
|
updateColor();
|
|
272
321
|
updateColorPickerPosition();
|
|
273
322
|
}
|
|
@@ -276,16 +325,31 @@
|
|
|
276
325
|
if (!hueBar) return;
|
|
277
326
|
const rect = hueBar.getBoundingClientRect();
|
|
278
327
|
const x = Math.max(0, Math.min(rect.width, event.clientX - rect.left));
|
|
328
|
+
|
|
329
|
+
// Always update HSB hue first
|
|
279
330
|
hue = Math.round((x / rect.width) * 360);
|
|
331
|
+
|
|
332
|
+
// If in RGB mode, sync the RGB values with the new HSB values
|
|
333
|
+
if (mode === 'RGB') {
|
|
334
|
+
[rgbRed, rgbGreen, rgbBlue] = hsbToRgb(hue, saturation, brightness);
|
|
335
|
+
}
|
|
336
|
+
|
|
280
337
|
updateColor();
|
|
281
338
|
}
|
|
282
339
|
|
|
283
340
|
function handleAlphaBarInteraction(event: MouseEvent) {
|
|
284
341
|
if (!alphaBar) return;
|
|
342
|
+
|
|
285
343
|
const rect = alphaBar.getBoundingClientRect();
|
|
286
344
|
const x = Math.max(0, Math.min(rect.width, event.clientX - rect.left));
|
|
287
|
-
|
|
288
|
-
|
|
345
|
+
|
|
346
|
+
let newAlpha = Math.round((x / rect.width) * 100);
|
|
347
|
+
|
|
348
|
+
if (isNaN(newAlpha) || typeof newAlpha !== 'number') newAlpha = 100;
|
|
349
|
+
|
|
350
|
+
alpha = newAlpha;
|
|
351
|
+
|
|
352
|
+
updateColor();
|
|
289
353
|
}
|
|
290
354
|
|
|
291
355
|
function handleHexChange(event: Event) {
|
|
@@ -442,18 +506,18 @@
|
|
|
442
506
|
return min + (value * (max - min)) / range;
|
|
443
507
|
}
|
|
444
508
|
|
|
445
|
-
// Watch for prop changes
|
|
509
|
+
// Watch for prop changes - FIXED: Better color normalization
|
|
446
510
|
$effect(() => {
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
511
|
+
const normalized = normalizeColorToHex(color);
|
|
512
|
+
if (normalized !== hexValue) {
|
|
513
|
+
hexValue = normalized;
|
|
514
|
+
const [h, s, b] = hexToHsb(normalized);
|
|
515
|
+
hue = h;
|
|
516
|
+
saturation = s;
|
|
517
|
+
brightness = b;
|
|
518
|
+
[rgbRed, rgbGreen, rgbBlue] = hsbToRgb(hue, saturation, brightness);
|
|
519
|
+
// Force position update after state changes
|
|
520
|
+
setTimeout(() => updateColorPickerPosition(), 0);
|
|
457
521
|
}
|
|
458
522
|
});
|
|
459
523
|
|
|
@@ -462,18 +526,19 @@
|
|
|
462
526
|
);
|
|
463
527
|
|
|
464
528
|
onMount(() => {
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
}
|
|
474
|
-
|
|
529
|
+
const normalized = normalizeColorToHex(color);
|
|
530
|
+
hexValue = normalized;
|
|
531
|
+
const [h, s, b] = hexToHsb(normalized);
|
|
532
|
+
hue = h;
|
|
533
|
+
saturation = s;
|
|
534
|
+
brightness = b;
|
|
535
|
+
[rgbRed, rgbGreen, rgbBlue] = hsbToRgb(hue, saturation, brightness);
|
|
536
|
+
|
|
537
|
+
console.log('ColorSelect mounted', { color });
|
|
475
538
|
updateColor();
|
|
476
|
-
|
|
539
|
+
// Delay position update to ensure DOM is ready
|
|
540
|
+
|
|
541
|
+
setTimeout(() => updateColorPickerPosition(), 5);
|
|
477
542
|
|
|
478
543
|
document.addEventListener('mousemove', handleMouseMove);
|
|
479
544
|
document.addEventListener('mouseup', handleMouseUp);
|
|
@@ -511,6 +576,7 @@
|
|
|
511
576
|
}
|
|
512
577
|
}
|
|
513
578
|
|
|
579
|
+
// Add an $effect to always update the color well and picker position after state changes
|
|
514
580
|
$effect(() => {
|
|
515
581
|
updateColorPickerPosition();
|
|
516
582
|
});
|
|
@@ -744,7 +810,9 @@
|
|
|
744
810
|
oninput={(e) => {
|
|
745
811
|
const target = e.target as HTMLInputElement;
|
|
746
812
|
if (!target) return;
|
|
747
|
-
|
|
813
|
+
let newAlpha = +target.value;
|
|
814
|
+
if (isNaN(newAlpha) || typeof newAlpha !== 'number') newAlpha = 100;
|
|
815
|
+
alpha = newAlpha;
|
|
748
816
|
emitColorChange(hexValue, alpha);
|
|
749
817
|
}}
|
|
750
818
|
/>
|
|
@@ -928,7 +996,7 @@
|
|
|
928
996
|
/* Controls */
|
|
929
997
|
.controls {
|
|
930
998
|
display: grid;
|
|
931
|
-
grid-template-columns:
|
|
999
|
+
grid-template-columns: 80px 1fr 30px;
|
|
932
1000
|
gap: 7px;
|
|
933
1001
|
width: 100%;
|
|
934
1002
|
}
|
|
@@ -980,7 +1048,6 @@
|
|
|
980
1048
|
border-radius: 4px;
|
|
981
1049
|
color: var(--text1, #ebebeb);
|
|
982
1050
|
font-size: 11px;
|
|
983
|
-
font-family: Inter, sans-serif;
|
|
984
1051
|
font-weight: 400;
|
|
985
1052
|
line-height: 16px;
|
|
986
1053
|
outline: none;
|
|
@@ -988,7 +1055,7 @@
|
|
|
988
1055
|
}
|
|
989
1056
|
|
|
990
1057
|
.input--hex {
|
|
991
|
-
width:
|
|
1058
|
+
width: 80px;
|
|
992
1059
|
text-align: left;
|
|
993
1060
|
}
|
|
994
1061
|
|
|
@@ -1000,7 +1067,6 @@
|
|
|
1000
1067
|
.label {
|
|
1001
1068
|
color: var(--text1, #ebebeb);
|
|
1002
1069
|
font-size: 11px;
|
|
1003
|
-
font-family: Inter, sans-serif;
|
|
1004
1070
|
font-weight: 400;
|
|
1005
1071
|
line-height: 16px;
|
|
1006
1072
|
text-align: center;
|
|
@@ -167,7 +167,6 @@
|
|
|
167
167
|
.copy-text__title {
|
|
168
168
|
margin: 0;
|
|
169
169
|
color: var(--text-color-primary, #ffffff);
|
|
170
|
-
font-family: Inter, sans-serif;
|
|
171
170
|
font-size: 12px;
|
|
172
171
|
font-weight: 500;
|
|
173
172
|
line-height: 16px;
|
|
@@ -181,7 +180,6 @@
|
|
|
181
180
|
align-items: flex-start;
|
|
182
181
|
align-self: stretch;
|
|
183
182
|
color: var(--text2);
|
|
184
|
-
font-family: Inter;
|
|
185
183
|
font-size: 12px;
|
|
186
184
|
font-style: normal;
|
|
187
185
|
font-weight: 500;
|
|
@@ -327,7 +327,6 @@
|
|
|
327
327
|
|
|
328
328
|
.tab-text {
|
|
329
329
|
color: inherit;
|
|
330
|
-
font-family: Inter;
|
|
331
330
|
font-size: 11.5px;
|
|
332
331
|
font-style: normal;
|
|
333
332
|
font-weight: 400;
|
|
@@ -402,7 +401,7 @@
|
|
|
402
401
|
|
|
403
402
|
.preview-bar-content span {
|
|
404
403
|
color: var(--actionPrimaryText);
|
|
405
|
-
|
|
404
|
+
|
|
406
405
|
font-size: 11.5px;
|
|
407
406
|
font-style: normal;
|
|
408
407
|
font-weight: 500;
|
|
@@ -462,7 +462,7 @@
|
|
|
462
462
|
font-weight: 500;
|
|
463
463
|
font-size: 11.5px;
|
|
464
464
|
color: var(--text1);
|
|
465
|
-
|
|
465
|
+
|
|
466
466
|
text-align: center;
|
|
467
467
|
}
|
|
468
468
|
|
|
@@ -474,7 +474,7 @@
|
|
|
474
474
|
background: var(--background1);
|
|
475
475
|
color: var(--text1);
|
|
476
476
|
font-size: 11.5px;
|
|
477
|
-
|
|
477
|
+
|
|
478
478
|
box-shadow: var(--boxShadows-input-inner);
|
|
479
479
|
transition: all 0.2s ease;
|
|
480
480
|
}
|
|
@@ -530,7 +530,7 @@
|
|
|
530
530
|
flex: 1;
|
|
531
531
|
font-size: 11.5px;
|
|
532
532
|
color: var(--text1);
|
|
533
|
-
|
|
533
|
+
|
|
534
534
|
line-height: 1.2;
|
|
535
535
|
}
|
|
536
536
|
|
|
@@ -237,7 +237,7 @@
|
|
|
237
237
|
|
|
238
238
|
.message {
|
|
239
239
|
color: var(--text-text-2, #bdbdbd);
|
|
240
|
-
|
|
240
|
+
|
|
241
241
|
font-size: 11px;
|
|
242
242
|
font-style: normal;
|
|
243
243
|
font-weight: 400;
|
|
@@ -252,7 +252,7 @@
|
|
|
252
252
|
|
|
253
253
|
.link {
|
|
254
254
|
color: var(--blue-blue-text, #8ac2ff);
|
|
255
|
-
|
|
255
|
+
|
|
256
256
|
font-size: 11px;
|
|
257
257
|
font-style: normal;
|
|
258
258
|
font-weight: 400;
|
|
@@ -553,7 +553,7 @@
|
|
|
553
553
|
}
|
|
554
554
|
.label .label-name {
|
|
555
555
|
color: var(--text1);
|
|
556
|
-
|
|
556
|
+
|
|
557
557
|
font-size: 11.5px;
|
|
558
558
|
font-style: normal;
|
|
559
559
|
font-weight: 400;
|
|
@@ -566,7 +566,7 @@
|
|
|
566
566
|
|
|
567
567
|
.label .label-description {
|
|
568
568
|
color: var(--text2, #bdbdbd);
|
|
569
|
-
|
|
569
|
+
|
|
570
570
|
font-size: 10px;
|
|
571
571
|
font-style: normal;
|
|
572
572
|
font-weight: 400;
|
|
@@ -645,7 +645,7 @@
|
|
|
645
645
|
gap: 4px;
|
|
646
646
|
align-self: stretch;
|
|
647
647
|
color: var(--text2, #bdbdbd);
|
|
648
|
-
|
|
648
|
+
|
|
649
649
|
font-size: 11px;
|
|
650
650
|
font-style: normal;
|
|
651
651
|
font-weight: 500;
|
|
@@ -679,7 +679,7 @@
|
|
|
679
679
|
gap: 4px;
|
|
680
680
|
align-self: stretch;
|
|
681
681
|
color: var(--text-text-1, #d9d9d9);
|
|
682
|
-
|
|
682
|
+
|
|
683
683
|
font-size: 11px;
|
|
684
684
|
font-style: normal;
|
|
685
685
|
font-weight: 400;
|
|
@@ -813,10 +813,6 @@
|
|
|
813
813
|
{/if}
|
|
814
814
|
|
|
815
815
|
<style>
|
|
816
|
-
.text {
|
|
817
|
-
font-family: inherit;
|
|
818
|
-
}
|
|
819
|
-
|
|
820
816
|
.labels.link {
|
|
821
817
|
cursor: pointer;
|
|
822
818
|
padding: 4px;
|
|
@@ -882,7 +878,6 @@
|
|
|
882
878
|
}
|
|
883
879
|
|
|
884
880
|
* {
|
|
885
|
-
font-family: Inter;
|
|
886
881
|
font-style: normal;
|
|
887
882
|
line-height: 16px;
|
|
888
883
|
letter-spacing: -0.115px;
|
|
@@ -950,7 +945,7 @@
|
|
|
950
945
|
|
|
951
946
|
.popup-description span {
|
|
952
947
|
color: var(--text2, #bdbdbd);
|
|
953
|
-
|
|
948
|
+
|
|
954
949
|
font-size: 11px;
|
|
955
950
|
font-style: normal;
|
|
956
951
|
font-weight: 400;
|
package/dist/ui/index.css
CHANGED
|
@@ -161,7 +161,6 @@
|
|
|
161
161
|
margin: 0 auto;
|
|
162
162
|
background: var(--background1);
|
|
163
163
|
color: var(--text1);
|
|
164
|
-
font-family: var(--font-stack);
|
|
165
164
|
}
|
|
166
165
|
|
|
167
166
|
.start-demo {
|
|
@@ -211,7 +210,7 @@
|
|
|
211
210
|
cursor: pointer;
|
|
212
211
|
font-size: var(--font-size-small);
|
|
213
212
|
font-weight: var(--font-weight-normal);
|
|
214
|
-
|
|
213
|
+
|
|
215
214
|
transition: all 0.2s ease;
|
|
216
215
|
}
|
|
217
216
|
|
|
@@ -252,7 +251,6 @@
|
|
|
252
251
|
border: 1px solid var(--border2);
|
|
253
252
|
padding: var(--padding-tiny);
|
|
254
253
|
border-radius: var(--border-radius);
|
|
255
|
-
font-family: monospace;
|
|
256
254
|
font-size: var(--font-size-small);
|
|
257
255
|
color: var(--text2);
|
|
258
256
|
display: block;
|
|
@@ -290,7 +290,6 @@
|
|
|
290
290
|
cursor: pointer;
|
|
291
291
|
transition: all 0.3s ease;
|
|
292
292
|
width: 100%;
|
|
293
|
-
font-family: inherit;
|
|
294
293
|
font-size: inherit;
|
|
295
294
|
}
|
|
296
295
|
|
|
@@ -553,7 +552,6 @@
|
|
|
553
552
|
|
|
554
553
|
.debug-info p {
|
|
555
554
|
margin: 0.5rem 0;
|
|
556
|
-
font-family: 'SFMono-Regular', Consolas, monospace;
|
|
557
555
|
font-size: 0.875rem;
|
|
558
556
|
color: #495057;
|
|
559
557
|
}
|
|
@@ -169,7 +169,6 @@
|
|
|
169
169
|
background: #e9ecef;
|
|
170
170
|
padding: 0.2rem 0.4rem;
|
|
171
171
|
border-radius: 3px;
|
|
172
|
-
font-family: 'SFMono-Regular', Consolas, monospace;
|
|
173
172
|
font-size: 0.875rem;
|
|
174
173
|
color: #e83e8c;
|
|
175
174
|
}
|
|
@@ -189,7 +188,6 @@
|
|
|
189
188
|
|
|
190
189
|
.debug-info p {
|
|
191
190
|
margin: 0.5rem 0;
|
|
192
|
-
font-family: 'SFMono-Regular', Consolas, monospace;
|
|
193
191
|
font-size: 0.875rem;
|
|
194
192
|
color: #495057;
|
|
195
193
|
}
|
|
@@ -132,7 +132,6 @@
|
|
|
132
132
|
background: #e9ecef;
|
|
133
133
|
padding: 0.2rem 0.4rem;
|
|
134
134
|
border-radius: 3px;
|
|
135
|
-
font-family: 'SFMono-Regular', Consolas, monospace;
|
|
136
135
|
color: #e83e8c;
|
|
137
136
|
font-size: 0.875rem;
|
|
138
137
|
}
|
|
@@ -273,7 +272,6 @@
|
|
|
273
272
|
|
|
274
273
|
.debug-info p {
|
|
275
274
|
margin: 0.5rem 0;
|
|
276
|
-
font-family: 'SFMono-Regular', Consolas, monospace;
|
|
277
275
|
font-size: 0.875rem;
|
|
278
276
|
color: #495057;
|
|
279
277
|
}
|
|
@@ -296,7 +296,6 @@
|
|
|
296
296
|
margin: 0 auto;
|
|
297
297
|
background: var(--background1);
|
|
298
298
|
color: var(--text1);
|
|
299
|
-
font-family: var(--font-stack);
|
|
300
299
|
}
|
|
301
300
|
|
|
302
301
|
.demo-controls {
|
|
@@ -375,7 +374,6 @@
|
|
|
375
374
|
background: var(--background1);
|
|
376
375
|
color: var(--text1);
|
|
377
376
|
font-size: var(--font-size-small);
|
|
378
|
-
font-family: var(--font-stack);
|
|
379
377
|
}
|
|
380
378
|
|
|
381
379
|
input:focus {
|
|
@@ -413,7 +411,7 @@
|
|
|
413
411
|
cursor: pointer;
|
|
414
412
|
font-size: var(--font-size-small);
|
|
415
413
|
font-weight: var(--font-weight-normal);
|
|
416
|
-
|
|
414
|
+
|
|
417
415
|
transition: all 0.2s ease;
|
|
418
416
|
}
|
|
419
417
|
|
|
@@ -509,7 +507,6 @@
|
|
|
509
507
|
background: var(--background3);
|
|
510
508
|
border: 1px solid var(--border2);
|
|
511
509
|
border-radius: var(--border-radius);
|
|
512
|
-
font-family: monospace;
|
|
513
510
|
font-size: var(--font-size-tiny);
|
|
514
511
|
color: var(--text3);
|
|
515
512
|
}
|
|
@@ -519,7 +516,6 @@
|
|
|
519
516
|
border: 1px solid var(--border2);
|
|
520
517
|
padding: var(--padding-tiny);
|
|
521
518
|
border-radius: var(--border-radius);
|
|
522
|
-
font-family: monospace;
|
|
523
519
|
font-size: var(--font-size-tiny);
|
|
524
520
|
color: var(--text2);
|
|
525
521
|
display: block;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convert a color name to a hex value
|
|
3
|
+
* @param colorName - The color name to convert
|
|
4
|
+
* @returns The hex value of the color
|
|
5
|
+
*/
|
|
6
|
+
export declare function colorNameToHex(colorName: string): string | null;
|
|
7
|
+
/**
|
|
8
|
+
* Normalize a hex value
|
|
9
|
+
* @param value - The hex value to normalize
|
|
10
|
+
* @returns The normalized hex value
|
|
11
|
+
*/
|
|
12
|
+
export declare function normalizeHex(value: string): string;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convert a color name to a hex value
|
|
3
|
+
* @param colorName - The color name to convert
|
|
4
|
+
* @returns The hex value of the color
|
|
5
|
+
*/
|
|
6
|
+
export function colorNameToHex(colorName) {
|
|
7
|
+
const tempDiv = document.createElement('div');
|
|
8
|
+
tempDiv.style.color = colorName;
|
|
9
|
+
document.body.appendChild(tempDiv);
|
|
10
|
+
const rgbColor = window.getComputedStyle(tempDiv).color;
|
|
11
|
+
document.body.removeChild(tempDiv);
|
|
12
|
+
const match = rgbColor.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
|
|
13
|
+
if (match) {
|
|
14
|
+
const r = parseInt(match[1]);
|
|
15
|
+
const g = parseInt(match[2]);
|
|
16
|
+
const b = parseInt(match[3]);
|
|
17
|
+
const toHex = (c) => {
|
|
18
|
+
const hex = c.toString(16);
|
|
19
|
+
return hex.length === 1 ? '0' + hex : hex;
|
|
20
|
+
};
|
|
21
|
+
return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Normalize a hex value
|
|
29
|
+
* @param value - The hex value to normalize
|
|
30
|
+
* @returns The normalized hex value
|
|
31
|
+
*/
|
|
32
|
+
export function normalizeHex(value) {
|
|
33
|
+
let v = value.trim();
|
|
34
|
+
if (!v.startsWith('#')) {
|
|
35
|
+
const hex = colorNameToHex(v);
|
|
36
|
+
if (hex)
|
|
37
|
+
v = hex;
|
|
38
|
+
else
|
|
39
|
+
v = `#${v}`;
|
|
40
|
+
}
|
|
41
|
+
// Expand 3-digit hex to 6-digit
|
|
42
|
+
if (/^#[A-Fa-f0-9]{3}$/.test(v)) {
|
|
43
|
+
v = '#' + v[1] + v[1] + v[2] + v[2] + v[3] + v[3];
|
|
44
|
+
}
|
|
45
|
+
// Only accept valid 6-digit hex
|
|
46
|
+
if (/^#[A-Fa-f0-9]{6}$/.test(v)) {
|
|
47
|
+
return v.toUpperCase();
|
|
48
|
+
}
|
|
49
|
+
return value;
|
|
50
|
+
}
|
|
@@ -234,7 +234,7 @@ See console for the complete diff structure.
|
|
|
234
234
|
<style>
|
|
235
235
|
.demo-container {
|
|
236
236
|
padding: var(--spacing-24);
|
|
237
|
-
|
|
237
|
+
|
|
238
238
|
background: var(--background1);
|
|
239
239
|
color: var(--text1);
|
|
240
240
|
max-width: 800px;
|
|
@@ -261,7 +261,7 @@ See console for the complete diff structure.
|
|
|
261
261
|
cursor: pointer;
|
|
262
262
|
font-size: var(--font-size-small);
|
|
263
263
|
font-weight: var(--font-weight-normal);
|
|
264
|
-
|
|
264
|
+
|
|
265
265
|
transition: all 0.2s ease;
|
|
266
266
|
margin: var(--spacing-8) 0;
|
|
267
267
|
}
|
|
@@ -284,7 +284,6 @@ See console for the complete diff structure.
|
|
|
284
284
|
margin-top: var(--spacing-12);
|
|
285
285
|
white-space: pre-wrap;
|
|
286
286
|
border-radius: var(--border-radius);
|
|
287
|
-
font-family: monospace;
|
|
288
287
|
color: var(--text2);
|
|
289
288
|
font-size: var(--font-size-small);
|
|
290
289
|
}
|
package/dist/ui/utils/index.d.ts
CHANGED
package/dist/ui/utils/index.js
CHANGED