@wordpress/components
Version:
UI components for WordPress.
234 lines (209 loc) • 7.69 kB
JavaScript
import { createElement } from "@wordpress/element";
/**
* External dependencies
*/
import { ScrollView, TouchableWithoutFeedback, View, Animated, Easing, Dimensions, Platform, Text } from 'react-native';
import { map, uniq } from 'lodash';
/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { useRef, useEffect, useState } from '@wordpress/element';
import { usePreferredColorSchemeStyle } from '@wordpress/compose';
/**
* Internal dependencies
*/
import styles from './style.scss';
import ColorIndicator from '../color-indicator';
import { colorsUtils } from '../mobile/color-settings/utils';
const ANIMATION_DURATION = 200;
let contentWidth = 0;
let scrollPosition = 0;
let customIndicatorWidth = 0;
function ColorPalette({
setColor,
activeColor,
isGradientColor,
defaultSettings,
currentSegment,
onCustomPress,
shouldEnableBottomSheetScroll,
shouldShowCustomIndicatorOption = true,
shouldShowCustomLabel = true,
shouldShowCustomVerticalSeparator = true,
customColorIndicatorStyles,
customIndicatorWrapperStyles
}) {
const customSwatchGradients = ['linear-gradient(120deg, rgba(255,0,0,.8) 0%, rgba(255,255,255,1) 70.71%)', 'linear-gradient(240deg, rgba(0,255,0,.8) 0%, rgba(0,255,0,0) 70.71%)', 'linear-gradient(360deg, rgba(0,0,255,.8) 0%, rgba(0,0,255,0) 70.71%)'];
const isCustomGradientColor = isGradientColor && isSelectedCustom();
const [shouldShowCustomIndicator, setShouldShowCustomIndicator] = useState(shouldShowCustomIndicatorOption && (!isGradientSegment || isCustomGradientColor));
const scrollViewRef = useRef();
const isIOS = Platform.OS === 'ios';
const isGradientSegment = currentSegment === colorsUtils.segments[1];
const scale = useRef(new Animated.Value(1)).current;
const opacity = useRef(new Animated.Value(1)).current;
const defaultColors = uniq(map(defaultSettings.colors, 'color'));
const defaultGradientColors = uniq(map(defaultSettings.gradients, 'gradient'));
const colors = isGradientSegment ? defaultGradientColors : defaultColors;
const customIndicatorColor = isGradientSegment ? activeColor : customSwatchGradients;
useEffect(() => {
setShouldShowCustomIndicator(shouldShowCustomIndicatorOption && (!isGradientSegment || isCustomGradientColor));
}, [shouldShowCustomIndicatorOption, isGradientSegment, isCustomGradientColor]);
const accessibilityHint = isGradientSegment ? __('Navigates to customize the gradient') : __('Navigates to custom color picker');
const customText = __('Custom');
useEffect(() => {
if (scrollViewRef.current) {
if (isSelectedCustom()) {
scrollViewRef.current.scrollToEnd();
} else {
scrollViewRef.current.scrollTo({
x: 0,
y: 0
});
}
}
}, [currentSegment]);
function isSelectedCustom() {
const isWithinColors = activeColor && colors && colors.includes(activeColor);
if (activeColor) {
if (isGradientSegment) {
return isGradientColor && !isWithinColors;
}
return !isGradientColor && !isWithinColors;
}
return false;
}
function isSelected(color) {
return !isSelectedCustom() && activeColor === color;
}
function timingAnimation(property, toValue) {
return Animated.timing(property, {
toValue,
duration: ANIMATION_DURATION,
easing: Easing.ease,
useNativeDriver: true
});
}
function performAnimation(color) {
if (!isSelected(color)) {
opacity.setValue(0);
}
Animated.parallel([timingAnimation(scale, 2), timingAnimation(opacity, 1)]).start(() => {
opacity.setValue(1);
scale.setValue(1);
});
}
const scaleInterpolation = scale.interpolate({
inputRange: [1, 1.5, 2],
outputRange: [1, 0.7, 1]
});
function deselectCustomGradient() {
const {
width
} = Dimensions.get('window');
const isVisible = contentWidth - scrollPosition - customIndicatorWidth < width;
if (isCustomGradientColor) {
if (!isIOS) {
// Scroll position on Android doesn't adjust automatically when removing the last item from the horizontal list.
// https://github.com/facebook/react-native/issues/27504
// Workaround: Force the scroll when deselecting custom gradient color and when custom indicator is visible on layout.
if (isCustomGradientColor && isVisible && scrollViewRef.current) {
scrollViewRef.current.scrollTo({
x: scrollPosition - customIndicatorWidth
});
}
}
}
}
function onColorPress(color) {
deselectCustomGradient();
performAnimation(color);
setColor(color);
}
function onContentSizeChange(width) {
contentWidth = width;
if (isSelectedCustom() && scrollViewRef.current) {
scrollViewRef.current.scrollToEnd({
animated: !isIOS
});
}
}
function onCustomIndicatorLayout({
nativeEvent
}) {
const {
width
} = nativeEvent.layout;
if (width !== customIndicatorWidth) {
customIndicatorWidth = width;
}
}
function onScroll({
nativeEvent
}) {
scrollPosition = nativeEvent.contentOffset.x;
}
const verticalSeparatorStyle = usePreferredColorSchemeStyle(styles.verticalSeparator, styles.verticalSeparatorDark);
const customTextStyle = usePreferredColorSchemeStyle([styles.customText, !isIOS && styles.customTextAndroid], styles.customTextDark);
const customIndicatorWrapperStyle = [styles.customIndicatorWrapper, customIndicatorWrapperStyles];
return createElement(ScrollView, {
contentContainerStyle: styles.contentContainer,
style: styles.container,
horizontal: true,
showsHorizontalScrollIndicator: false,
keyboardShouldPersistTaps: "always",
disableScrollViewPanResponder: true,
scrollEventThrottle: 16,
onScroll: onScroll,
onContentSizeChange: onContentSizeChange,
onScrollBeginDrag: () => shouldEnableBottomSheetScroll(false),
onScrollEndDrag: () => shouldEnableBottomSheetScroll(true),
ref: scrollViewRef
}, colors.map(color => {
const scaleValue = isSelected(color) ? scaleInterpolation : 1;
return createElement(View, {
key: `${color}-${isSelected(color)}`
}, createElement(TouchableWithoutFeedback, {
onPress: () => onColorPress(color),
accessibilityRole: 'button',
accessibilityState: {
selected: isSelected(color)
},
accessibilityHint: color
}, createElement(Animated.View, {
style: {
transform: [{
scale: scaleValue
}]
}
}, createElement(ColorIndicator, {
color: color,
isSelected: isSelected(color),
opacity: opacity,
style: [styles.colorIndicator, customColorIndicatorStyles]
}))));
}), shouldShowCustomIndicator && createElement(View, {
style: customIndicatorWrapperStyle,
onLayout: onCustomIndicatorLayout
}, shouldShowCustomVerticalSeparator && createElement(View, {
style: verticalSeparatorStyle
}), createElement(TouchableWithoutFeedback, {
onPress: onCustomPress,
accessibilityRole: 'button',
accessibilityState: {
selected: isSelectedCustom()
},
accessibilityHint: accessibilityHint
}, createElement(View, {
style: customIndicatorWrapperStyle
}, createElement(ColorIndicator, {
withCustomPicker: !isGradientSegment,
color: customIndicatorColor,
isSelected: isSelectedCustom(),
style: [styles.colorIndicator, customColorIndicatorStyles]
}), shouldShowCustomLabel && createElement(Text, {
style: customTextStyle
}, isIOS ? customText : customText.toUpperCase())))));
}
export default ColorPalette;
//# sourceMappingURL=index.native.js.map