reanimated-color-picker 0.0.21 → 0.0.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/package.json +7 -7
  2. package/readme.md +8 -5
  3. package/src/ColorPicker.js +439 -0
  4. package/{lib/ColorPicker.js → src/ColorPicker.web.js} +0 -0
  5. package/src/ColorsConversionFormulas.js +212 -0
  6. package/{lib/ColorsConversionFormulas.js → src/ColorsConversionFormulas.web.js} +0 -0
  7. package/src/GlobalStyles.js +51 -0
  8. package/{lib/GlobalStyles.js → src/GlobalStyles.web.js} +1 -1
  9. package/src/NamedColors.js +147 -0
  10. package/{lib/NamedColors.js → src/NamedColors.web.js} +0 -0
  11. package/{lib → src}/assets/Background1.png +0 -0
  12. package/{lib → src}/assets/Background2.png +0 -0
  13. package/{lib → src}/assets/Brightness.png +0 -0
  14. package/{lib → src}/assets/Hue.png +0 -0
  15. package/{lib → src}/assets/Opacity.png +0 -0
  16. package/{lib → src}/assets/Saturation.png +0 -0
  17. package/src/components/BrightnessSlider.js +108 -0
  18. package/src/components/BrightnessSlider.web.js +1 -0
  19. package/src/components/HueSlider.js +106 -0
  20. package/src/components/HueSlider.web.js +1 -0
  21. package/src/components/OpacitySlider.js +102 -0
  22. package/src/components/OpacitySlider.web.js +1 -0
  23. package/src/components/Panel1.js +126 -0
  24. package/{lib/components/Panel1.js → src/components/Panel1.web.js} +1 -1
  25. package/src/components/Panel2.js +127 -0
  26. package/{lib/components/Panel2.js → src/components/Panel2.web.js} +1 -1
  27. package/src/components/Preview.js +104 -0
  28. package/{lib/components/Preview.js → src/components/Preview.web.js} +0 -0
  29. package/src/components/SaturationSlider.js +115 -0
  30. package/src/components/SaturationSlider.web.js +1 -0
  31. package/src/components/Swatches.js +82 -0
  32. package/{lib/components/Swatches.js → src/components/Swatches.web.js} +0 -0
  33. package/{lib → src}/index.d.ts +0 -0
  34. package/src/index.js +11 -0
  35. package/lib/components/BrightnessSlider.js +0 -1
  36. package/lib/components/HueSlider.js +0 -1
  37. package/lib/components/OpacitySlider.js +0 -1
  38. package/lib/components/SaturationSlider.js +0 -1
  39. package/lib/index.js +0 -1
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "reanimated-color-picker",
3
- "version": "0.0.21",
3
+ "version": "0.0.24",
4
4
  "description": "Pure JavaScript color picker for react-native",
5
- "main": "lib/index.js",
6
- "source": "lib/index.js",
7
- "types": "lib/index.d.ts",
5
+ "main": "src/index.js",
6
+ "types": "src/index.d.ts",
8
7
  "scripts": {
9
- "publish": "npm run build && npm publish",
10
- "build": "@powershell if(test-path lib){ rm lib -r } && babel src --out-dir lib --copy-files"
8
+ "remove-web": "@powershell rm src -r -Include *.web.js",
9
+ "build": "npm run remove-web && babel src --out-dir src --out-file-extension .web.js --ignore src/index.js",
10
+ "prepublishOnly": "npm run build"
11
11
  },
12
12
  "keywords": [
13
13
  "react-native",
@@ -16,7 +16,7 @@
16
16
  "palette"
17
17
  ],
18
18
  "files": [
19
- "lib"
19
+ "src"
20
20
  ],
21
21
  "repository": "https://github.com/alabsi91/reanimated-color-picker",
22
22
  "author": "Ahmed Alabsi <alabsi91@gmail.com> (https://github.com/alabsi91)",
package/readme.md CHANGED
@@ -42,11 +42,11 @@
42
42
 
43
43
  - Use the links below to follow the installation instructions.
44
44
 
45
- - [react-native-gesture-handler](https://docs.swmansion.com/react-native-gesture-handler/docs/installation).
45
+ - [react-native-gesture-handler](https://docs.swmansion.com/react-native-gesture-handler/docs/installation) version `2.0.0` or higher.
46
46
 
47
- - [react-native-reanimated](https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/installation).
47
+ - [react-native-reanimated](https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/installation) version `2.0.0` or higher.
48
48
 
49
- - For `expo` platform, version `44` or higher is required.
49
+ - For `Expo` manged workflow version `44` or higher is required.
50
50
 
51
51
  # :small_blue_diamond:Installation
52
52
 
@@ -64,7 +64,10 @@ npm i reanimated-color-picker
64
64
  - You can add, remove, rearrange or style the color picker's built-in components.
65
65
  - You can also add your components.
66
66
 
67
- - Check out the working example, for bare workflow [here](https://github.com/alabsi91/reanimated-color-picker/tree/main/Example), for Expo managed workflow [here](https://github.com/alabsi91/reanimated-color-picker/tree/main/ExampleExpo)
67
+ - Check out the working examples:
68
+ - Bare workflow [here](https://github.com/alabsi91/reanimated-color-picker/tree/main/Example)
69
+ - Expo managed workflow [here](https://github.com/alabsi91/reanimated-color-picker/tree/main/ExampleExpo)
70
+ - Expo snack [here](https://snack.expo.dev/@alabsi91/reanimated-color-picker)
68
71
 
69
72
  ```jsx
70
73
  import React, { useState } from 'react';
@@ -276,4 +279,4 @@ export default function App() {
276
279
 
277
280
  # :small_blue_diamond:License
278
281
 
279
- - [**MIT**](https://github.com/alabsi91/reanimated-color-picker/blob/main/LICENSE)
282
+ - Reanimated Color Picker library is licensed under [**The MIT License.**](https://github.com/alabsi91/reanimated-color-picker/blob/main/LICENSE)
@@ -0,0 +1,439 @@
1
+ import React, { useRef, useEffect, useMemo } from 'react';
2
+ import { I18nManager, Text, StyleSheet } from 'react-native';
3
+ import { GestureHandlerRootView } from 'react-native-gesture-handler';
4
+ import {
5
+ useAnimatedStyle,
6
+ useSharedValue,
7
+ withTiming,
8
+ } from 'react-native-reanimated';
9
+ import {
10
+ ALPHA_HEX,
11
+ COLOR_HSVA,
12
+ CONTRAST_RATIO,
13
+ HSL_HEX,
14
+ HSL_RGB,
15
+ HSV_HSL,
16
+ } from './ColorsConversionFormulas';
17
+
18
+ const isRtl = I18nManager.isRTL,
19
+ CONTRAST_RATIO_MIN = 4.5;
20
+
21
+ export default function ColorPicker({
22
+ tracksHeight = 25,
23
+ thumbsSize = 25 * 1.4,
24
+ value = '#418181',
25
+ onChange,
26
+ onComplete,
27
+ width = 300,
28
+ style = {},
29
+ children = <Text>NO CHILDREN</Text>,
30
+ } = {}) {
31
+ const isFirstRender = useRef(true);
32
+ const initialColor = useRef(COLOR_HSVA(value));
33
+ const previewColorFormat = useRef('hex');
34
+
35
+ const panel1ThumbeSize = useRef(thumbsSize);
36
+ const panel2ThumbeSize = useRef(thumbsSize);
37
+ const hueThumbeSize = useRef(thumbsSize);
38
+ const brightnessThumbeSize = useRef(thumbsSize);
39
+ const saturationThumbeSize = useRef(thumbsSize);
40
+ const opacityThumbeSize = useRef(thumbsSize);
41
+
42
+ const hue = useRef(initialColor.current.h);
43
+ const saturation = useRef(initialColor.current.s);
44
+ const brightness = useRef(initialColor.current.b);
45
+ const alpha = useRef(initialColor.current.a);
46
+
47
+ const color_hsl = (
48
+ color = { h: hue.current, s: saturation.current, b: brightness.current },
49
+ ) => {
50
+ const { h, s, l } = HSV_HSL(color.h, color.s, color.b);
51
+ return `hsl(${h}, ${s}%, ${l}%)`;
52
+ };
53
+ const color_hsla = (
54
+ color = {
55
+ h: hue.current,
56
+ s: saturation.current,
57
+ b: brightness.current,
58
+ a: alpha.current,
59
+ },
60
+ ) => {
61
+ const { h, s, l } = HSV_HSL(color.h, color.s, color.b);
62
+ return `hsla(${h}, ${s}%, ${l}%, ${color.a / 100})`;
63
+ };
64
+ const color_hex = (
65
+ color = {
66
+ h: hue.current,
67
+ s: saturation.current,
68
+ b: brightness.current,
69
+ a: alpha.current,
70
+ },
71
+ ) => {
72
+ const { h, s, l } = HSV_HSL(color.h, color.s, color.b);
73
+ return HSL_HEX(h, s, l) + (color.a === 100 ? '' : ALPHA_HEX(color.a));
74
+ };
75
+ const color_rgb = (
76
+ color = { h: hue.current, s: saturation.current, b: brightness.current },
77
+ ) => {
78
+ const { h, s, l } = HSV_HSL(color.h, color.s, color.b);
79
+ const { r, g, b } = HSL_RGB(h, s, l);
80
+ return `rgb(${r}, ${g}, ${b})`;
81
+ };
82
+ const color_rgba = (
83
+ color = {
84
+ h: hue.current,
85
+ s: saturation.current,
86
+ b: brightness.current,
87
+ a: alpha.current,
88
+ },
89
+ ) => {
90
+ const { h, s, l } = HSV_HSL(color.h, color.s, color.b);
91
+ const { r, g, b } = HSL_RGB(h, s, l);
92
+ return `rgba(${r}, ${g}, ${b}, ${color.a / 100})`;
93
+ };
94
+ const color_hsv = (
95
+ color = { h: hue.current, s: saturation.current, b: brightness.current },
96
+ ) => {
97
+ return `hsv(${color.h}, ${color.s}%, ${color.b}%)`;
98
+ };
99
+ const color_hsva = (
100
+ color = {
101
+ h: hue.current,
102
+ s: saturation.current,
103
+ b: brightness.current,
104
+ a: alpha.current,
105
+ },
106
+ ) => {
107
+ return `hsva(${color.h}, ${color.s}%, ${color.b}%, ${color.a / 100})`;
108
+ };
109
+
110
+ const returnedResults = (
111
+ color = {
112
+ h: hue.current,
113
+ s: saturation.current,
114
+ b: brightness.current,
115
+ a: alpha.current,
116
+ },
117
+ ) => {
118
+ return {
119
+ hex: color_hex(color),
120
+ rgb: color_rgb(color),
121
+ rgba: color_rgba(color),
122
+ hsl: color_hsl(color),
123
+ hsla: color_hsla(color),
124
+ hsv: color_hsv(color),
125
+ hsva: color_hsva(color),
126
+ };
127
+ };
128
+
129
+ const previewColor = useSharedValue(color_hex());
130
+ const previewColorStyle = useAnimatedStyle(() => ({
131
+ backgroundColor: previewColor.value,
132
+ }));
133
+ const previewColorWithoutOpacity = useAnimatedStyle(() => ({
134
+ backgroundColor:
135
+ previewColor.value.length > 7
136
+ ? previewColor.value.substring(0, 7)
137
+ : previewColor.value,
138
+ }));
139
+ const activeHue = useSharedValue(HSL_HEX(hue.current, 100, 50));
140
+ const activeHueStyle = useAnimatedStyle(() => ({
141
+ backgroundColor: activeHue.value,
142
+ }));
143
+
144
+ const saturationPanel1_handlePos = useSharedValue(0); // for saturation panle 1 adobe style
145
+ const brightnessPanel1_handlePos = useSharedValue(0); // for brightness panle 1 adobe style
146
+
147
+ const huePanel2_handlePos = useSharedValue(0); // for hue panle 2 windows style
148
+ const saturationPanel2_handlePos = useSharedValue(0); // for saturation panle 2 windows style
149
+
150
+ const hue_handlePos = useSharedValue(0); // for hue slider
151
+ const saturationSlider_handlePos = useSharedValue(0); // for saturation slider
152
+ const brightnessSlider_handlePos = useSharedValue(0); // for brightness slider
153
+ const opacity_handlePos = useSharedValue(0); // for opacity slider
154
+ const previewTextColor = useSharedValue('#ffffff'); // for result text color
155
+ const previewText = useSharedValue(
156
+ returnedResults()[previewColorFormat.current],
157
+ ); // for result text
158
+
159
+ const previewTextColorStyle = useAnimatedStyle(() => ({
160
+ color: previewTextColor.value,
161
+ }));
162
+
163
+ const onGestureEventFinish = () => {
164
+ onComplete?.(returnedResults());
165
+ };
166
+
167
+ const updateBrightness = brightnessChannel => {
168
+ brightness.current = brightnessChannel;
169
+ previewColor.value = color_hex(); // to update result color.
170
+ previewText.value = returnedResults()[previewColorFormat.current]; // update result text
171
+ // change result text color based on lightness
172
+ const contrast = CONTRAST_RATIO(
173
+ hue.current,
174
+ saturation.current,
175
+ brightness.current,
176
+ previewTextColor.value,
177
+ );
178
+ previewTextColor.value =
179
+ contrast < CONTRAST_RATIO_MIN
180
+ ? previewTextColor.value === '#ffffff'
181
+ ? '#000000'
182
+ : '#ffffff'
183
+ : previewTextColor.value;
184
+
185
+ onChange?.(returnedResults());
186
+ };
187
+
188
+ const updateSaturation = saturationChannel => {
189
+ saturation.current = saturationChannel;
190
+ previewColor.value = color_hex(); // to update result color.
191
+ previewText.value = returnedResults()[previewColorFormat.current]; // update result text
192
+ // change result text color based on lightness
193
+ const contrast = CONTRAST_RATIO(
194
+ hue.current,
195
+ saturation.current,
196
+ brightness.current,
197
+ previewTextColor.value,
198
+ );
199
+ previewTextColor.value =
200
+ contrast < CONTRAST_RATIO_MIN
201
+ ? previewTextColor.value === '#ffffff'
202
+ ? '#000000'
203
+ : '#ffffff'
204
+ : previewTextColor.value;
205
+
206
+ onChange?.(returnedResults());
207
+ };
208
+
209
+ const updateSB = (saturationChannel, brightnessChannel) => {
210
+ saturation.current = saturationChannel;
211
+ brightness.current = brightnessChannel;
212
+ previewColor.value = color_hex(); // to update result color.
213
+ previewText.value = returnedResults()[previewColorFormat.current]; // update result text
214
+ // change result text color based on lightness
215
+ const contrast = CONTRAST_RATIO(
216
+ hue.current,
217
+ saturation.current,
218
+ brightness.current,
219
+ previewTextColor.value,
220
+ );
221
+ previewTextColor.value =
222
+ contrast < CONTRAST_RATIO_MIN
223
+ ? previewTextColor.value === '#ffffff'
224
+ ? '#000000'
225
+ : '#ffffff'
226
+ : previewTextColor.value;
227
+
228
+ onChange?.(returnedResults());
229
+ };
230
+
231
+ const updateHS = (hueChannel, saturationChannel) => {
232
+ saturation.current = saturationChannel;
233
+ hue.current = hueChannel;
234
+ previewColor.value = color_hex(); // to update result color.
235
+ previewText.value = returnedResults()[previewColorFormat.current]; // update result text
236
+ // change result text color based on lightness
237
+ const contrast = CONTRAST_RATIO(
238
+ hue.current,
239
+ saturation.current,
240
+ brightness.current,
241
+ previewTextColor.value,
242
+ );
243
+ previewTextColor.value =
244
+ contrast < CONTRAST_RATIO_MIN
245
+ ? previewTextColor.value === '#ffffff'
246
+ ? '#000000'
247
+ : '#ffffff'
248
+ : previewTextColor.value;
249
+
250
+ activeHue.value = HSL_HEX(hueChannel, 100, 50);
251
+ onChange?.(returnedResults());
252
+ };
253
+
254
+ const updateHue = hueChannel => {
255
+ hue.current = hueChannel;
256
+ previewColor.value = color_hex(); // to update result color.
257
+ previewText.value = returnedResults()[previewColorFormat.current]; // update color text
258
+ // change result text color based on lightness
259
+ const contrast = CONTRAST_RATIO(
260
+ hue.current,
261
+ saturation.current,
262
+ brightness.current,
263
+ previewTextColor.value,
264
+ );
265
+ previewTextColor.value =
266
+ contrast < CONTRAST_RATIO_MIN
267
+ ? previewTextColor.value === '#ffffff'
268
+ ? '#000000'
269
+ : '#ffffff'
270
+ : previewTextColor.value;
271
+
272
+ activeHue.value = HSL_HEX(hueChannel, 100, 50);
273
+ onChange?.(returnedResults());
274
+ };
275
+
276
+ const updateOpacity = alphaChannel => {
277
+ alpha.current = alphaChannel;
278
+ previewColor.value = color_hex(); // to update result color.
279
+ previewText.value = returnedResults()[previewColorFormat.current]; // update result text
280
+
281
+ onChange?.(returnedResults());
282
+ };
283
+
284
+ const setHandlesPos = () => {
285
+ const duration = 100;
286
+ const { h, s, b, a } = initialColor.current;
287
+
288
+ hue.current = h;
289
+ saturation.current = s;
290
+ brightness.current = b;
291
+ alpha.current = a;
292
+ // for colors
293
+ previewColor.value = color_hex(); // update result color.
294
+ previewText.value = returnedResults()[previewColorFormat.current]; // update result text
295
+ activeHue.value = HSL_HEX(h, 100, 50);
296
+ // change result text color based on lightness
297
+ const contrast = CONTRAST_RATIO(
298
+ hue.current,
299
+ saturation.current,
300
+ brightness.current,
301
+ previewTextColor.value,
302
+ );
303
+ previewTextColor.value =
304
+ contrast < CONTRAST_RATIO_MIN
305
+ ? previewTextColor.value === '#ffffff'
306
+ ? '#000000'
307
+ : '#ffffff'
308
+ : previewTextColor.value;
309
+ //~ saturation
310
+ saturationPanel1_handlePos.value = withTiming(
311
+ isRtl
312
+ ? (s / 100) * width - width + panel1ThumbeSize.current / 2
313
+ : (s / 100) * width - panel1ThumbeSize.current / 2,
314
+ duration,
315
+ ); // panel 1 adobe style
316
+ saturationPanel2_handlePos.value = withTiming(
317
+ width - (s / 100) * width - panel2ThumbeSize.current / 2,
318
+ duration,
319
+ ); // panel 2 windows style
320
+ saturationSlider_handlePos.value = withTiming(
321
+ isRtl
322
+ ? (s / 100) * width - width + saturationThumbeSize.current / 2
323
+ : (s / 100) * width - saturationThumbeSize.current / 2,
324
+ duration,
325
+ );
326
+ //~ brightness
327
+ brightnessPanel1_handlePos.value = withTiming(
328
+ width - (b / 100) * width - panel1ThumbeSize.current / 2,
329
+ duration,
330
+ );
331
+ brightnessSlider_handlePos.value = withTiming(
332
+ isRtl
333
+ ? (b / 100) * width - width + brightnessThumbeSize.current / 2
334
+ : (b / 100) * width - brightnessThumbeSize.current / 2,
335
+ duration,
336
+ );
337
+ //~ hue
338
+ hue_handlePos.value = withTiming(
339
+ isRtl
340
+ ? width - (h / 360) * width - width + hueThumbeSize.current / 2
341
+ : width - (h / 360) * width - hueThumbeSize.current / 2,
342
+ 100,
343
+ );
344
+ huePanel2_handlePos.value = withTiming(
345
+ isRtl
346
+ ? (h / 360) * width - width + panel2ThumbeSize.current / 2
347
+ : (h / 360) * width - panel2ThumbeSize.current / 2,
348
+ duration,
349
+ ); // panel 2 windows style
350
+ //~ opacity
351
+ opacity_handlePos.value = withTiming(
352
+ isRtl
353
+ ? (a / 100) * width - width + opacityThumbeSize.current / 2
354
+ : (a / 100) * width - opacityThumbeSize.current / 2,
355
+ duration,
356
+ );
357
+ };
358
+
359
+ // when value change, update handles pos.
360
+ useEffect(() => {
361
+ if (isFirstRender.current) {
362
+ isFirstRender.current = false;
363
+ setHandlesPos();
364
+ return;
365
+ }
366
+ initialColor.current = COLOR_HSVA(value);
367
+ setHandlesPos();
368
+ }, [value, width]);
369
+
370
+ const RenderChildren = () =>
371
+ React.Children.map(children, child =>
372
+ React.isValidElement(child)
373
+ ? React.cloneElement(child, {
374
+ activeHueStyle,
375
+
376
+ previewText,
377
+ previewTextColor,
378
+ previewTextColorStyle,
379
+ previewColorStyle,
380
+ previewColorWithoutOpacity,
381
+ previewColorFormat,
382
+
383
+ setHandlesPos,
384
+ saturationPanel1_handlePos,
385
+ brightnessPanel1_handlePos,
386
+ saturationPanel2_handlePos,
387
+ huePanel2_handlePos,
388
+ saturationSlider_handlePos,
389
+ brightnessSlider_handlePos,
390
+ hue_handlePos,
391
+ opacity_handlePos,
392
+
393
+ updateSaturation,
394
+ updateBrightness,
395
+ updateSB,
396
+ updateHS,
397
+ updateOpacity,
398
+ updateHue,
399
+
400
+ tracksHeight,
401
+ thumbsSize,
402
+
403
+ panel1ThumbeSize,
404
+ panel2ThumbeSize,
405
+ saturationThumbeSize,
406
+ brightnessThumbeSize,
407
+ hueThumbeSize,
408
+ opacityThumbeSize,
409
+
410
+ value,
411
+ width,
412
+ initialColor,
413
+ returnedResults,
414
+
415
+ onGestureEventFinish,
416
+ onChange,
417
+ onComplete,
418
+ ...child.props,
419
+ })
420
+ : null,
421
+ );
422
+
423
+ const ColorPickerModules = useMemo(() => RenderChildren(), []);
424
+
425
+ return (
426
+ <GestureHandlerRootView style={[styles.wrapper, style]}>
427
+ {ColorPickerModules}
428
+ </GestureHandlerRootView>
429
+ );
430
+ }
431
+
432
+ const styles = StyleSheet.create({
433
+ wrapper: {
434
+ flexDirection: 'column',
435
+ justifyContent: 'space-evenly',
436
+ alignSelf: 'center',
437
+ flex: 1,
438
+ },
439
+ });
File without changes