diff --git a/demo/src/screens/PlaygroundScreen.tsx b/demo/src/screens/PlaygroundScreen.tsx
index 0bda100e67..9b00628acc 100644
--- a/demo/src/screens/PlaygroundScreen.tsx
+++ b/demo/src/screens/PlaygroundScreen.tsx
@@ -1,20 +1,11 @@
-import React, {Component} from 'react';
-import {View, Text, Card, TextField, Button} from 'react-native-ui-lib';
+import React, {Component, useState} from 'react';
+import {View, ColorPicker, Gradient, Button, GradientTypes} from 'react-native-ui-lib';
-export default class PlaygroundScreen extends Component {
- render() {
- return (
-
-
-
-
-
- Playground Screen
-
-
-
-
-
- );
- }
-}
+export default () => {
+ const [colors, setColors] = useState(['#ddaaaa', '#badddd']);
+ return (
+
+ setColors(prev => [...prev, color])}/>
+
+ );
+};
diff --git a/src/components/colorPicker/ColorPickerDialog.tsx b/src/components/colorPicker/ColorPickerDialog.tsx
index 926498459a..7152beb494 100644
--- a/src/components/colorPicker/ColorPickerDialog.tsx
+++ b/src/components/colorPicker/ColorPickerDialog.tsx
@@ -1,14 +1,16 @@
-import _ from 'lodash';
import React, {useCallback, useEffect, useState} from 'react';
import {LayoutAnimation, StyleSheet, Keyboard, StyleProp, ViewStyle} from 'react-native';
+import {useSharedValue} from 'react-native-reanimated';
+import tinycolor from 'tinycolor2';
import {Constants, asBaseComponent} from '../../commons/new';
import {Colors} from '../../style';
import {ModalProps} from '../../components/modal';
import Dialog, {DialogProps} from '../../incubator/Dialog';
-import {getColorValue, getValidColorString, getTextColor, BORDER_RADIUS, HSLColor} from './ColorPickerPresenter';
+import {getTextColor, BORDER_RADIUS} from './ColorPickerPresenter';
import Header from './ColorPickerDialogHeader';
import Preview from './ColorPickerPreview';
import Sliders from './ColorPickerDialogSliders';
+import {ColorPickerContextProvider} from './context/ColorPickerContext';
export interface ColorPickerDialogProps extends DialogProps {
/**
@@ -68,9 +70,7 @@ const ColorPickerDialog = (props: ColorPickerDialogProps) => {
} = props;
const [keyboardHeight, setKeyboardHeight] = useState(KEYBOARD_HEIGHT);
- const [color, setColor] = useState(Colors.getHSL(initialColor));
- const [text, setText] = useState(getColorValue(initialColor));
- const [valid, setValid] = useState(getValidColorString(text).valid);
+ const color = useSharedValue(tinycolor(initialColor).toHsl());
const changeHeight = (height: number) => {
setKeyboardHeight(prevKeyboardHeight => {
@@ -107,13 +107,7 @@ const ColorPickerDialog = (props: ColorPickerDialogProps) => {
}, [keyboardDidShow, keyboardDidHide]);
const resetValues = () => {
- const color = Colors.getHSL(initialColor);
- const text = getColorValue(initialColor);
- const {valid} = getValidColorString(text);
-
- setColor(color);
- setText(text);
- setValid(valid);
+ color.value = tinycolor(initialColor).toHsl();
};
const onDismiss = () => {
@@ -122,8 +116,7 @@ const ColorPickerDialog = (props: ColorPickerDialogProps) => {
};
const onDonePressed = () => {
- const {hex} = getValidColorString(text);
-
+ const hex = tinycolor(color.value).toHexString();
if (hex) {
props.onSubmit?.(hex, getTextColor(hex));
onDismiss();
@@ -133,58 +126,38 @@ const ColorPickerDialog = (props: ColorPickerDialogProps) => {
changeHeight(0);
};
- const onChangeText = (value: string) => {
- applyColor(value);
- };
-
- const applyColor = (text: string) => {
- const {hex, valid} = getValidColorString(text);
-
- if (hex) {
- setColor(Colors.getHSL(hex));
- }
- setText(text);
- setValid(valid);
- };
-
- const updateColor = useCallback((value: HSLColor) => {
- setColor(value);
- const hex = Colors.getHexString(value);
- setText(_.toUpper(getColorValue(hex)));
- setValid(true);
- }, []);
return (
-
+ containerStyle={styles.dialog}
+ testID={`${testID}.dialog`}
+ modalProps={MODAL_PROPS}
+ {...dialogProps}
+ >
+
+ {
+ color.value = tinycolor(value).toHsl();
+ }}
+ />
+
+
+
);
};
diff --git a/src/components/colorPicker/ColorPickerDialogHeader.tsx b/src/components/colorPicker/ColorPickerDialogHeader.tsx
index 3b0a550e0c..1d87bf606e 100644
--- a/src/components/colorPicker/ColorPickerDialogHeader.tsx
+++ b/src/components/colorPicker/ColorPickerDialogHeader.tsx
@@ -1,5 +1,5 @@
import _ from 'lodash';
-import React from 'react';
+import React, {useContext, useState} from 'react';
import {StyleSheet} from 'react-native';
import View from '../view';
@@ -8,15 +8,27 @@ import Assets from '../../assets';
import {Colors} from '../../style';
import {ColorPickerDialogProps} from './ColorPickerDialog';
import {BORDER_RADIUS} from './ColorPickerPresenter';
+import {ColorPickerContext} from './context/ColorPickerContext';
+import {runOnJS, useAnimatedReaction} from 'react-native-reanimated';
type HeaderProps = Pick & {
- valid: boolean;
onDismiss: () => void;
- onDonePressed: () => void;
+ onDonePressed: (hex: string) => void;
};
const Header = (props: HeaderProps) => {
- const {onDismiss, accessibilityLabels, testID, doneButtonColor, valid, onDonePressed} = props;
+ const {onDismiss, accessibilityLabels, testID, doneButtonColor, onDonePressed} = props;
+ const [valid, setValid] = useState(false);
+ const colorPickerContext = useContext(ColorPickerContext);
+
+ useAnimatedReaction(() => {
+ return colorPickerContext?.isValid.value;
+ },
+ (currentValidity, prevValidity) => {
+ if (currentValidity !== prevValidity) {
+ runOnJS(setValid)(!!currentValidity);
+ }
+ });
return (
diff --git a/src/components/colorPicker/ColorPickerDialogSliders.tsx b/src/components/colorPicker/ColorPickerDialogSliders.tsx
index 335d89c691..ca47332e6d 100644
--- a/src/components/colorPicker/ColorPickerDialogSliders.tsx
+++ b/src/components/colorPicker/ColorPickerDialogSliders.tsx
@@ -1,22 +1,26 @@
-import React from 'react';
+import React, {useContext} from 'react';
import {StyleSheet} from 'react-native';
import {Colors} from '../../style';
import ColorSliderGroup from '../slider/ColorSliderGroup';
import {HSLColor} from './ColorPickerPresenter';
import {ColorPickerDialogProps} from './ColorPickerDialog';
+import {ColorPickerContext} from './context/ColorPickerContext';
type SlidersProps = Pick & {
keyboardHeight: number;
- color: HSLColor;
- onSliderValueChange: (value: HSLColor) => void;
};
const Sliders = (props: SlidersProps) => {
- const {keyboardHeight, color, migrate, onSliderValueChange} = props;
- const colorValue = color.a === 0 ? Colors.getHSL(Colors.$backgroundInverted) : color;
-
+ const {keyboardHeight, migrate} = props;
+ const colorPickerContext = useContext(ColorPickerContext);
+ const colorValue =
+ !colorPickerContext || colorPickerContext.statefulColor.a === 0
+ ? Colors.getHSL(Colors.$backgroundInverted)
+ : colorPickerContext.statefulColor;
+ console.log(`Nitzan - sliders colorValue`, colorValue);
return (
+ key={Colors.getHexString(colorValue)}
initialColor={colorValue}
containerStyle={[styles.sliderGroup, {height: keyboardHeight}]}
sliderContainerStyle={styles.slider}
@@ -24,7 +28,6 @@ const Sliders = (props: SlidersProps) => {
labelsStyle={styles.label}
accessible={false}
migrate={migrate}
- onValueChange={onSliderValueChange}
/>
);
};
diff --git a/src/components/colorPicker/ColorPickerPresenter.ts b/src/components/colorPicker/ColorPickerPresenter.ts
index 226fff1fd6..3678d580ca 100644
--- a/src/components/colorPicker/ColorPickerPresenter.ts
+++ b/src/components/colorPicker/ColorPickerPresenter.ts
@@ -10,8 +10,14 @@ export function getColorValue(color?: string) {
}
return color.replace('#', '');
}
+
+export function isTransparent(color?: string) {
+ 'worklet';
+ return color && color.toUpperCase() === 'transparent'.toUpperCase();
+}
export function getHexColor(text: string) {
- if (!Colors.isTransparent(text)) {
+ 'worklet';
+ if (!isTransparent(text)) {
const trimmed = text.replace(/\s+/g, '');
const hex = `#${trimmed}`;
return hex;
@@ -19,17 +25,38 @@ export function getHexColor(text: string) {
return text;
}
+export function isValidHex(string: string) {
+ 'worklet';
+ return /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(string);
+}
+
export function getValidColorString(text?: string) {
+ 'worklet';
if (text) {
const hex = getHexColor(text);
- if (Colors.isValidHex(hex)) {
+ if (isValidHex(hex)) {
return {hex, valid: true};
}
}
return {undefined, valid: false};
}
+export function hslToHex(hsl: {h: number; s: number; l: number}) {
+ 'worklet';
+ let {h, s, l} = hsl;
+ l /= 100;
+ const a = (s * Math.min(l, 1 - l)) / 100;
+ const f = (n: number) => {
+ const k = (n + h / 30) % 12;
+ const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
+ return Math.round(255 * color)
+ .toString(16)
+ .padStart(2, '0'); // convert to Hex and prefix "0" if needed
+ };
+ return `${f(0)}${f(8)}${f(4)}`;
+}
+
export function getHexString(color: HSLColor) {
return _.toUpper(Colors.getHexString(color));
}
diff --git a/src/components/colorPicker/ColorPickerPreview.tsx b/src/components/colorPicker/ColorPickerPreview.tsx
index e67f19e32f..d15804b712 100644
--- a/src/components/colorPicker/ColorPickerPreview.tsx
+++ b/src/components/colorPicker/ColorPickerPreview.tsx
@@ -1,64 +1,184 @@
-import React, {useRef} from 'react';
-import {StyleSheet, TextInput, PixelRatio, I18nManager} from 'react-native';
+import React, {useContext, useState, useRef, useEffect} from 'react';
+import {StyleSheet, TextInput, PixelRatio, I18nManager, TextInputProps} from 'react-native';
import {Colors, Typography} from '../../style';
import {ColorPickerDialogProps} from './ColorPickerDialog';
-import {BORDER_RADIUS, HSLColor, getColorValue, getHexString, getTextColor} from './ColorPickerPresenter';
+import {BORDER_RADIUS, isValidHex} from './ColorPickerPresenter';
+import {ColorPickerContext} from './context/ColorPickerContext';
import View from '../view';
import TouchableOpacity from '../touchableOpacity';
-import Text from '../text';
import {Constants} from '../../commons/new';
+import Animated, {useAnimatedStyle, useAnimatedProps, useDerivedValue} from 'react-native-reanimated';
+import tinycolor from 'tinycolor2';
type PreviewProps = Pick & {
- color: HSLColor;
- text: ReturnType;
- valid: boolean;
onChangeText: (value: string) => void;
onFocus: () => void;
};
-const Preview = (props: PreviewProps) => {
- const {color, text, onChangeText, previewInputStyle, onFocus, accessibilityLabels, testID} = props;
- const textInput = useRef(null);
- const hex = getHexString(color);
- const textColor = getTextColor(hex);
+Animated.addWhitelistedNativeProps({text: true, selectionColor: true});
+
+const AnimatedTextInput = Animated.createAnimatedComponent(TextInput);
+
+const Preview = (props: PreviewProps) => {
+ const {previewInputStyle, onFocus, accessibilityLabels, testID} = props;
+ const colorPickerContext = useContext(ColorPickerContext);
+ const {grey10, white} = Colors;
const fontScale = PixelRatio.getFontScale();
- const value = Colors.isTransparent(text) ? '000000' : text;
+ const [isFocused, setIsFocused] = useState(false);
+ const [hex, setHex] = useState(colorPickerContext?.hex.value || '#');
+
+ const previewBackgroundColor = useAnimatedStyle(() => {
+ return {
+ backgroundColor: colorPickerContext?.hex.value || '#ffffff'
+ };
+ }, [colorPickerContext]);
+
+ const textColor = useDerivedValue(() => {
+ const l = colorPickerContext?.value.value.l;
+ return l && l > 0.45 ? grey10 : white;
+ });
+
+ const textStyle = useAnimatedStyle(() => {
+ return {
+ color: textColor.value,
+ width: 10 * 16.5 * fontScale
+ };
+ });
+ const underlineStyle = useAnimatedStyle(() => {
+ return {
+ backgroundColor: textColor.value
+ };
+ });
+
+ const animatedProps = useAnimatedProps(() => {
+ return {
+ text: colorPickerContext?.hex.value
+ // selectionColor: textColor.value
+ } as any;
+ }, [colorPickerContext]);
+
+ const _onFocus = () => {
+ setIsFocused(true);
+ setHex(colorPickerContext?.hex.value || '#');
+ };
+ const _onChangeText = (value: string) => {
+ if (isFocused) {
+ setHex(value || '#');
+ }
+ };
+
+ const onBlur = () => {
+ if (!isValidHex(hex)) {
+ return;
+ }
+ if (colorPickerContext) {
+ colorPickerContext.setColor(tinycolor(hex).toHsl());
+ }
+ setIsFocused(false);
+ setHex('#');
+ };
+
+ // const TextInputRenderFunction = (props: {focusedProps: Partial; notFocusedProps: Partial}) => {
+ // const {focusedProps, notFocusedProps} = props;
+ // if (!isFocused) {
+ // return (
+ // {
+ // _onFocus();
+ // }}
+ // activeOpacity={1}
+ // accessible={false}
+ // >
+ //
+ //
+ // );
+ // } else {
+ // return (
+ //
+ // );
+ // }
+ // };
+
+ console.log(`Nitzan - isFocused`, isFocused);
return (
-
-
-
-
+
+ {!isFocused ? (
+ {
+ _onFocus();
}}
+ activeOpacity={1}
accessible={false}
- recorderTag={'unmask'}
>
- #
-
-
+
+ ) : (
+ {
// keyboardType={'numbers-and-punctuation'} // doesn't work with `autoCapitalize`
returnKeyType={'done'}
enablesReturnKeyAutomatically
- onFocus={onFocus}
accessibilityLabel={accessibilityLabels?.input}
testID={`${testID}.dialog.textInput`}
+ onBlur={onBlur}
+ onFocus={onFocus}
+ autoFocus
/>
-
-
-
-
+ )}
+
+
+
);
};
diff --git a/src/components/colorPicker/context/ColorPickerContext.tsx b/src/components/colorPicker/context/ColorPickerContext.tsx
new file mode 100644
index 0000000000..92c0bf5798
--- /dev/null
+++ b/src/components/colorPicker/context/ColorPickerContext.tsx
@@ -0,0 +1,97 @@
+import React, {PropsWithChildren, createContext, useCallback, useMemo, useState} from 'react';
+import {SharedValue, runOnJS, useAnimatedReaction, useSharedValue, useWorkletCallback} from 'react-native-reanimated';
+import type {ColorFormats} from 'tinycolor2';
+import {getValidColorString, hslToHex} from '../ColorPickerPresenter';
+
+type HSLA = ColorFormats.HSLA;
+export type SharedColorContextType = {
+ value: SharedValue;
+ hex: SharedValue;
+ isValid: SharedValue;
+ statefulColor: ColorFormats.HSLA;
+ setColor: (hsla: HSLA) => void;
+ updateAlpha: (a: number) => void;
+ updateHue: (h: number) => void;
+ updateSaturation: (s: number) => void;
+ updateLightness: (l: number) => void;
+ reset: () => void;
+};
+
+export const ColorPickerContext = createContext(null);
+
+interface ColorPickerContextProviderProps extends PropsWithChildren {
+ color: T;
+}
+
+const DEFAULT_VALUE = {h: 0, s: 0, l: 0, a: 0};
+
+export const ColorPickerContextProvider = (props: ColorPickerContextProviderProps>) => {
+ const {color, children} = props;
+ const [statefulColor, setStatefulColor] = useState(color.value);
+
+ const reset = useCallback(() => {
+ color.value = DEFAULT_VALUE;
+ }, [color]);
+
+ const updateAlpha = useWorkletCallback((a: number) => {
+ 'worklet';
+ color.value = {...color.value, a};
+ },
+ [color]);
+
+ const updateHue = useWorkletCallback((h: number) => {
+ 'worklet';
+ console.log(`Nitzan - h`, h);
+ color.value = {...color.value, h};
+ },
+ [color]);
+ const updateLightness = useWorkletCallback((l: number) => {
+ 'worklet';
+ color.value = {...color.value, l};
+ },
+ [color]);
+ const updateSaturation = useWorkletCallback((s: number) => {
+ 'worklet';
+ color.value = {...color.value, s};
+ },
+ [color]);
+
+ const hex = useSharedValue(undefined);
+ const isValid = useSharedValue(false);
+
+ useAnimatedReaction(() => {
+ const {h, s, l} = color.value;
+ return getValidColorString(hslToHex({h, s: s * 100, l: l * 100}));
+ },
+ (current, prev) => {
+ if (current.hex !== prev?.hex) {
+ if (current.valid) {
+ hex.value = current.hex?.toUpperCase();
+ }
+ }
+ if (current.valid !== prev?.valid) {
+ isValid.value = current.valid;
+ }
+ });
+
+ const setColor = useWorkletCallback((hsla: HSLA) => {
+ color.value = hsla;
+ runOnJS(setStatefulColor)(hsla);
+ });
+
+ const providerValue = useMemo(() => {
+ return {
+ value: color,
+ hex,
+ isValid,
+ statefulColor,
+ setColor,
+ updateAlpha,
+ updateHue,
+ updateLightness,
+ updateSaturation,
+ reset
+ };
+ }, [color, reset, updateAlpha, updateHue, updateLightness, updateSaturation, hex, isValid, setColor, statefulColor]);
+ return {children};
+};
diff --git a/src/components/gradient/AnimatedGradient.tsx b/src/components/gradient/AnimatedGradient.tsx
new file mode 100644
index 0000000000..3dfbcafae6
--- /dev/null
+++ b/src/components/gradient/AnimatedGradient.tsx
@@ -0,0 +1,91 @@
+import React, {useMemo} from 'react';
+import {GradientTypes} from './index';
+import View from '../view';
+import Constants from '../../commons/Constants';
+import Colors from '../../style/colors';
+import Animated, {SharedValue, useAnimatedStyle, isSharedValue} from 'react-native-reanimated';
+import {StyleSheet, StyleProp, ViewStyle} from 'react-native';
+import tinycolor from 'tinycolor2';
+
+const toHSLStringWorklet = (hsla: tinycolor.ColorFormats.HSLA | tinycolor.ColorFormats.HSL) => {
+ 'worklet';
+ if ('a' in hsla) {
+ return `hsla(${hsla.h}, ${Math.round(hsla.s * 100)}%, ${Math.round(hsla.l * 100)}%, ${hsla.a})`;
+ }
+ return `hsl(${hsla.h}, ${Math.round(hsla.s * 100)}%, ${Math.round(hsla.l * 100)}%)`;
+};
+
+interface GradientStepProps {
+ color?: SharedValue;
+ index: number;
+ type?: GradientTypes | `${GradientTypes}`;
+ numberOfSteps: number;
+}
+
+const AnimatedGradientStep = (props: GradientStepProps) => {
+ const {color = tinycolor(Colors.white).toHsl(), type, index, numberOfSteps} = props;
+ const maximum = type === GradientTypes.HUE ? 359 : 1;
+ const i = (index * maximum) / numberOfSteps;
+
+ const animatedStepStyle = useAnimatedStyle(() => {
+ const hslColor = isSharedValue(color) ? color.value : color;
+ let backgroundColor;
+ switch (type) {
+ case GradientTypes.HUE:
+ backgroundColor = toHSLStringWorklet({s: 1, l: 0.5, h: i});
+ break;
+ case GradientTypes.LIGHTNESS:
+ backgroundColor = toHSLStringWorklet({...hslColor, l: i});
+ break;
+ case GradientTypes.SATURATION:
+ backgroundColor = toHSLStringWorklet({...hslColor, s: i});
+ break;
+ default:
+ backgroundColor = toHSLStringWorklet({...hslColor, a: i});
+ }
+ return {
+ backgroundColor
+ };
+ });
+ return ;
+};
+
+export interface AnimatedGradientProps {
+ color?: Readonly>;
+ type?: GradientTypes | `${GradientTypes}`;
+ numberOfSteps: number;
+ style?: StyleProp;
+}
+
+const AnimatedGradient = (props: AnimatedGradientProps) => {
+ const {color, type, numberOfSteps, style} = props;
+ const rows = Array(numberOfSteps);
+ for (let index = 0; index < numberOfSteps; index++) {
+ rows[index] = (
+
+ );
+ }
+
+ const containerStyle = useMemo(() => {
+ return [styles.container, style];
+ }, [style]);
+
+ return {rows};
+};
+
+AnimatedGradient.types = GradientTypes;
+
+export default AnimatedGradient;
+
+const styles = StyleSheet.create({
+ row: {
+ flex: 1,
+ marginLeft: Constants.isIOS ? -StyleSheet.hairlineWidth : 0
+ },
+ container: {
+ flex: 1,
+ flexDirection: 'row',
+ justifyContent: 'center',
+ alignItems: 'stretch'
+ }
+});
diff --git a/src/components/slider/GradientSlider.tsx b/src/components/slider/GradientSlider.tsx
index ff4d47bb58..12cbec3241 100644
--- a/src/components/slider/GradientSlider.tsx
+++ b/src/components/slider/GradientSlider.tsx
@@ -1,18 +1,18 @@
import _ from 'lodash';
-import React, {useCallback, useEffect, useState, useMemo} from 'react';
+import React, {useCallback, useEffect, useState, useMemo, useContext} from 'react';
import {asBaseComponent, forwardRef, ForwardRefInjectedProps} from '../../commons/new';
import {ComponentStatics} from '../../typings/common';
import {Colors} from '../../style';
import {Slider as NewSlider} from '../../incubator';
import Gradient from '../gradient';
+import AnimatedGradient from '../gradient/AnimatedGradient';
import {GradientSliderProps, GradientSliderTypes, HSLA} from './types';
import Slider from './index';
-import {SliderContextProps} from './context/SliderContext';
-import asSliderGroupChild from './context/asSliderGroupChild';
+import {ColorPickerContext} from '../colorPicker/context/ColorPickerContext';
+import {isSharedValue, useDerivedValue} from 'react-native-reanimated';
+import tinycolor from 'tinycolor2';
-type GradientSliderComponentProps = {
- sliderContext: SliderContextProps;
-} & GradientSliderProps;
+type GradientSliderComponentProps = GradientSliderProps;
type Props = GradientSliderComponentProps & ForwardRefInjectedProps;
@@ -26,7 +26,6 @@ const GradientSlider = (props: Props) => {
type = GradientSliderTypes.DEFAULT,
gradientSteps = 120,
color: propsColors = Colors.$backgroundPrimaryHeavy,
- sliderContext,
onValueChange: _onValueChange,
migrate,
containerStyle,
@@ -40,40 +39,67 @@ const GradientSlider = (props: Props) => {
return _.isString(propsColors) ? Colors.getHSL(propsColors) : propsColors;
}, [propsColors]);
const [color, setColor] = useState(initialColor);
+
+ let colorPickerContext = useContext(ColorPickerContext);
+ //TODO: Remove after migration is done.
+ if (!migrate) {
+ colorPickerContext = null;
+ }
useEffect(() => {
+ console.log(`Nitzan - dfgsdfgjsfgjh`, )
setColor(initialColor);
}, [initialColor]);
- const getColor = useCallback(() => {
- return color || sliderContext.value;
- }, [color, sliderContext.value]);
-
+ const animatedHueColor = useDerivedValue(() => {
+ if (colorPickerContext) {
+ return {
+ h: colorPickerContext.value.value.h,
+ s: 1,
+ l: 0.5,
+ a: 1
+ };
+ }
+ return {};
+ });
const hueColor = useMemo(() => {
- const color = getColor();
return {
h: color.h,
s: 1,
l: 0.5,
a: 1
};
- }, [getColor]);
+ }, [color]);
const renderDefaultGradient = useCallback(() => {
- return ;
- }, [getColor, gradientSteps]);
+ if (colorPickerContext) {
+ const {value} = colorPickerContext;
+ return ;
+ }
+ return ;
+ }, [gradientSteps, colorPickerContext, color]);
const renderHueGradient = useCallback(() => {
return ;
}, [gradientSteps]);
const renderLightnessGradient = useCallback(() => {
+ if (colorPickerContext && isSharedValue(animatedHueColor)) {
+ return (
+
+ );
+ }
return ;
- }, [hueColor, gradientSteps]);
+ }, [hueColor, gradientSteps, animatedHueColor, colorPickerContext]);
const renderSaturationGradient = useCallback(() => {
+ if (colorPickerContext && isSharedValue(animatedHueColor)) {
+ return (
+
+ );
+ }
return ;
- }, [hueColor, gradientSteps]);
+ }, [hueColor, gradientSteps, animatedHueColor, colorPickerContext]);
const onValueChange = useCallback((value: string, alpha: number) => {
// alpha returns for type.DEFAULT
@@ -82,67 +108,59 @@ const GradientSlider = (props: Props) => {
[_onValueChange]);
const updateColor = useCallback((color: HSLA) => {
- if (!_.isEmpty(sliderContext)) {
- sliderContext.setValue?.(color);
- } else {
- setColor(color);
- const hex = Colors.getHexString(color);
- onValueChange(hex, color.a);
- }
+ setColor(color);
+ const hex = Colors.getHexString(color);
+ onValueChange(hex, color.a);
},
- [sliderContext, onValueChange]);
+ [onValueChange]);
const reset = useCallback(() => {
updateColor(initialColor);
}, [initialColor, updateColor]);
const updateAlpha = useCallback((a: number) => {
- const color = getColor();
updateColor({...color, a});
},
- [getColor, updateColor]);
+ [updateColor, color]);
const updateHue = useCallback((h: number) => {
- const color = getColor();
updateColor({...color, h});
},
- [getColor, updateColor]);
+ [color, updateColor]);
const updateLightness = useCallback((l: number) => {
- const color = getColor();
updateColor({...color, l});
},
- [getColor, updateColor]);
+ [color, updateColor]);
const updateSaturation = useCallback((s: number) => {
- const color = getColor();
updateColor({...color, s});
},
- [getColor, updateColor]);
+ [color, updateColor]);
let step = 0.01;
let maximumValue = 1;
- let value = color.a;
+ let value = colorPickerContext ? colorPickerContext.value.value.a : color.a;
let renderTrack = renderDefaultGradient;
- let sliderOnValueChange = updateAlpha;
+ let sliderOnValueChange = colorPickerContext ? colorPickerContext.updateAlpha : updateAlpha;
switch (type) {
case GradientSliderTypes.HUE:
step = 1;
maximumValue = 359;
- value = initialColor.h;
+ value = colorPickerContext ? colorPickerContext.value.value.h : initialColor.h;
renderTrack = renderHueGradient;
- sliderOnValueChange = updateHue;
+ sliderOnValueChange = colorPickerContext ? colorPickerContext.updateHue : updateHue;
break;
case GradientSliderTypes.LIGHTNESS:
- value = initialColor.l;
+ value = colorPickerContext ? colorPickerContext.value.value.l : initialColor.l;
renderTrack = renderLightnessGradient;
- sliderOnValueChange = updateLightness;
+ sliderOnValueChange = colorPickerContext ? colorPickerContext.updateLightness : updateLightness;
break;
case GradientSliderTypes.SATURATION:
- value = initialColor.s;
+ value = colorPickerContext ? colorPickerContext.value.value.s : initialColor.s;
renderTrack = renderSaturationGradient;
- sliderOnValueChange = updateSaturation;
+ sliderOnValueChange = colorPickerContext ? colorPickerContext.updateSaturation : updateSaturation;
break;
default:
break;
@@ -153,7 +171,7 @@ const GradientSlider = (props: Props) => {
(props: Props) => {
disabled={disabled}
accessible={accessible}
useRange={false}
+ useWorkletHandlers={!!colorPickerContext}
/>
);
};
@@ -171,7 +190,4 @@ const GradientSlider = (props: Props) => {
GradientSlider.displayName = 'GradientSlider';
GradientSlider.types = GradientSliderTypes;
// @ts-expect-error
-export default asBaseComponent>(
- // @ts-expect-error
- forwardRef(asSliderGroupChild(forwardRef(GradientSlider)))
-);
+export default asBaseComponent>(forwardRef(GradientSlider));
diff --git a/src/incubator/Slider/index.tsx b/src/incubator/Slider/index.tsx
index 562dab4bca..85a8db941e 100644
--- a/src/incubator/Slider/index.tsx
+++ b/src/incubator/Slider/index.tsx
@@ -1,5 +1,5 @@
import _ from 'lodash';
-import React, {ReactElement, useImperativeHandle, useCallback, useMemo, useEffect} from 'react';
+import React, {ReactElement, useContext, useImperativeHandle, useCallback, useMemo, useEffect} from 'react';
import {StyleSheet, AccessibilityRole, StyleProp, ViewStyle, GestureResponderEvent, LayoutChangeEvent, ViewProps, AccessibilityProps} from 'react-native';
import {useSharedValue, useAnimatedStyle, runOnJS, useAnimatedReaction, withTiming} from 'react-native-reanimated';
import {forwardRef, ForwardRefInjectedProps, Constants} from '../../commons/new';
@@ -139,6 +139,8 @@ export interface SliderProps extends AccessibilityProps {
* Whether to use the new Slider implementation using Reanimated
*/
migrate?: boolean;
+
+ useWorkletHandlers?: boolean;
}
type Props = SliderProps & ForwardRefInjectedProps;
@@ -188,9 +190,11 @@ const Slider = React.memo((props: Props) => {
useGap = true,
accessible = true,
testID,
- enableThumbShadow = true
+ enableThumbShadow = true,
+ useWorkletHandlers
} = themeProps;
+
const accessibilityProps = useMemo(() => {
if (accessible) {
return {
@@ -284,8 +288,16 @@ const Slider = React.memo((props: Props) => {
minimumValue,
maximumValue,
stepXValue.value);
+ if (useWorkletHandlers) {
+ onRangeChange?.({min: value, max: maxValue});
+ return;
+ }
runOnJS(onRangeChangeThrottled)(value, maxValue);
} else if (prevOffset) { // don't invoke onChange when setting the slider
+ if (useWorkletHandlers) {
+ onValueChange?.(value);
+ return;
+ }
runOnJS(onValueChangeThrottled)(value);
}
}
@@ -301,6 +313,10 @@ const Slider = React.memo((props: Props) => {
minimumValue,
maximumValue,
stepXValue.value);
+ if (useWorkletHandlers) {
+ onRangeChange?.({min: minValue, max: maxValue});
+ return;
+ }
runOnJS(onRangeChangeThrottled)(minValue, maxValue);
});
diff --git a/src/index.ts b/src/index.ts
index 6d8e2cfee8..61cde7ab42 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -189,7 +189,6 @@ export {
WheelPickerItemProps,
WheelPickerAlign
} from './components/WheelPicker';
-
/* ===== TestKit ===== */
// export {default as TextTestKit} from './components/text/Text.driver';
// export {default as ImageTestKit} from './components/image/Image.driver';