reanimated-color-picker 0.0.1

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/ColorPicker.js ADDED
@@ -0,0 +1,724 @@
1
+ import React, { useRef, useEffect, useMemo } from 'react';
2
+ import { View, Image, I18nManager, Pressable, TextInput, Text, StyleSheet } from 'react-native';
3
+ import { PanGestureHandler, GestureHandlerRootView } from 'react-native-gesture-handler';
4
+ import Animated, {
5
+ runOnJS,
6
+ useAnimatedGestureHandler,
7
+ useAnimatedStyle,
8
+ useSharedValue,
9
+ useAnimatedProps,
10
+ withTiming,
11
+ } from 'react-native-reanimated';
12
+ import { ALPHA_HEX, COLOR_HSVA, CONTRAST_RATIO, HSL_HEX, HSL_RGB, HSV_HSL } from './ColorsConversionFormulas';
13
+
14
+ const PANEL_IMAGE = require('./assets/Background.png'),
15
+ OPACITY_IMAGE = require('./assets/Opacity.png'),
16
+ HUE_IMAGE = require('./assets/Hue.png');
17
+
18
+ const isRtl = I18nManager.isRTL,
19
+ HUE_MAX = 360,
20
+ SB_MAX = 100,
21
+ OPACITY_MAX = 100,
22
+ CONTRAST_RATIO_MIN = 4.5,
23
+ SWATCHE_SIZE = 30,
24
+ TRACKS_HEIGHT = 25,
25
+ HANDLES_SCALE = 1.2,
26
+ WIDTH = 300;
27
+
28
+ const SWATCHES_COLORS = [
29
+ '#f44336',
30
+ '#E91E63',
31
+ '#9C27B0',
32
+ '#673AB7',
33
+ '#3F51B5',
34
+ '#2196F3',
35
+ '#03A9F4',
36
+ '#00BCD4',
37
+ '#009688',
38
+ '#4CAF50',
39
+ '#8BC34A',
40
+ '#CDDC39',
41
+ '#FFEB3B',
42
+ '#FFC107',
43
+ '#FF9800',
44
+ '#FF5722',
45
+ '#795548',
46
+ '#9E9E9E',
47
+ '#607D8B',
48
+ ];
49
+
50
+ Animated.addWhitelistedNativeProps({ text: true });
51
+ const AnimatedTextInput = Animated.createAnimatedComponent(TextInput);
52
+
53
+ const ReText = props => {
54
+ const { text, style, customStyle } = { ...props };
55
+
56
+ const animatedProps = useAnimatedProps(() => ({ text: text.value }));
57
+
58
+ return (
59
+ <AnimatedTextInput
60
+ underlineColorAndroid='transparent'
61
+ editable={false}
62
+ value={text.value}
63
+ style={[{ fontWeight: 'bold', padding: 0, height: '100%', width: '100%', textAlign: 'center' }, customStyle, style]}
64
+ {...{ animatedProps }}
65
+ />
66
+ );
67
+ };
68
+
69
+ export default function ColorPicker({
70
+ tracksHeight = TRACKS_HEIGHT,
71
+ thumbsSize = TRACKS_HEIGHT * 1.4,
72
+ value = '#418181',
73
+ onChange,
74
+ onComplete,
75
+ width = WIDTH,
76
+ style = {},
77
+ children = <Text>NO CHILDREN</Text>,
78
+ } = {}) {
79
+ const isFirstRender = useRef(true);
80
+ const initialColor = useRef(COLOR_HSVA(value));
81
+ const previewColorFormat = useRef('hex');
82
+
83
+ const panelThumbeSize = useRef(thumbsSize);
84
+ const hueThumbeSize = useRef(thumbsSize);
85
+ const opacityThumbeSize = useRef(thumbsSize);
86
+
87
+ const hue = useRef(initialColor.current.h);
88
+ const saturation = useRef(initialColor.current.s);
89
+ const brightness = useRef(initialColor.current.b);
90
+ const alpha = useRef(initialColor.current.a);
91
+
92
+ const color_hsl = color => {
93
+ color ??= { h: hue.current, s: saturation.current, b: brightness.current };
94
+ const { h, s, l } = HSV_HSL(color.h, color.s, color.b);
95
+ return `hsl(${h}, ${s}%, ${l}%)`;
96
+ };
97
+ const color_hsla = color => {
98
+ color ??= { h: hue.current, s: saturation.current, b: brightness.current, a: alpha.current };
99
+ const { h, s, l } = HSV_HSL(color.h, color.s, color.b);
100
+ return `hsla(${h}, ${s}%, ${l}%, ${color.a / 100})`;
101
+ };
102
+ const color_hex = color => {
103
+ color ??= { h: hue.current, s: saturation.current, b: brightness.current, a: alpha.current };
104
+ const { h, s, l } = HSV_HSL(color.h, color.s, color.b);
105
+ return HSL_HEX(h, s, l) + (color.a === 100 ? '' : ALPHA_HEX(color.a));
106
+ };
107
+ const color_rgb = color => {
108
+ color ??= { h: hue.current, s: saturation.current, b: brightness.current };
109
+ const { h, s, l } = HSV_HSL(color.h, color.s, color.b);
110
+ const { r, g, b } = HSL_RGB(h, s, l);
111
+ return `rgb(${r}, ${g}, ${b})`;
112
+ };
113
+ const color_rgba = color => {
114
+ color ??= { h: hue.current, s: saturation.current, b: brightness.current, a: alpha.current };
115
+ const { h, s, l } = HSV_HSL(color.h, color.s, color.b);
116
+ const { r, g, b } = HSL_RGB(h, s, l);
117
+ return `rgba(${r}, ${g}, ${b}, ${color.a / 100})`;
118
+ };
119
+ const color_hsv = color => {
120
+ color ??= { h: hue.current, s: saturation.current, b: brightness.current };
121
+ return `hsv(${color.h}, ${color.s}%, ${color.b}%)`;
122
+ };
123
+ const color_hsva = color => {
124
+ color ??= { h: hue.current, s: saturation.current, b: brightness.current, a: alpha.current };
125
+ return `hsva(${color.h}, ${color.s}%, ${color.b}%, ${color.a / 100})`;
126
+ };
127
+
128
+ const returnedResults = color => {
129
+ color ??= { h: hue.current, s: saturation.current, b: brightness.current, a: alpha.current };
130
+ return {
131
+ hex: color_hex(color),
132
+ rgb: color_rgb(color),
133
+ rgba: color_rgba(color),
134
+ hsl: color_hsl(color),
135
+ hsla: color_hsla(color),
136
+ hsv: color_hsv(color),
137
+ hsva: color_hsva(color),
138
+ };
139
+ };
140
+
141
+ const previewColor = useSharedValue(color_hex());
142
+ const previewColorStyle = useAnimatedStyle(() => ({ backgroundColor: previewColor.value }));
143
+ const previewColorWithoutOpacity = useAnimatedStyle(() => ({
144
+ backgroundColor: previewColor.value.length > 7 ? previewColor.value.substring(0, 7) : previewColor.value,
145
+ }));
146
+ const activeHue = useSharedValue(HSL_HEX(hue.current, 100, 50));
147
+ const activeHueStyle = useAnimatedStyle(() => ({ backgroundColor: activeHue.value }));
148
+
149
+ const hue_handlePos = useSharedValue(0); // for hue
150
+ const saturation_handlePos = useSharedValue(0); // for saturation
151
+ const brightness_handlePos = useSharedValue(0); // for brightness
152
+ const opacity_handlePos = useSharedValue(0); // for opacity
153
+ const previewTextColor = useSharedValue('#ffffff'); // for result text color
154
+ const previewText = useSharedValue(returnedResults()[previewColorFormat.current]); // for result text
155
+ const scale_panelHandle = useSharedValue(1); // for handles scale.
156
+ const scale_hueHandle = useSharedValue(1); // for handles scale.
157
+ const scale_opacityHandle = useSharedValue(1); // for handles scale.
158
+
159
+ const resultTextColorST = useAnimatedStyle(() => ({ color: previewTextColor.value }));
160
+
161
+ const panel_handleStyle = useAnimatedStyle(() => ({
162
+ backgroundColor: previewTextColor.value === '#ffffff' ? '#ffffff50' : '#00000050',
163
+ borderColor: previewTextColor.value,
164
+ transform: [
165
+ { translateX: saturation_handlePos.value },
166
+ { translateY: brightness_handlePos.value },
167
+ { scale: scale_panelHandle.value },
168
+ ],
169
+ }));
170
+
171
+ const onGestureEventFinish = () => {
172
+ onComplete?.(returnedResults());
173
+ };
174
+
175
+ const updateSB = (saturationChannel, brightnessChannel) => {
176
+ saturation.current = saturationChannel;
177
+ brightness.current = brightnessChannel;
178
+ previewColor.value = color_hex(); // to update result color.
179
+ previewText.value = returnedResults()[previewColorFormat.current]; // update result text
180
+ // change result text color based on lightness
181
+ const contrast = CONTRAST_RATIO(hue.current, saturation.current, brightness.current, previewTextColor.value);
182
+ previewTextColor.value =
183
+ contrast < CONTRAST_RATIO_MIN ? (previewTextColor.value === '#ffffff' ? '#000000' : '#ffffff') : previewTextColor.value;
184
+
185
+ onChange?.(returnedResults());
186
+ };
187
+
188
+ const updateHue = hueChannel => {
189
+ hue.current = hueChannel;
190
+ previewColor.value = color_hex(); // to update result color.
191
+ previewText.value = returnedResults()[previewColorFormat.current]; // update color text
192
+ // change result text color based on lightness
193
+ const contrast = CONTRAST_RATIO(hue.current, saturation.current, brightness.current, previewTextColor.value);
194
+ previewTextColor.value =
195
+ contrast < CONTRAST_RATIO_MIN ? (previewTextColor.value === '#ffffff' ? '#000000' : '#ffffff') : previewTextColor.value;
196
+
197
+ activeHue.value = HSL_HEX(hueChannel, 100, 50); // to update SV background color.
198
+ onChange?.(returnedResults());
199
+ };
200
+
201
+ const updateOpacity = alphaChannel => {
202
+ alpha.current = alphaChannel;
203
+ previewColor.value = color_hex(); // to update result color.
204
+ previewText.value = returnedResults()[previewColorFormat.current]; // update result text
205
+
206
+ onChange?.(returnedResults());
207
+ };
208
+
209
+ const setHandlesPos = () => {
210
+ const duration = 100;
211
+ const { h, s, b, a } = initialColor.current;
212
+
213
+ hue.current = h;
214
+ saturation.current = s;
215
+ brightness.current = b;
216
+ alpha.current = a;
217
+ // for colors
218
+ previewColor.value = color_hex(); // update result color.
219
+ previewText.value = returnedResults()[previewColorFormat.current]; // update result text
220
+ activeHue.value = HSL_HEX(h, 100, 50);
221
+ // change result text color based on lightness
222
+ const contrast = CONTRAST_RATIO(hue.current, saturation.current, brightness.current, previewTextColor.value);
223
+ previewTextColor.value =
224
+ contrast < CONTRAST_RATIO_MIN ? (previewTextColor.value === '#ffffff' ? '#000000' : '#ffffff') : previewTextColor.value;
225
+ // saturation
226
+ saturation_handlePos.value = withTiming(
227
+ isRtl ? (s / SB_MAX) * width - width + panelThumbeSize.current / 2 : (s / SB_MAX) * width - panelThumbeSize.current / 2,
228
+ duration
229
+ );
230
+ // brightness
231
+ brightness_handlePos.value = withTiming(width - (b / SB_MAX) * width - panelThumbeSize.current / 2, duration);
232
+ // hue
233
+ hue_handlePos.value = withTiming(
234
+ isRtl
235
+ ? width - (h / HUE_MAX) * width - width + hueThumbeSize.current / 2
236
+ : width - (h / HUE_MAX) * width - hueThumbeSize.current / 2,
237
+ 100
238
+ );
239
+ // opacity
240
+ opacity_handlePos.value = withTiming(
241
+ isRtl
242
+ ? (a / OPACITY_MAX) * width - width + opacityThumbeSize.current / 2
243
+ : (a / OPACITY_MAX) * width - opacityThumbeSize.current / 2,
244
+ duration
245
+ );
246
+ };
247
+
248
+ // when value change, update handles pos.
249
+ useEffect(() => {
250
+ if (isFirstRender.current) {
251
+ isFirstRender.current = false;
252
+ setHandlesPos();
253
+ return;
254
+ }
255
+ initialColor.current = COLOR_HSVA(value);
256
+ setHandlesPos();
257
+ }, [value, width]);
258
+
259
+ const RenderChildren = () =>
260
+ React.Children.map(children, child => {
261
+ switch (child.type.name) {
262
+ case 'Panel':
263
+ return React.cloneElement(child, {
264
+ width,
265
+ activeHueStyle,
266
+ panel_handleStyle,
267
+ previewColorWithoutOpacity,
268
+ scale_panelHandle,
269
+ saturation_handlePos,
270
+ brightness_handlePos,
271
+ updateSB,
272
+ onGestureEventFinish,
273
+ setHandlesPos,
274
+ panelThumbeSize,
275
+ thumbsSize,
276
+ });
277
+ case 'Preview':
278
+ return React.cloneElement(child, {
279
+ width,
280
+ initialColor,
281
+ returnedResults,
282
+ value,
283
+ previewColorStyle,
284
+ previewText,
285
+ resultTextColorST,
286
+ previewColorFormat,
287
+ });
288
+ case 'HueSlider':
289
+ return React.cloneElement(child, {
290
+ width,
291
+ hueThumbeSize,
292
+ setHandlesPos,
293
+ scale_hueHandle,
294
+ updateHue,
295
+ onGestureEventFinish,
296
+ hue_handlePos,
297
+ previewColorWithoutOpacity,
298
+ tracksHeight,
299
+ thumbsSize,
300
+ });
301
+ case 'OpacitySlider':
302
+ return React.cloneElement(child, {
303
+ width,
304
+ opacityThumbeSize,
305
+ setHandlesPos,
306
+ scale_opacityHandle,
307
+ activeHueStyle,
308
+ opacity_handlePos,
309
+ updateOpacity,
310
+ onGestureEventFinish,
311
+ previewColorWithoutOpacity,
312
+ tracksHeight,
313
+ thumbsSize,
314
+ });
315
+ case 'Swatches':
316
+ return React.cloneElement(child, {
317
+ width,
318
+ initialColor,
319
+ setHandlesPos,
320
+ onChange,
321
+ onComplete,
322
+ returnedResults,
323
+ });
324
+
325
+ default:
326
+ return child;
327
+ }
328
+ });
329
+
330
+ return (
331
+ <GestureHandlerRootView style={[styles.wrapper, style]}>
332
+ <RenderChildren />
333
+ </GestureHandlerRootView>
334
+ );
335
+ }
336
+
337
+ export function Panel({
338
+ activeHueStyle,
339
+ panel_handleStyle,
340
+ previewColorWithoutOpacity,
341
+ scale_panelHandle,
342
+ saturation_handlePos,
343
+ brightness_handlePos,
344
+ updateSB,
345
+ onGestureEventFinish,
346
+ setHandlesPos,
347
+ panelThumbeSize,
348
+ width,
349
+ thumbsSize,
350
+ borderRadius = 5, // by user
351
+ thumbSize = thumbsSize, // by user
352
+ }) {
353
+ panelThumbeSize.current = thumbSize;
354
+
355
+ useEffect(() => {
356
+ setHandlesPos();
357
+ }, []);
358
+
359
+ const panel_GestureEvent = useAnimatedGestureHandler({
360
+ onStart: (event, ctx) => {
361
+ ctx.x = event.x;
362
+ ctx.y = event.y;
363
+ scale_panelHandle.value = withTiming(HANDLES_SCALE, { duration: 100 });
364
+ },
365
+ onActive: (event, ctx) => {
366
+ const clamp = (v, max) => Math.min(Math.max(v, 0), max);
367
+
368
+ const x = event.translationX;
369
+ const y = event.translationY;
370
+ const posX = clamp(x + ctx.x, width);
371
+ const posY = clamp(y + ctx.y, width);
372
+ const percentX = posX / width;
373
+ const percentY = posY / width;
374
+
375
+ const saturationX = Math.round(percentX * SB_MAX);
376
+ const brightnessY = Math.round(SB_MAX - percentY * SB_MAX);
377
+
378
+ saturation_handlePos.value = isRtl ? percentX * width - width + thumbSize / 2 : percentX * width - thumbSize / 2;
379
+ brightness_handlePos.value = percentY * width - thumbSize / 2;
380
+
381
+ runOnJS(updateSB)(saturationX, brightnessY);
382
+ },
383
+ onFinish: () => {
384
+ scale_panelHandle.value = withTiming(1, { duration: 100 });
385
+ runOnJS(onGestureEventFinish)();
386
+ },
387
+ });
388
+
389
+ return (
390
+ <PanGestureHandler onGestureEvent={panel_GestureEvent} minDist={0}>
391
+ <Animated.View style={[styles.panel_container, { width, height: width, borderRadius }, activeHueStyle]}>
392
+ <Image source={PANEL_IMAGE} style={[styles.panel_image, { borderRadius }]} />
393
+ <Animated.View
394
+ style={[styles.handle, { width: thumbSize, height: thumbSize, borderRadius: thumbSize / 2 }, panel_handleStyle]}
395
+ >
396
+ <Animated.View style={[styles.handleInner, { borderRadius: thumbSize / 2 }, previewColorWithoutOpacity]} />
397
+ </Animated.View>
398
+ </Animated.View>
399
+ </PanGestureHandler>
400
+ );
401
+ }
402
+
403
+ export function Preview({
404
+ width,
405
+ initialColor,
406
+ returnedResults,
407
+ value,
408
+ previewColorStyle,
409
+ previewText,
410
+ resultTextColorST,
411
+ previewColorFormat,
412
+ style = {}, // by user
413
+ textStyle = {}, // by user
414
+ colorFormat = 'hex', // by user
415
+ hideInitialColor = false, // by user
416
+ }) {
417
+ previewColorFormat.current = colorFormat;
418
+
419
+ const initialColorText = useMemo(() => {
420
+ const { h, s, b } = initialColor.current;
421
+ const hsl = HSV_HSL(h, s, b);
422
+ const formated = returnedResults(initialColor.current)[previewColorFormat.current];
423
+ const color = hsl.l < 50 ? '#fff' : '#000';
424
+ return { formated, color };
425
+ }, [value, colorFormat]);
426
+
427
+ return (
428
+ <View style={[styles.preview, { width }, style]}>
429
+ {!hideInitialColor && (
430
+ <View style={[styles.previewChildren, { backgroundColor: value }]}>
431
+ <Text style={[{ color: initialColorText.color }, { fontWeight: 'bold' }, textStyle]}>{initialColorText.formated}</Text>
432
+ </View>
433
+ )}
434
+ <Animated.View style={[styles.previewChildren, previewColorStyle]}>
435
+ <ReText text={previewText} style={resultTextColorST} customStyle={textStyle} />
436
+ </Animated.View>
437
+ </View>
438
+ );
439
+ }
440
+
441
+ export function HueSlider({
442
+ width,
443
+ hueThumbeSize,
444
+ setHandlesPos,
445
+ scale_hueHandle,
446
+ updateHue,
447
+ onGestureEventFinish,
448
+ hue_handlePos,
449
+ previewColorWithoutOpacity,
450
+ tracksHeight,
451
+ thumbsSize,
452
+ thumbSize = thumbsSize, // by user
453
+ trackHeight = tracksHeight, // by user
454
+ borderRadius = 5, // by user
455
+ }) {
456
+ trackHeight = trackHeight <= 80 ? trackHeight : 80;
457
+ hueThumbeSize.current = thumbSize;
458
+
459
+ useEffect(() => {
460
+ setHandlesPos();
461
+ }, []);
462
+
463
+ const hue_handleStyle = useAnimatedStyle(() => ({
464
+ backgroundColor: '#ffffff50',
465
+ borderColor: '#ffffff',
466
+ transform: [
467
+ { translateX: hue_handlePos.value },
468
+ { translateY: -(thumbSize - trackHeight) / 2 },
469
+ { scale: scale_hueHandle.value },
470
+ ],
471
+ }));
472
+
473
+ const HueGestureEvent = useAnimatedGestureHandler(
474
+ {
475
+ onStart: (event, ctx) => {
476
+ ctx.x = event.x;
477
+ scale_hueHandle.value = withTiming(HANDLES_SCALE, { duration: 100 });
478
+ },
479
+ onActive: (event, ctx) => {
480
+ const clamp = (v, max) => Math.min(Math.max(v, 0), max);
481
+
482
+ const x = event.translationX;
483
+ const pos = clamp(x + ctx.x, width);
484
+ const percent = pos / width;
485
+
486
+ const hueX = HUE_MAX - Math.round(percent * HUE_MAX);
487
+
488
+ hue_handlePos.value = isRtl ? percent * width - width + thumbSize / 2 : percent * width - thumbSize / 2;
489
+
490
+ runOnJS(updateHue)(hueX);
491
+ },
492
+ onFinish: () => {
493
+ scale_hueHandle.value = withTiming(1, { duration: 100 });
494
+ runOnJS(onGestureEventFinish)();
495
+ },
496
+ },
497
+ [width]
498
+ );
499
+
500
+ return (
501
+ <PanGestureHandler onGestureEvent={HueGestureEvent} minDist={0}>
502
+ <Animated.View style={{ position: 'relative', width, height: trackHeight }}>
503
+ <View style={[styles.hue_opacityImageContainer, { borderRadius }]}>
504
+ <Image source={HUE_IMAGE} style={styles.hue_opacityImage} />
505
+ </View>
506
+ <Animated.View
507
+ style={[styles.handle, { width: thumbSize, height: thumbSize, borderRadius: thumbSize / 2 }, hue_handleStyle]}
508
+ >
509
+ <Animated.View style={[styles.handleInner, { borderRadius: thumbSize / 2 }, previewColorWithoutOpacity]} />
510
+ </Animated.View>
511
+ </Animated.View>
512
+ </PanGestureHandler>
513
+ );
514
+ }
515
+
516
+ export function OpacitySlider({
517
+ width,
518
+ opacityThumbeSize,
519
+ setHandlesPos,
520
+ scale_opacityHandle,
521
+ activeHueStyle,
522
+ opacity_handlePos,
523
+ updateOpacity,
524
+ onGestureEventFinish,
525
+ previewColorWithoutOpacity,
526
+ tracksHeight,
527
+ thumbsSize,
528
+ thumbSize = thumbsSize, // by user
529
+ trackHeight = tracksHeight, // by user
530
+ borderRadius = 5, // by user
531
+ }) {
532
+ trackHeight = trackHeight <= 80 ? trackHeight : 80;
533
+ opacityThumbeSize.current = thumbSize;
534
+
535
+ useEffect(() => {
536
+ setHandlesPos();
537
+ }, []);
538
+
539
+ const opacity_handleStyle = useAnimatedStyle(() => ({
540
+ backgroundColor: '#ffffff50',
541
+ borderColor: '#ffffff',
542
+ transform: [
543
+ { translateX: opacity_handlePos.value },
544
+ { translateY: -(thumbSize - trackHeight) / 2 },
545
+ { scale: scale_opacityHandle.value },
546
+ ],
547
+ }));
548
+
549
+ const opacityGestureEvent = useAnimatedGestureHandler({
550
+ onStart: (event, ctx) => {
551
+ ctx.x = event.x;
552
+ scale_opacityHandle.value = withTiming(HANDLES_SCALE, { duration: 100 });
553
+ },
554
+ onActive: (event, ctx) => {
555
+ const clamp = (v, max) => Math.min(Math.max(v, 0), max);
556
+
557
+ const x = event.translationX;
558
+ const pos = clamp(x + ctx.x, width);
559
+ const percent = pos / width;
560
+
561
+ const opacityX = Math.round(percent * OPACITY_MAX);
562
+
563
+ opacity_handlePos.value = isRtl ? percent * width - width + thumbSize / 2 : percent * width - thumbSize / 2;
564
+
565
+ runOnJS(updateOpacity)(opacityX);
566
+ },
567
+ onFinish: () => {
568
+ scale_opacityHandle.value = withTiming(1, { duration: 100 });
569
+ runOnJS(onGestureEventFinish)();
570
+ },
571
+ });
572
+
573
+ return (
574
+ <PanGestureHandler onGestureEvent={opacityGestureEvent} minDist={0}>
575
+ <Animated.View style={{ position: 'relative', width, height: trackHeight }}>
576
+ <Animated.View style={[styles.hue_opacityImageContainer, { borderRadius }, activeHueStyle]}>
577
+ <Image source={OPACITY_IMAGE} style={styles.hue_opacityImage} />
578
+ </Animated.View>
579
+ <Animated.View
580
+ style={[styles.handle, { width: thumbSize, height: thumbSize, borderRadius: thumbSize / 2 }, opacity_handleStyle]}
581
+ >
582
+ <Animated.View style={[styles.handleInner, { borderRadius: thumbSize / 2 }, previewColorWithoutOpacity]} />
583
+ </Animated.View>
584
+ </Animated.View>
585
+ </PanGestureHandler>
586
+ );
587
+ }
588
+
589
+ export function Swatches({
590
+ width,
591
+ initialColor,
592
+ setHandlesPos,
593
+ onChange,
594
+ onComplete,
595
+ returnedResults,
596
+ colors, // by user
597
+ style = {}, // by user
598
+ swatcheStyle = {}, // by user
599
+ }) {
600
+ colors ??= SWATCHES_COLORS;
601
+ const onPress = swatch => {
602
+ initialColor.current = COLOR_HSVA(swatch);
603
+ setHandlesPos();
604
+ onChange?.(returnedResults());
605
+ onComplete?.(returnedResults());
606
+ };
607
+ return (
608
+ <View style={[styles.swatcheContainer, { width }, style]}>
609
+ {colors.map((swatch, i) => (
610
+ <Pressable
611
+ key={swatch + i}
612
+ onPress={() => onPress(swatch)}
613
+ style={[styles.swatch, swatcheStyle, { backgroundColor: swatch }]}
614
+ />
615
+ ))}
616
+ </View>
617
+ );
618
+ }
619
+
620
+ const styles = StyleSheet.create({
621
+ wrapper: {
622
+ flexDirection: 'column',
623
+ justifyContent: 'space-evenly',
624
+ alignItems: 'center',
625
+ alignSelf: 'center',
626
+ flex: 1,
627
+ },
628
+ panel_container: {
629
+ position: 'relative',
630
+ alignItems: 'center',
631
+ borderRadius: 5,
632
+ backgroundColor: 'red',
633
+
634
+ shadowColor: '#000',
635
+ shadowOffset: {
636
+ width: 0,
637
+ height: 2,
638
+ },
639
+ shadowOpacity: 0.25,
640
+ shadowRadius: 3.84,
641
+
642
+ elevation: 5,
643
+ },
644
+ panel_image: {
645
+ width: '100%',
646
+ height: '100%',
647
+ },
648
+ handle: {
649
+ position: 'absolute',
650
+ left: 0,
651
+ top: 0,
652
+ borderWidth: 1,
653
+ justifyContent: 'center',
654
+ alignItems: 'center',
655
+ },
656
+ handleInner: {
657
+ width: '75%',
658
+ height: '75%',
659
+
660
+ shadowColor: '#000',
661
+ shadowOffset: {
662
+ width: 0,
663
+ height: 2,
664
+ },
665
+ shadowOpacity: 0.25,
666
+ shadowRadius: 3.84,
667
+
668
+ elevation: 5,
669
+ },
670
+ hue_opacityImageContainer: {
671
+ width: '100%',
672
+ height: '100%',
673
+ borderRadius: 5,
674
+ overflow: 'hidden',
675
+
676
+ shadowColor: '#000',
677
+ shadowOffset: {
678
+ width: 0,
679
+ height: 2,
680
+ },
681
+ shadowOpacity: 0.25,
682
+ shadowRadius: 3.84,
683
+
684
+ elevation: 5,
685
+ },
686
+ hue_opacityImage: {
687
+ width: '100%',
688
+ height: 80,
689
+ },
690
+ preview: {
691
+ flexDirection: 'row',
692
+ height: TRACKS_HEIGHT,
693
+ borderRadius: 5,
694
+ overflow: 'hidden',
695
+ },
696
+ previewChildren: {
697
+ flex: 1,
698
+ height: '100%',
699
+ justifyContent: 'center',
700
+ alignItems: 'center',
701
+ },
702
+ swatcheContainer: {
703
+ flexDirection: 'row',
704
+ flexWrap: 'wrap',
705
+ justifyContent: 'space-between',
706
+ },
707
+ swatch: {
708
+ width: SWATCHE_SIZE,
709
+ height: SWATCHE_SIZE,
710
+ borderRadius: SWATCHE_SIZE / 2,
711
+ marginHorizontal: 5,
712
+ marginBottom: 15,
713
+
714
+ shadowColor: '#000',
715
+ shadowOffset: {
716
+ width: 0,
717
+ height: 2,
718
+ },
719
+ shadowOpacity: 0.25,
720
+ shadowRadius: 3.84,
721
+
722
+ elevation: 5,
723
+ },
724
+ });
@@ -0,0 +1,220 @@
1
+ import NamedColors from './NamedColors';
2
+
3
+ export const HSL_RGB = (h, s, l) => {
4
+ s /= 100;
5
+ l /= 100;
6
+
7
+ if (h === undefined) return { r: 0, g: 0, b: 0 };
8
+
9
+ const chroma = (1 - Math.abs(2 * l - 1)) * s;
10
+ let huePrime = h / 60;
11
+ const secondComponent = chroma * (1 - Math.abs((huePrime % 2) - 1));
12
+ huePrime = Math.floor(huePrime);
13
+
14
+ let red = [0, 5].includes(huePrime) ? chroma : [1, 4].includes(huePrime) ? secondComponent : 0,
15
+ green = [1, 2].includes(huePrime) ? chroma : [0, 3].includes(huePrime) ? secondComponent : 0,
16
+ blue = [3, 4].includes(huePrime) ? chroma : [2, 5].includes(huePrime) ? secondComponent : 0;
17
+
18
+ const lightnessAdjustment = l - chroma / 2;
19
+
20
+ red += lightnessAdjustment;
21
+ green += lightnessAdjustment;
22
+ blue += lightnessAdjustment;
23
+
24
+ return { r: Math.abs(Math.round(red * 255)), g: Math.abs(Math.round(green * 255)), b: Math.abs(Math.round(blue * 255)) };
25
+ };
26
+
27
+ export const ALPHA_HEX = number => {
28
+ const op = Math.floor((number / 100) * 255);
29
+ const hex = op.toString(16);
30
+ return op < 16 ? '0' + hex : hex;
31
+ };
32
+
33
+ export const HSL_HEX = (h, s, l) => {
34
+ l /= 100;
35
+ const a = (s * Math.min(l, 1 - l)) / 100;
36
+ const f = n => {
37
+ const k = (n + h / 30) % 12;
38
+ const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
39
+ return Math.round(255 * color)
40
+ .toString(16)
41
+ .padStart(2, '0'); // convert to Hex and prefix "0" if needed
42
+ };
43
+ return `#${f(0)}${f(8)}${f(4)}`;
44
+ };
45
+
46
+ export const HSV_HSL = (h, s, b) => {
47
+ s /= 100;
48
+ b /= 100;
49
+ let l = ((2 - s) * b) / 2;
50
+ if (l !== 0) s = Math.round((l === 1 ? 0 : l < 0.5 ? (s * b) / (l * 2) : (s * b) / (2 - l * 2)) * 100);
51
+ l = Math.round(l * 100);
52
+ return { h, s, l };
53
+ };
54
+
55
+ export const RGB_HSV = (r, g, b) => {
56
+ let rabs, gabs, babs, rr, gg, bb, h, s, v, diff, diffc, percentRoundFn;
57
+ rabs = r / 255;
58
+ gabs = g / 255;
59
+ babs = b / 255;
60
+ // eslint-disable-next-line no-sequences
61
+ (v = Math.max(rabs, gabs, babs)), (diff = v - Math.min(rabs, gabs, babs));
62
+ diffc = c => (v - c) / 6 / diff + 1 / 2;
63
+ percentRoundFn = num => Math.round(num * 100) / 100;
64
+ if (diff === 0) {
65
+ h = s = 0;
66
+ } else {
67
+ s = diff / v;
68
+ rr = diffc(rabs);
69
+ gg = diffc(gabs);
70
+ bb = diffc(babs);
71
+
72
+ if (rabs === v) {
73
+ h = bb - gg;
74
+ } else if (gabs === v) {
75
+ h = 1 / 3 + rr - bb;
76
+ } else if (babs === v) {
77
+ h = 2 / 3 + gg - rr;
78
+ }
79
+ if (h < 0) {
80
+ h += 1;
81
+ } else if (h > 1) {
82
+ h -= 1;
83
+ }
84
+ }
85
+ return {
86
+ h: Math.round(h * 360),
87
+ s: percentRoundFn(s * 100),
88
+ b: percentRoundFn(v * 100),
89
+ };
90
+ };
91
+
92
+ export const HEX_RGB = hex => {
93
+ const isValidHex = h => /^#([A-Fa-f0-9]{3,4}){1,2}$/.test(h);
94
+
95
+ const getChunksFromString = (st, chunkSize) => st.match(new RegExp(`.{${chunkSize}}`, 'g'));
96
+
97
+ const convertHexUnitTo256 = hexStr => parseInt(hexStr.repeat(2 / hexStr.length), 16);
98
+
99
+ if (!isValidHex(hex)) throw new Error('Invalid HEX');
100
+
101
+ const chunkSize = Math.floor((hex.length - 1) / 3);
102
+ const hexArr = getChunksFromString(hex.slice(1), chunkSize);
103
+ const [r, g, b, a] = hexArr.map(convertHexUnitTo256);
104
+ const alpha = Math.round((a / 255) * 100);
105
+ return { r, g, b, a: alpha ? alpha : 100 };
106
+ };
107
+
108
+ export const HEX_HSV = hex => {
109
+ const { r, g, b, a } = HEX_RGB(hex);
110
+ return { ...RGB_HSV(r, g, b), a };
111
+ };
112
+
113
+ export const HSL_HSV = (h, s, l) => {
114
+ const { r, g, b } = HSL_RGB(h, s, l);
115
+ return RGB_HSV(r, g, b);
116
+ };
117
+
118
+ export const COLOR_HSVA = colorStr => {
119
+ colorStr = colorStr.trim();
120
+ const isRgb = colorStr.startsWith('rgb');
121
+ const isRgba = colorStr.startsWith('rgba');
122
+ const isHex = colorStr.startsWith('#');
123
+ const isNamedColor = NamedColors.hasOwnProperty(colorStr);
124
+ const isHsl = colorStr.startsWith('hsl');
125
+ const isHsla = colorStr.startsWith('hsla');
126
+ const isHsv = colorStr.startsWith('hsv');
127
+ const isHsva = colorStr.startsWith('hsva');
128
+
129
+ if (isRgb) {
130
+ const match = colorStr.match(/(?<=\()[^)]+/)?.[0];
131
+ if (!match) throw new Error('Invalid RGB value');
132
+ const colorValues = match.split(',');
133
+ if (colorValues.length !== 3) throw new Error('Invalid RGB value');
134
+ const [r, g, b] = colorValues.map(v => +v);
135
+ if (isNaN(r) || isNaN(g) || isNaN(b)) throw new Error('Invalid RGB value');
136
+ return { ...RGB_HSV(r, g, b), a: 100 };
137
+ }
138
+
139
+ if (isRgba) {
140
+ const match = colorStr.match(/(?<=\()[^)]+/)?.[0];
141
+ if (!match) throw new Error('Invalid RGBA value');
142
+ const colorValues = match.split(',');
143
+ if (colorValues.length !== 4) throw new Error('Invalid RGBA value');
144
+ const [r, g, b, a] = colorValues.map(v => +v);
145
+ if (isNaN(r) || isNaN(g) || isNaN(b) || isNaN(a)) throw new Error('Invalid RGBA value');
146
+ return { ...RGB_HSV(r, g, b), a: Math.round(a * 100) };
147
+ }
148
+
149
+ if (isHex) return HEX_HSV(colorStr);
150
+
151
+ if (isNamedColor) return HEX_HSV(NamedColors[colorStr]);
152
+
153
+ if (isHsl) {
154
+ const match = colorStr.match(/(?<=\()[^)]+/)?.[0];
155
+ if (!match) throw new Error('Invalid HSL value');
156
+ const colorValues = match.split(',');
157
+ if (colorValues.length !== 3) throw new Error('Invalid HSL value');
158
+ const [h, s, l] = colorValues.map(v => +v);
159
+ if (isNaN(h) || isNaN(s) || isNaN(l)) throw new Error('Invalid HSL value');
160
+ return { ...HSL_HSV(h, s, l), a: 100 };
161
+ }
162
+
163
+ if (isHsla) {
164
+ const match = colorStr.match(/(?<=\()[^)]+/)?.[0];
165
+ if (!match) throw new Error('Invalid HSLA value');
166
+ const colorValues = match.split(',');
167
+ if (colorValues.length !== 4) throw new Error('Invalid HSLA value');
168
+ const [h, s, l, a] = colorValues.map(v => +v);
169
+ if (isNaN(h) || isNaN(s) || isNaN(l) || isNaN(a)) throw new Error('Invalid HSLA value');
170
+ return { ...HSL_HSV(h, s, l), a: Math.round(a * 100) };
171
+ }
172
+
173
+ if (isHsv) {
174
+ const match = colorStr.match(/(?<=\()[^)]+/)?.[0];
175
+ if (!match) throw new Error('Invalid HSV value');
176
+ const colorValues = match.split(',');
177
+ if (colorValues.length !== 3) throw new Error('Invalid HSV value');
178
+ const [h, s, b] = colorValues.map(n => +n);
179
+ if (isNaN(h) || isNaN(s) || isNaN(b)) throw new Error('Invalid HSV value');
180
+ return { h, s, b, a: 100 };
181
+ }
182
+
183
+ if (isHsva) {
184
+ const match = colorStr.match(/(?<=\()[^)]+/)?.[0];
185
+ if (!match) throw new Error('Invalid HSVA value');
186
+ const colorValues = match.split(',');
187
+ if (colorValues.length !== 4) throw new Error('Invalid HSVA value');
188
+ const [h, s, b, a] = colorValues.map(n => +n);
189
+ if (isNaN(h) || isNaN(s) || isNaN(b) || isNaN(a)) throw new Error('Invalid HSVA value');
190
+ return { h, s, b, a: Math.round(a * 100) };
191
+ }
192
+
193
+ throw new Error('Invalid color');
194
+ };
195
+
196
+ const luminanceRGB = (r, g, b) => {
197
+ const a = [r, g, b].map(v => {
198
+ v /= 255;
199
+ return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
200
+ });
201
+ return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722;
202
+ };
203
+ const luminanceHEX = hex => {
204
+ const { r, g, b } = HEX_RGB(hex);
205
+ const a = [r, g, b].map(v => {
206
+ v /= 255;
207
+ return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
208
+ });
209
+ return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722;
210
+ };
211
+
212
+ export const CONTRAST_RATIO = (h, s, v, hex) => {
213
+ const hsl = HSV_HSL(h, s, v),
214
+ { r, g, b } = HSL_RGB(hsl.h, hsl.s, hsl.l),
215
+ lum1 = luminanceRGB(r, g, b),
216
+ lum2 = luminanceHEX(hex),
217
+ brightest = Math.max(lum1, lum2),
218
+ darkest = Math.min(lum1, lum2);
219
+ return +((brightest + 0.05) / (darkest + 0.05)).toFixed(1);
220
+ };
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2020 Doho
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/NamedColors.js ADDED
@@ -0,0 +1,147 @@
1
+ export default {
2
+ aliceblue: '#f0f8ff',
3
+ antiquewhite: '#faebd7',
4
+ aqua: '#00ffff',
5
+ aquamarine: '#7fffd4',
6
+ azure: '#f0ffff',
7
+ beige: '#f5f5dc',
8
+ bisque: '#ffe4c4',
9
+ black: '#000000',
10
+ blanchedalmond: '#ffebcd',
11
+ blue: '#0000ff',
12
+ blueviolet: '#8a2be2',
13
+ brown: '#a52a2a',
14
+ burlywood: '#deb887',
15
+ cadetblue: '#5f9ea0',
16
+ chartreuse: '#7fff00',
17
+ chocolate: '#d2691e',
18
+ coral: '#ff7f50',
19
+ cornflowerblue: '#6495ed',
20
+ cornsilk: '#fff8dc',
21
+ crimson: '#dc143c',
22
+ cyan: '#00ffff',
23
+ darkblue: '#00008b',
24
+ darkcyan: '#008b8b',
25
+ darkgoldenrod: '#b8860b',
26
+ darkgray: '#a9a9a9',
27
+ darkgreen: '#006400',
28
+ darkgrey: '#a9a9a9',
29
+ darkkhaki: '#bdb76b',
30
+ darkmagenta: '#8b008b',
31
+ darkolivegreen: '#556b2f',
32
+ darkorange: '#ff8c00',
33
+ darkorchid: '#9932cc',
34
+ darkred: '#8b0000',
35
+ darksalmon: '#e9967a',
36
+ darkseagreen: '#8fbc8f',
37
+ darkslateblue: '#483d8b',
38
+ darkslategrey: '#2f4f4f',
39
+ darkturquoise: '#00ced1',
40
+ darkviolet: '#9400d3',
41
+ deeppink: '#ff1493',
42
+ deepskyblue: '#00bfff',
43
+ dimgray: '#696969',
44
+ dimgrey: '#696969',
45
+ dodgerblue: '#1e90ff',
46
+ firebrick: '#b22222',
47
+ floralwhite: '#fffaf0',
48
+ forestgreen: '#228b22',
49
+ fuchsia: '#ff00ff',
50
+ gainsboro: '#dcdcdc',
51
+ ghostwhite: '#f8f8ff',
52
+ gold: '#ffd700',
53
+ goldenrod: '#daa520',
54
+ gray: '#808080',
55
+ green: '#008000',
56
+ greenyellow: '#adff2f',
57
+ grey: '#808080',
58
+ honeydew: '#f0fff0',
59
+ hotpink: '#ff69b4',
60
+ indianred: '#cd5c5c',
61
+ indigo: '#4b0082',
62
+ ivory: '#fffff0',
63
+ khaki: '#f0e68c',
64
+ lavender: '#e6e6fa',
65
+ lavenderblush: '#fff0f5',
66
+ lawngreen: '#7cfc00',
67
+ lemonchiffon: '#fffacd',
68
+ lightblue: '#add8e6',
69
+ lightcoral: '#f08080',
70
+ lightcyan: '#e0ffff',
71
+ lightgoldenrodyellow: '#fafad2',
72
+ lightgray: '#d3d3d3',
73
+ lightgreen: '#90ee90',
74
+ lightgrey: '#d3d3d3',
75
+ lightpink: '#ffb6c1',
76
+ lightsalmon: '#ffa07a',
77
+ lightseagreen: '#20b2aa',
78
+ lightskyblue: '#87cefa',
79
+ lightslategrey: '#778899',
80
+ lightsteelblue: '#b0c4de',
81
+ lightyellow: '#ffffe0',
82
+ lime: '#00ff00',
83
+ limegreen: '#32cd32',
84
+ linen: '#faf0e6',
85
+ magenta: '#ff00ff',
86
+ maroon: '#800000',
87
+ mediumaquamarine: '#66cdaa',
88
+ mediumblue: '#0000cd',
89
+ mediumorchid: '#ba55d3',
90
+ mediumpurple: '#9370db',
91
+ mediumseagreen: '#3cb371',
92
+ mediumslateblue: '#7b68ee',
93
+ mediumspringgreen: '#00fa9a',
94
+ mediumturquoise: '#48d1cc',
95
+ mediumvioletred: '#c71585',
96
+ midnightblue: '#191970',
97
+ mintcream: '#f5fffa',
98
+ mistyrose: '#ffe4e1',
99
+ moccasin: '#ffe4b5',
100
+ navajowhite: '#ffdead',
101
+ navy: '#000080',
102
+ oldlace: '#fdf5e6',
103
+ olive: '#808000',
104
+ olivedrab: '#6b8e23',
105
+ orange: '#ffa500',
106
+ orangered: '#ff4500',
107
+ orchid: '#da70d6',
108
+ palegoldenrod: '#eee8aa',
109
+ palegreen: '#98fb98',
110
+ paleturquoise: '#afeeee',
111
+ palevioletred: '#db7093',
112
+ papayawhip: '#ffefd5',
113
+ peachpuff: '#ffdab9',
114
+ peru: '#cd853f',
115
+ pink: '#ffc0cb',
116
+ plum: '#dda0dd',
117
+ powderblue: '#b0e0e6',
118
+ purple: '#800080',
119
+ rebeccapurple: '#663399',
120
+ red: '#ff0000',
121
+ rosybrown: '#bc8f8f',
122
+ royalblue: '#4169e1',
123
+ saddlebrown: '#8b4513',
124
+ salmon: '#fa8072',
125
+ sandybrown: '#f4a460',
126
+ seagreen: '#2e8b57',
127
+ seashell: '#fff5ee',
128
+ sienna: '#a0522d',
129
+ silver: '#c0c0c0',
130
+ skyblue: '#87ceeb',
131
+ slateblue: '#6a5acd',
132
+ slategray: '#708090',
133
+ snow: '#fffafa',
134
+ springgreen: '#00ff7f',
135
+ steelblue: '#4682b4',
136
+ tan: '#d2b48c',
137
+ teal: '#008080',
138
+ thistle: '#d8bfd8',
139
+ tomato: '#ff6347',
140
+ turquoise: '#40e0d0',
141
+ violet: '#ee82ee',
142
+ wheat: '#f5deb3',
143
+ white: '#ffffff',
144
+ whitesmoke: '#f5f5f5',
145
+ yellow: '#ffff00',
146
+ yellowgreen: '#9acd32',
147
+ };
Binary file
package/assets/Hue.png ADDED
Binary file
Binary file
package/index.d.ts ADDED
@@ -0,0 +1,121 @@
1
+ import { StyleProp, TextStyle, ViewStyle } from 'react-native';
2
+
3
+ interface returnedResults {
4
+ hex: string;
5
+ rgb: string;
6
+ rgba: string;
7
+ hsl: string;
8
+ hsla: string;
9
+ hsv: string;
10
+ hsva: string;
11
+ }
12
+
13
+ interface ColorPickerProps {
14
+ /** - hue and opacity sliders track height. */
15
+ tracksHeight?: number;
16
+
17
+ /** - sliders handles (thumbs) size (height*width). */
18
+ thumbsSize?: number;
19
+
20
+ /** - color picker component width. */
21
+ width?: number;
22
+
23
+ /**
24
+ * - color picker wrapper style.
25
+ * - if you want to change the width use the width prop.
26
+ */
27
+ style?: StyleProp<ViewStyle>;
28
+
29
+ /**
30
+ * - initial color.
31
+ * - Accepts `hex`, `rgb`, `rgba`, `hsl`, `hsla`, and `named color` formats.
32
+ */
33
+ value?: string;
34
+
35
+ /** - called when the user moves the sliders. */
36
+ onChange?: (colors: returnedResults) => void;
37
+
38
+ /** - called when the user lifts his finger off the sliders. */
39
+ onComplete?: (colors: returnedResults) => void;
40
+
41
+ children?: React.ReactNode;
42
+ }
43
+
44
+ interface SwatchesPorps {
45
+ /**
46
+ * - swatch style.
47
+ * - **Note** `backgroundColor` is immutable.
48
+ */
49
+ swatcheStyle?: StyleProp<ViewStyle>;
50
+
51
+ /** - swatches container style. */
52
+ style?: StyleProp<ViewStyle>;
53
+
54
+ /** - provide your own swatches colors. */
55
+ colors?: string[];
56
+ }
57
+
58
+ interface PreviewPorps {
59
+ /** - show color preview in specific format. */
60
+ colorFormat?: 'hex' | 'rgb' | 'rgba' | 'hsl' | 'hsla' | 'hsv' | 'hsva';
61
+
62
+ /** - hide initial color preview and show the picked color preview only. */
63
+ hideInitialColor?: boolean;
64
+
65
+ /**
66
+ * - preview container style.
67
+ * - **Note** `backgroundColor` is immutable.
68
+ */
69
+ style?: StyleProp<ViewStyle>;
70
+
71
+ /**
72
+ * - preview text style.
73
+ * - **Note** `color` is immutable.
74
+ */
75
+ textStyle?: StyleProp<TextStyle>;
76
+ }
77
+
78
+ interface PanelProps {
79
+ /** - panel border raduis. */
80
+ borderRadius?: number;
81
+
82
+ /** - panel handle (thumb) size (height*width). */
83
+ thumbSize?: number;
84
+ }
85
+
86
+ interface HueProps {
87
+ /** - hue slider handle (thumb) size (height*width). */
88
+ thumbSize?: number;
89
+
90
+ /**
91
+ * - opacity slider track height.
92
+ * - **Note** max height is `80`
93
+ */
94
+ trackHeight?: number;
95
+
96
+ /** - hue slider border raduis. */
97
+ borderRadius?: number;
98
+ }
99
+
100
+ interface OpacityProps {
101
+ /** - opacity slider handle (thumb) size (height*width). */
102
+ thumbSize?: number;
103
+
104
+ /**
105
+ * - opacity slider track height.
106
+ * - **Note** max height is `80`
107
+ */
108
+ trackHeight?: number;
109
+
110
+ /** - opacity slider border raduis. */
111
+ borderRadius?: number;
112
+ }
113
+
114
+ declare const ColorPicker: React.FunctionComponent<ColorPickerProps>;
115
+ export declare const Preview: React.FunctionComponent<PreviewPorps>;
116
+ export declare const Panel: React.FunctionComponent<PanelProps>;
117
+ export declare const HueSlider: React.FunctionComponent<HueProps>;
118
+ export declare const OpacitySlider: React.FunctionComponent<OpacityProps>;
119
+ export declare const Swatches: React.FunctionComponent<SwatchesPorps>;
120
+
121
+ export default ColorPicker;
package/index.js ADDED
@@ -0,0 +1,4 @@
1
+ import ColorPicker from './ColorPicker.js';
2
+
3
+ export default ColorPicker;
4
+ export { Panel, Swatches, Preview, OpacitySlider, HueSlider } from './ColorPicker.js';
package/package.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "reanimated-color-picker",
3
+ "version": "0.0.1",
4
+ "description": "",
5
+ "main": "index.js",
6
+ "source": "index.js",
7
+ "types": "index.d.ts",
8
+ "scripts": {
9
+ "publish": "npm publish"
10
+ },
11
+ "keywords": [
12
+ "react-native",
13
+ "color",
14
+ "picker",
15
+ "palette"
16
+ ],
17
+ "repository": "https://github.com/alabsi91/rn-color-picker",
18
+ "author": "Ahmed Alabsi <alabsi91@gmail.com> (https://github.com/alabsi91)",
19
+ "license": "MIT",
20
+ "bugs": {
21
+ "url": "https://github.com/alabsi91/rn-color-picker/issues"
22
+ },
23
+ "homepage": "https://github.com/alabsi91/rn-color-picker",
24
+ "peerDependencies": {
25
+ "react-native-gesture-handler": ">=2.0.0",
26
+ "react-native-reanimated": ">=2.0.0"
27
+ }
28
+ }