@wordpress/components
Version:
UI components for WordPress.
279 lines (249 loc) • 9.7 kB
JavaScript
import { createElement, Fragment } from "@wordpress/element";
/**
* External dependencies
*/
import { ScrollView, TouchableWithoutFeedback, View, Animated, Easing, Dimensions, Platform, Text } from 'react-native';
/**
* WordPress dependencies
*/
import { __, sprintf } from '@wordpress/i18n';
import { useRef, useEffect } 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(_ref) {
var _defaultSettings$colo, _defaultSettings$allC, _defaultSettings$grad;
let {
enableCustomColor = true,
setColor,
activeColor,
isGradientColor,
defaultSettings,
currentSegment,
onCustomPress,
shouldEnableBottomSheetScroll,
shouldShowCustomIndicatorOption = true,
shouldShowCustomLabel = true,
shouldShowCustomVerticalSeparator = true,
customColorIndicatorStyles,
customIndicatorWrapperStyles,
label
} = _ref;
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 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 = [...new Set(((_defaultSettings$colo = defaultSettings.colors) !== null && _defaultSettings$colo !== void 0 ? _defaultSettings$colo : []).map(_ref2 => {
let {
color
} = _ref2;
return color;
}))];
const mergedColors = [...new Set(((_defaultSettings$allC = defaultSettings.allColors) !== null && _defaultSettings$allC !== void 0 ? _defaultSettings$allC : []).map(_ref3 => {
let {
color
} = _ref3;
return color;
}))];
const defaultGradientColors = [...new Set(((_defaultSettings$grad = defaultSettings.gradients) !== null && _defaultSettings$grad !== void 0 ? _defaultSettings$grad : []).map(_ref4 => {
let {
gradient
} = _ref4;
return gradient;
}))];
const colors = isGradientSegment ? defaultGradientColors : defaultColors;
const customIndicatorColor = isGradientSegment ? activeColor : customSwatchGradients;
const isCustomGradientColor = isGradientColor && isSelectedCustom();
const shouldShowCustomIndicator = enableCustomColor && 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()) {
scrollToEndWithDelay();
} else {
scrollViewRef.current.scrollTo({
x: 0,
y: 0
});
}
} // Temporarily disabling exhuastive-deps until the component can be refactored and updated safely.
// Please see https://github.com/WordPress/gutenberg/pull/41253 for discussion and details.
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [currentSegment]);
function isSelectedCustom() {
const isWithinColors = activeColor && mergedColors && mergedColors.includes(activeColor);
if (enableCustomColor && 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 getColorGradientName(value) {
var _defaultSettings$grad2, _defaultSettings$allC2;
const fallbackName = sprintf(
/* translators: %s: the hex color value */
__('Unlabeled color. %s'), value);
const foundColorName = isGradientSegment ? (_defaultSettings$grad2 = defaultSettings.gradients) === null || _defaultSettings$grad2 === void 0 ? void 0 : _defaultSettings$grad2.find(gradient => gradient.gradient === value) : (_defaultSettings$allC2 = defaultSettings.allColors) === null || _defaultSettings$allC2 === void 0 ? void 0 : _defaultSettings$allC2.find(color => color.color === value);
return foundColorName ? foundColorName === null || foundColorName === void 0 ? void 0 : foundColorName.name : fallbackName;
}
function onColorPress(color) {
deselectCustomGradient();
performAnimation(color);
setColor(color);
}
function onContentSizeChange(width) {
contentWidth = width;
if (isSelectedCustom() && scrollViewRef.current) {
scrollToEndWithDelay();
}
}
function scrollToEndWithDelay() {
const delayedScroll = setTimeout(() => {
scrollViewRef.current.scrollToEnd();
}, ANIMATION_DURATION);
return () => {
clearTimeout(delayedScroll);
};
}
function onCustomIndicatorLayout(_ref5) {
let {
nativeEvent
} = _ref5;
const {
width
} = nativeEvent.layout;
if (width !== customIndicatorWidth) {
customIndicatorWidth = width;
}
}
function onScroll(_ref6) {
let {
nativeEvent
} = _ref6;
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(Fragment, null, label && createElement(Text, {
accessibilityRole: "header",
style: styles.headerText
}, label), createElement(ScrollView, {
contentContainerStyle: styles.contentContainer,
horizontal: true,
showsHorizontalScrollIndicator: false,
keyboardShouldPersistTaps: "always",
disableScrollViewPanResponder: true,
scrollEventThrottle: 16,
onScroll: onScroll,
onContentSizeChange: onContentSizeChange,
onScrollBeginDrag: () => shouldEnableBottomSheetScroll(false),
onScrollEndDrag: () => shouldEnableBottomSheetScroll(true),
ref: scrollViewRef,
testID: `color-palette${label ? '-' + label : ''}`
}, colors.map(color => {
const scaleValue = isSelected(color) ? scaleInterpolation : 1;
const colorName = getColorGradientName(color);
return createElement(View, {
key: `${color}-${isSelected(color)}`
}, createElement(TouchableWithoutFeedback, {
onPress: () => onColorPress(color),
accessibilityRole: 'button',
accessibilityState: {
selected: isSelected(color)
},
accessibilityHint: color,
accessibilityLabel: colorName,
testID: 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