react-native-color-picker-palette 1.0.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.
- package/LICENSE +21 -0
- package/README.md +340 -0
- package/package.json +70 -0
- package/src/core/hooks/index.ts +2 -0
- package/src/core/hooks/useColor.ts +93 -0
- package/src/core/hooks/useComponentLayout.ts +38 -0
- package/src/core/index.ts +19 -0
- package/src/core/services/ColorService.ts +338 -0
- package/src/core/services/index.ts +1 -0
- package/src/core/types/index.ts +211 -0
- package/src/core/utils/clamp.ts +16 -0
- package/src/core/utils/format.ts +59 -0
- package/src/core/utils/index.ts +8 -0
- package/src/full/components/Alpha.tsx +221 -0
- package/src/full/components/ColorPicker.tsx +206 -0
- package/src/full/components/Fields/HexField.tsx +125 -0
- package/src/full/components/Fields/RgbFields.tsx +192 -0
- package/src/full/components/Fields/index.tsx +70 -0
- package/src/full/components/Hue.tsx +188 -0
- package/src/full/components/RectangleSaturation.tsx +203 -0
- package/src/full/components/Saturation.tsx +258 -0
- package/src/full/components/Thumb.tsx +47 -0
- package/src/full/components/Value.tsx +192 -0
- package/src/full/components/index.ts +8 -0
- package/src/full/index.ts +69 -0
- package/src/index.ts +19 -0
- package/src/lite/components/Alpha.tsx +228 -0
- package/src/lite/components/ColorPicker.tsx +209 -0
- package/src/lite/components/Fields/HexField.tsx +103 -0
- package/src/lite/components/Fields/RgbFields.tsx +138 -0
- package/src/lite/components/Fields/index.tsx +53 -0
- package/src/lite/components/Hue.tsx +192 -0
- package/src/lite/components/RectangleSaturation.tsx +238 -0
- package/src/lite/components/Saturation.tsx +289 -0
- package/src/lite/components/Thumb.tsx +47 -0
- package/src/lite/components/Value.tsx +201 -0
- package/src/lite/components/index.ts +8 -0
- package/src/lite/index.ts +75 -0
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
import type { IColor, IRGB, IHSV, ColorModel } from '../types';
|
|
2
|
+
import { clamp, toHexString } from '../utils';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* ColorService - Handles all color conversions between HEX, RGB, and HSV
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* // Convert from hex
|
|
9
|
+
* const color = ColorService.fromHex('#FF5500');
|
|
10
|
+
*
|
|
11
|
+
* // Convert from RGB
|
|
12
|
+
* const color = ColorService.fromRgb({ r: 255, g: 85, b: 0, a: 1 });
|
|
13
|
+
*
|
|
14
|
+
* // Convert from HSV
|
|
15
|
+
* const color = ColorService.fromHsv({ h: 20, s: 100, v: 100, a: 1 });
|
|
16
|
+
*
|
|
17
|
+
* // Get string representations
|
|
18
|
+
* ColorService.toRgbString(color.rgb); // "rgb(255, 85, 0)"
|
|
19
|
+
* ColorService.toRgbaString(color.rgb); // "rgba(255, 85, 0, 1)"
|
|
20
|
+
*/
|
|
21
|
+
export const ColorService = {
|
|
22
|
+
/**
|
|
23
|
+
* Convert from any color model to IColor (all formats)
|
|
24
|
+
*
|
|
25
|
+
* @param model - The color model type ('hex', 'rgb', or 'hsv')
|
|
26
|
+
* @param value - The color value in the specified model
|
|
27
|
+
* @returns Complete color object with all formats
|
|
28
|
+
*/
|
|
29
|
+
convert<T extends ColorModel>(
|
|
30
|
+
model: T,
|
|
31
|
+
value: T extends 'hex' ? string : T extends 'rgb' ? IRGB : IHSV
|
|
32
|
+
): IColor {
|
|
33
|
+
switch (model) {
|
|
34
|
+
case 'hex':
|
|
35
|
+
return ColorService.fromHex(value as string);
|
|
36
|
+
case 'rgb':
|
|
37
|
+
return ColorService.fromRgb(value as IRGB);
|
|
38
|
+
case 'hsv':
|
|
39
|
+
return ColorService.fromHsv(value as IHSV);
|
|
40
|
+
default:
|
|
41
|
+
throw new Error(`Unknown color model: ${model}`);
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Create IColor from hex string
|
|
47
|
+
*
|
|
48
|
+
* @param hex - Hex color string (e.g., "#FF0000", "#F00", "#FF0000FF")
|
|
49
|
+
* @returns Complete color object
|
|
50
|
+
*/
|
|
51
|
+
fromHex(hex: string): IColor {
|
|
52
|
+
const normalizedHex = ColorService.normalizeHex(hex);
|
|
53
|
+
const rgb = ColorService.hex2rgb(normalizedHex);
|
|
54
|
+
const hsv = ColorService.rgb2hsv(rgb);
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
hex: normalizedHex,
|
|
58
|
+
rgb,
|
|
59
|
+
hsv,
|
|
60
|
+
};
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Create IColor from RGB
|
|
65
|
+
*
|
|
66
|
+
* @param rgb - RGB color object
|
|
67
|
+
* @returns Complete color object
|
|
68
|
+
*/
|
|
69
|
+
fromRgb(rgb: IRGB): IColor {
|
|
70
|
+
const normalizedRgb = ColorService.normalizeRgb(rgb);
|
|
71
|
+
const hex = ColorService.rgb2hex(normalizedRgb);
|
|
72
|
+
const hsv = ColorService.rgb2hsv(normalizedRgb);
|
|
73
|
+
|
|
74
|
+
return {
|
|
75
|
+
hex,
|
|
76
|
+
rgb: normalizedRgb,
|
|
77
|
+
hsv,
|
|
78
|
+
};
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Create IColor from HSV
|
|
83
|
+
*
|
|
84
|
+
* @param hsv - HSV color object
|
|
85
|
+
* @returns Complete color object
|
|
86
|
+
*/
|
|
87
|
+
fromHsv(hsv: IHSV): IColor {
|
|
88
|
+
const normalizedHsv = ColorService.normalizeHsv(hsv);
|
|
89
|
+
const rgb = ColorService.hsv2rgb(normalizedHsv);
|
|
90
|
+
const hex = ColorService.rgb2hex(rgb);
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
hex,
|
|
94
|
+
rgb,
|
|
95
|
+
hsv: normalizedHsv,
|
|
96
|
+
};
|
|
97
|
+
},
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Normalize hex string to #RRGGBB or #RRGGBBAA format
|
|
101
|
+
*
|
|
102
|
+
* @param hex - Raw hex string
|
|
103
|
+
* @returns Normalized hex string
|
|
104
|
+
*/
|
|
105
|
+
normalizeHex(hex: string): string {
|
|
106
|
+
let h = hex.replace('#', '').toUpperCase();
|
|
107
|
+
|
|
108
|
+
// Handle short formats
|
|
109
|
+
if (h.length === 3) {
|
|
110
|
+
// #RGB -> #RRGGBB
|
|
111
|
+
h = h[0] + h[0] + h[1] + h[1] + h[2] + h[2];
|
|
112
|
+
} else if (h.length === 4) {
|
|
113
|
+
// #RGBA -> #RRGGBBAA
|
|
114
|
+
h = h[0] + h[0] + h[1] + h[1] + h[2] + h[2] + h[3] + h[3];
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Ensure minimum 6 characters
|
|
118
|
+
h = h.padEnd(6, '0');
|
|
119
|
+
|
|
120
|
+
return '#' + h.slice(0, 8); // Max 8 chars (RRGGBBAA)
|
|
121
|
+
},
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Normalize RGB values to valid ranges
|
|
125
|
+
*
|
|
126
|
+
* @param rgb - Raw RGB object
|
|
127
|
+
* @returns Normalized RGB object
|
|
128
|
+
*/
|
|
129
|
+
normalizeRgb(rgb: IRGB): IRGB {
|
|
130
|
+
return {
|
|
131
|
+
r: clamp(Math.round(rgb.r), 0, 255),
|
|
132
|
+
g: clamp(Math.round(rgb.g), 0, 255),
|
|
133
|
+
b: clamp(Math.round(rgb.b), 0, 255),
|
|
134
|
+
a: clamp(rgb.a ?? 1, 0, 1),
|
|
135
|
+
};
|
|
136
|
+
},
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Normalize HSV values to valid ranges
|
|
140
|
+
*
|
|
141
|
+
* @param hsv - Raw HSV object
|
|
142
|
+
* @returns Normalized HSV object
|
|
143
|
+
*/
|
|
144
|
+
normalizeHsv(hsv: IHSV): IHSV {
|
|
145
|
+
return {
|
|
146
|
+
h: clamp(hsv.h, 0, 360) % 360,
|
|
147
|
+
s: clamp(hsv.s, 0, 100),
|
|
148
|
+
v: clamp(hsv.v, 0, 100),
|
|
149
|
+
a: clamp(hsv.a ?? 1, 0, 1),
|
|
150
|
+
};
|
|
151
|
+
},
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Convert HEX to RGB
|
|
155
|
+
*
|
|
156
|
+
* @param hex - Hex color string
|
|
157
|
+
* @returns RGB object
|
|
158
|
+
*/
|
|
159
|
+
hex2rgb(hex: string): IRGB {
|
|
160
|
+
const h = hex.replace('#', '');
|
|
161
|
+
|
|
162
|
+
const r = parseInt(h.slice(0, 2), 16) || 0;
|
|
163
|
+
const g = parseInt(h.slice(2, 4), 16) || 0;
|
|
164
|
+
const b = parseInt(h.slice(4, 6), 16) || 0;
|
|
165
|
+
const a = h.length >= 8 ? parseInt(h.slice(6, 8), 16) / 255 : 1;
|
|
166
|
+
|
|
167
|
+
return { r, g, b, a };
|
|
168
|
+
},
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Convert RGB to HEX
|
|
172
|
+
*
|
|
173
|
+
* @param rgb - RGB object
|
|
174
|
+
* @returns Hex string
|
|
175
|
+
*/
|
|
176
|
+
rgb2hex(rgb: IRGB): string {
|
|
177
|
+
const r = toHexString(rgb.r);
|
|
178
|
+
const g = toHexString(rgb.g);
|
|
179
|
+
const b = toHexString(rgb.b);
|
|
180
|
+
|
|
181
|
+
let hex = `#${r}${g}${b}`.toUpperCase();
|
|
182
|
+
|
|
183
|
+
// Add alpha if not fully opaque
|
|
184
|
+
if (rgb.a !== undefined && rgb.a < 1) {
|
|
185
|
+
const a = toHexString(Math.round(rgb.a * 255));
|
|
186
|
+
hex += a.toUpperCase();
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return hex;
|
|
190
|
+
},
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Convert RGB to HSV
|
|
194
|
+
*
|
|
195
|
+
* @param rgb - RGB object
|
|
196
|
+
* @returns HSV object
|
|
197
|
+
*/
|
|
198
|
+
rgb2hsv(rgb: IRGB): IHSV {
|
|
199
|
+
const r = rgb.r / 255;
|
|
200
|
+
const g = rgb.g / 255;
|
|
201
|
+
const b = rgb.b / 255;
|
|
202
|
+
|
|
203
|
+
const max = Math.max(r, g, b);
|
|
204
|
+
const min = Math.min(r, g, b);
|
|
205
|
+
const delta = max - min;
|
|
206
|
+
|
|
207
|
+
let h = 0;
|
|
208
|
+
let s = 0;
|
|
209
|
+
const v = max * 100;
|
|
210
|
+
|
|
211
|
+
if (delta !== 0) {
|
|
212
|
+
s = (delta / max) * 100;
|
|
213
|
+
|
|
214
|
+
switch (max) {
|
|
215
|
+
case r:
|
|
216
|
+
h = ((g - b) / delta + (g < b ? 6 : 0)) * 60;
|
|
217
|
+
break;
|
|
218
|
+
case g:
|
|
219
|
+
h = ((b - r) / delta + 2) * 60;
|
|
220
|
+
break;
|
|
221
|
+
case b:
|
|
222
|
+
h = ((r - g) / delta + 4) * 60;
|
|
223
|
+
break;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return {
|
|
228
|
+
h: Math.round(h),
|
|
229
|
+
s: Math.round(s),
|
|
230
|
+
v: Math.round(v),
|
|
231
|
+
a: rgb.a ?? 1,
|
|
232
|
+
};
|
|
233
|
+
},
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Convert HSV to RGB
|
|
237
|
+
*
|
|
238
|
+
* @param hsv - HSV object
|
|
239
|
+
* @returns RGB object
|
|
240
|
+
*/
|
|
241
|
+
hsv2rgb(hsv: IHSV): IRGB {
|
|
242
|
+
const h = hsv.h / 360;
|
|
243
|
+
const s = hsv.s / 100;
|
|
244
|
+
const v = hsv.v / 100;
|
|
245
|
+
|
|
246
|
+
let r = 0;
|
|
247
|
+
let g = 0;
|
|
248
|
+
let b = 0;
|
|
249
|
+
|
|
250
|
+
if (s === 0) {
|
|
251
|
+
r = g = b = v;
|
|
252
|
+
} else {
|
|
253
|
+
const i = Math.floor(h * 6);
|
|
254
|
+
const f = h * 6 - i;
|
|
255
|
+
const p = v * (1 - s);
|
|
256
|
+
const q = v * (1 - f * s);
|
|
257
|
+
const t = v * (1 - (1 - f) * s);
|
|
258
|
+
|
|
259
|
+
switch (i % 6) {
|
|
260
|
+
case 0:
|
|
261
|
+
r = v;
|
|
262
|
+
g = t;
|
|
263
|
+
b = p;
|
|
264
|
+
break;
|
|
265
|
+
case 1:
|
|
266
|
+
r = q;
|
|
267
|
+
g = v;
|
|
268
|
+
b = p;
|
|
269
|
+
break;
|
|
270
|
+
case 2:
|
|
271
|
+
r = p;
|
|
272
|
+
g = v;
|
|
273
|
+
b = t;
|
|
274
|
+
break;
|
|
275
|
+
case 3:
|
|
276
|
+
r = p;
|
|
277
|
+
g = q;
|
|
278
|
+
b = v;
|
|
279
|
+
break;
|
|
280
|
+
case 4:
|
|
281
|
+
r = t;
|
|
282
|
+
g = p;
|
|
283
|
+
b = v;
|
|
284
|
+
break;
|
|
285
|
+
case 5:
|
|
286
|
+
r = v;
|
|
287
|
+
g = p;
|
|
288
|
+
b = q;
|
|
289
|
+
break;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
return {
|
|
294
|
+
r: Math.round(r * 255),
|
|
295
|
+
g: Math.round(g * 255),
|
|
296
|
+
b: Math.round(b * 255),
|
|
297
|
+
a: hsv.a ?? 1,
|
|
298
|
+
};
|
|
299
|
+
},
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Get RGB string for styling
|
|
303
|
+
*
|
|
304
|
+
* @param rgb - RGB object
|
|
305
|
+
* @returns CSS rgb() string
|
|
306
|
+
*/
|
|
307
|
+
toRgbString(rgb: IRGB): string {
|
|
308
|
+
return `rgb(${rgb.r}, ${rgb.g}, ${rgb.b})`;
|
|
309
|
+
},
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Get RGBA string for styling
|
|
313
|
+
*
|
|
314
|
+
* @param rgb - RGB object
|
|
315
|
+
* @returns CSS rgba() string
|
|
316
|
+
*/
|
|
317
|
+
toRgbaString(rgb: IRGB): string {
|
|
318
|
+
return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${rgb.a})`;
|
|
319
|
+
},
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Get HSL string from HSV (for gradients)
|
|
323
|
+
*
|
|
324
|
+
* @param hsv - HSV object
|
|
325
|
+
* @returns CSS hsl() string
|
|
326
|
+
*/
|
|
327
|
+
toHslString(hsv: IHSV): string {
|
|
328
|
+
// Convert HSV to HSL
|
|
329
|
+
const h = hsv.h;
|
|
330
|
+
const s = hsv.s / 100;
|
|
331
|
+
const v = hsv.v / 100;
|
|
332
|
+
|
|
333
|
+
const l = v * (1 - s / 2);
|
|
334
|
+
const sl = l === 0 || l === 1 ? 0 : (v - l) / Math.min(l, 1 - l);
|
|
335
|
+
|
|
336
|
+
return `hsl(${h}, ${Math.round(sl * 100)}%, ${Math.round(l * 100)}%)`;
|
|
337
|
+
},
|
|
338
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { ColorService } from './ColorService';
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RGB color representation
|
|
3
|
+
*
|
|
4
|
+
* @property r - Red channel (0-255)
|
|
5
|
+
* @property g - Green channel (0-255)
|
|
6
|
+
* @property b - Blue channel (0-255)
|
|
7
|
+
* @property a - Alpha channel (0-1)
|
|
8
|
+
*/
|
|
9
|
+
export interface IRGB {
|
|
10
|
+
r: number;
|
|
11
|
+
g: number;
|
|
12
|
+
b: number;
|
|
13
|
+
a: number;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* HSV color representation
|
|
18
|
+
*
|
|
19
|
+
* @property h - Hue (0-360)
|
|
20
|
+
* @property s - Saturation (0-100)
|
|
21
|
+
* @property v - Value/Brightness (0-100)
|
|
22
|
+
* @property a - Alpha channel (0-1)
|
|
23
|
+
*/
|
|
24
|
+
export interface IHSV {
|
|
25
|
+
h: number;
|
|
26
|
+
s: number;
|
|
27
|
+
v: number;
|
|
28
|
+
a: number;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Complete color object with all formats
|
|
33
|
+
*
|
|
34
|
+
* @property hex - Hex string (e.g., "#FF0000" or "#FF0000FF" with alpha)
|
|
35
|
+
* @property rgb - RGB representation
|
|
36
|
+
* @property hsv - HSV representation
|
|
37
|
+
*/
|
|
38
|
+
export interface IColor {
|
|
39
|
+
hex: string;
|
|
40
|
+
rgb: IRGB;
|
|
41
|
+
hsv: IHSV;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Color model types for conversion
|
|
46
|
+
*/
|
|
47
|
+
export type ColorModel = 'hex' | 'rgb' | 'hsv';
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Props for the main ColorPicker component
|
|
51
|
+
*/
|
|
52
|
+
export interface IColorPickerProps {
|
|
53
|
+
/**
|
|
54
|
+
* Current color value
|
|
55
|
+
*/
|
|
56
|
+
color: IColor;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Called on every color change during interaction
|
|
60
|
+
*/
|
|
61
|
+
onChange: (color: IColor) => void;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Called when interaction ends (finger lifted)
|
|
65
|
+
*/
|
|
66
|
+
onChangeComplete?: (color: IColor) => void;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Width of the picker (diameter for circle, width for rectangle)
|
|
70
|
+
* @default 250
|
|
71
|
+
*/
|
|
72
|
+
width?: number;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Height of the hue and alpha bars
|
|
76
|
+
* @default 10
|
|
77
|
+
*/
|
|
78
|
+
barHeight?: number;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Size of the thumb indicators
|
|
82
|
+
* @default 24
|
|
83
|
+
*/
|
|
84
|
+
thumbSize?: number;
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Hide the hue slider bar
|
|
88
|
+
* @default false
|
|
89
|
+
*/
|
|
90
|
+
hideHue?: boolean;
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Hide the alpha slider bar
|
|
94
|
+
* @default false
|
|
95
|
+
*/
|
|
96
|
+
hideAlpha?: boolean;
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Hide the color preview
|
|
100
|
+
* @default false
|
|
101
|
+
*/
|
|
102
|
+
hidePreview?: boolean;
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Hide the input fields
|
|
106
|
+
* @default false
|
|
107
|
+
*/
|
|
108
|
+
hideInput?: boolean;
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Disable all interactions
|
|
112
|
+
* @default false
|
|
113
|
+
*/
|
|
114
|
+
disabled?: boolean;
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Picker variant: 'circle' (color wheel) or 'rectangle' (SV rectangle)
|
|
118
|
+
* @default 'rectangle'
|
|
119
|
+
*/
|
|
120
|
+
variant?: 'circle' | 'rectangle';
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Props for the Saturation component (circular color wheel)
|
|
125
|
+
*/
|
|
126
|
+
export interface ISaturationProps {
|
|
127
|
+
color: IColor;
|
|
128
|
+
onChange: (color: IColor) => void;
|
|
129
|
+
onChangeComplete?: (color: IColor) => void;
|
|
130
|
+
size: number;
|
|
131
|
+
thumbSize: number;
|
|
132
|
+
disabled?: boolean;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Props for the RectangleSaturation component
|
|
137
|
+
*/
|
|
138
|
+
export interface IRectangleSaturationProps {
|
|
139
|
+
color: IColor;
|
|
140
|
+
onChange: (color: IColor) => void;
|
|
141
|
+
onChangeComplete?: (color: IColor) => void;
|
|
142
|
+
width: number;
|
|
143
|
+
height: number;
|
|
144
|
+
thumbSize: number;
|
|
145
|
+
disabled?: boolean;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Props for the Hue component
|
|
150
|
+
*/
|
|
151
|
+
export interface IHueProps {
|
|
152
|
+
color: IColor;
|
|
153
|
+
onChange: (color: IColor) => void;
|
|
154
|
+
onChangeComplete?: (color: IColor) => void;
|
|
155
|
+
barHeight: number;
|
|
156
|
+
thumbSize: number;
|
|
157
|
+
disabled?: boolean;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Props for the Alpha component
|
|
162
|
+
*/
|
|
163
|
+
export interface IAlphaProps {
|
|
164
|
+
color: IColor;
|
|
165
|
+
onChange: (color: IColor) => void;
|
|
166
|
+
onChangeComplete?: (color: IColor) => void;
|
|
167
|
+
barHeight: number;
|
|
168
|
+
thumbSize: number;
|
|
169
|
+
disabled?: boolean;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Props for the Value/Brightness component
|
|
174
|
+
*/
|
|
175
|
+
export interface IValueProps {
|
|
176
|
+
color: IColor;
|
|
177
|
+
onChange: (color: IColor) => void;
|
|
178
|
+
onChangeComplete?: (color: IColor) => void;
|
|
179
|
+
barHeight: number;
|
|
180
|
+
thumbSize: number;
|
|
181
|
+
disabled?: boolean;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Props for the Thumb component
|
|
186
|
+
*/
|
|
187
|
+
export interface IThumbProps {
|
|
188
|
+
size: number;
|
|
189
|
+
color?: string;
|
|
190
|
+
style?: object;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Props for input fields
|
|
195
|
+
*/
|
|
196
|
+
export interface IFieldsProps {
|
|
197
|
+
color: IColor;
|
|
198
|
+
onChange: (color: IColor) => void;
|
|
199
|
+
onChangeComplete?: (color: IColor) => void;
|
|
200
|
+
disabled?: boolean;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Layout information from onLayout event
|
|
205
|
+
*/
|
|
206
|
+
export interface ILayout {
|
|
207
|
+
width: number;
|
|
208
|
+
height: number;
|
|
209
|
+
x: number;
|
|
210
|
+
y: number;
|
|
211
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clamps a value between a minimum and maximum
|
|
3
|
+
*
|
|
4
|
+
* @param value - The value to clamp
|
|
5
|
+
* @param min - Minimum allowed value
|
|
6
|
+
* @param max - Maximum allowed value
|
|
7
|
+
* @returns The clamped value
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* clamp(150, 0, 100) // returns 100
|
|
11
|
+
* clamp(-10, 0, 100) // returns 0
|
|
12
|
+
* clamp(50, 0, 100) // returns 50
|
|
13
|
+
*/
|
|
14
|
+
export const clamp = (value: number, min: number, max: number): number => {
|
|
15
|
+
return Math.min(Math.max(value, min), max);
|
|
16
|
+
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pads a string with leading zeros
|
|
3
|
+
*
|
|
4
|
+
* @param str - The string to pad
|
|
5
|
+
* @param len - The target length
|
|
6
|
+
* @returns The padded string
|
|
7
|
+
*/
|
|
8
|
+
export const padZero = (str: string, len: number = 2): string => {
|
|
9
|
+
return str.padStart(len, '0');
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Converts a number to a two-digit hex string
|
|
14
|
+
*
|
|
15
|
+
* @param num - The number to convert (0-255)
|
|
16
|
+
* @returns Two-character hex string
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* toHexString(255) // returns "FF"
|
|
20
|
+
* toHexString(0) // returns "00"
|
|
21
|
+
* toHexString(15) // returns "0F"
|
|
22
|
+
*/
|
|
23
|
+
export const toHexString = (num: number): string => {
|
|
24
|
+
return padZero(Math.round(num).toString(16), 2);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Rounds a number to specified decimal places
|
|
29
|
+
*
|
|
30
|
+
* @param num - The number to round
|
|
31
|
+
* @param decimals - Number of decimal places
|
|
32
|
+
* @returns The rounded number
|
|
33
|
+
*/
|
|
34
|
+
export const round = (num: number, decimals: number = 0): number => {
|
|
35
|
+
const factor = Math.pow(10, decimals);
|
|
36
|
+
return Math.round(num * factor) / factor;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Parses a float and returns 0 if NaN
|
|
41
|
+
*
|
|
42
|
+
* @param value - The string to parse
|
|
43
|
+
* @returns Parsed float or 0
|
|
44
|
+
*/
|
|
45
|
+
export const safeParseFloat = (value: string): number => {
|
|
46
|
+
const parsed = parseFloat(value);
|
|
47
|
+
return isNaN(parsed) ? 0 : parsed;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Parses an int and returns 0 if NaN
|
|
52
|
+
*
|
|
53
|
+
* @param value - The string to parse
|
|
54
|
+
* @returns Parsed int or 0
|
|
55
|
+
*/
|
|
56
|
+
export const safeParseInt = (value: string): number => {
|
|
57
|
+
const parsed = parseInt(value, 10);
|
|
58
|
+
return isNaN(parsed) ? 0 : parsed;
|
|
59
|
+
};
|