UNPKG

@wordpress/components

Version:
279 lines (249 loc) 9.7 kB
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