UNPKG

@wordpress/components

Version:
264 lines (257 loc) 9.92 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _reactNative = require("react-native"); var _reactNativeVideo = _interopRequireDefault(require("react-native-video")); var _reactNativeBridge = require("@wordpress/react-native-bridge"); var _i18n = require("@wordpress/i18n"); var _element = require("@wordpress/element"); var _compose = require("@wordpress/compose"); var _focalPoint = _interopRequireDefault(require("./focal-point")); var _tooltip = _interopRequireDefault(require("./tooltip")); var _style = _interopRequireDefault(require("./style.scss")); var _utils = require("./utils"); var _math = require("../utils/math"); var _image = _interopRequireDefault(require("../mobile/image")); var _unitControl = _interopRequireDefault(require("../unit-control")); var _jsxRuntime = require("react/jsx-runtime"); /** * External dependencies */ /** * WordPress dependencies */ /** * Internal dependencies */ const MIN_POSITION_VALUE = 0; const MAX_POSITION_VALUE = 100; const FOCAL_POINT_UNITS = [{ default: 50, label: '%', value: '%' }]; function FocalPointPicker(props) { const { focalPoint, onChange, shouldEnableBottomSheetScroll, url } = props; const isVideo = (0, _utils.isVideoType)(url); const [containerSize, setContainerSize] = (0, _element.useState)(null); const [sliderKey, setSliderKey] = (0, _element.useState)(0); const [displayPlaceholder, setDisplayPlaceholder] = (0, _element.useState)(true); const [videoNaturalSize, setVideoNaturalSize] = (0, _element.useState)(null); const [tooltipVisible, setTooltipVisible] = (0, _element.useState)(false); const locationPageOffsetX = (0, _element.useRef)(); const locationPageOffsetY = (0, _element.useRef)(); const videoRef = (0, _element.useRef)(null); (0, _element.useEffect)(() => { (0, _reactNativeBridge.requestFocalPointPickerTooltipShown)(tooltipShown => { if (!tooltipShown) { setTooltipVisible(true); (0, _reactNativeBridge.setFocalPointPickerTooltipShown)(true); } }); }, []); // Animated coordinates for drag handle. const pan = (0, _element.useRef)(new _reactNative.Animated.ValueXY()).current; /** * Set drag handle position anytime focal point coordinates change. * E.g. initial render, dragging range sliders. */ (0, _element.useEffect)(() => { if (containerSize) { pan.setValue({ x: focalPoint.x * containerSize.width, y: focalPoint.y * containerSize.height }); } }, [focalPoint, containerSize, pan]); // Pan responder to manage drag handle interactivity. const panResponder = (0, _element.useMemo)(() => _reactNative.PanResponder.create({ onStartShouldSetPanResponder: () => true, onStartShouldSetPanResponderCapture: () => true, onMoveShouldSetPanResponder: () => true, onMoveShouldSetPanResponderCapture: () => true, onPanResponderGrant: event => { shouldEnableBottomSheetScroll(false); const { locationX: x, locationY: y, pageX, pageY } = event.nativeEvent; locationPageOffsetX.current = pageX - x; locationPageOffsetY.current = pageY - y; pan.setValue({ x, y }); // Set cursor to tap location. pan.extractOffset(); // Set offset to current value. }, // Move cursor to match delta drag. onPanResponderMove: _reactNative.Animated.event([null, { dx: pan.x, dy: pan.y }], { useNativeDriver: false }), onPanResponderRelease: event => { shouldEnableBottomSheetScroll(true); pan.flattenOffset(); // Flatten offset into value. const { pageX, pageY } = event.nativeEvent; // Ideally, x and y below are merely locationX and locationY from the // nativeEvent. However, we are required to compute these relative // coordinates to workaround a bug affecting Android's PanResponder. // Specifically, dragging the handle outside the bounds of the image // results in inaccurate locationX and locationY coordinates to be // reported. https://github.com/facebook/react-native/issues/15290#issuecomment-435494944 const x = pageX - locationPageOffsetX.current; const y = pageY - locationPageOffsetY.current; onChange({ x: (0, _math.clamp)(x / containerSize?.width, 0, 1).toFixed(2), y: (0, _math.clamp)(y / containerSize?.height, 0, 1).toFixed(2) }); // Slider (child of RangeCell) is uncontrolled, so we must increment a // key to re-mount and sync the pan gesture values to the sliders // https://github.com/callstack/react-native-slider/tree/v3.0.3#value setSliderKey(prevState => prevState + 1); } }), [containerSize, pan, onChange, shouldEnableBottomSheetScroll]); const mediaBackground = (0, _compose.usePreferredColorSchemeStyle)(_style.default.mediaBackground, _style.default.mediaBackgroundDark); const imagePreviewStyles = [displayPlaceholder && _style.default.mediaPlaceholder, _style.default.image]; const videoPreviewStyles = [{ aspectRatio: videoNaturalSize && videoNaturalSize.width / videoNaturalSize.height, // Hide Video component since it has black background while loading the source opacity: displayPlaceholder ? 0 : 1 }, _style.default.video, displayPlaceholder && _style.default.mediaPlaceholder]; const focalPointGroupStyles = [_style.default.focalPointGroup, { transform: [{ translateX: pan.x.interpolate({ inputRange: [0, containerSize?.width || 0], outputRange: [0, containerSize?.width || 0], extrapolate: 'clamp' }) }, { translateY: pan.y.interpolate({ inputRange: [0, containerSize?.height || 0], outputRange: [0, containerSize?.height || 0], extrapolate: 'clamp' }) }] }]; const FOCAL_POINT_SIZE = 50; const focalPointStyles = _reactNative.StyleSheet.flatten([_style.default.focalPoint, { height: FOCAL_POINT_SIZE, marginLeft: -(FOCAL_POINT_SIZE / 2), marginTop: -(FOCAL_POINT_SIZE / 2), width: FOCAL_POINT_SIZE }]); const onTooltipPress = () => setTooltipVisible(false); const onMediaLayout = event => { const { height, width } = event.nativeEvent.layout; if (width !== 0 && height !== 0 && (containerSize?.width !== width || containerSize?.height !== height)) { setContainerSize({ width, height }); } }; const onImageDataLoad = () => setDisplayPlaceholder(false); const onVideoLoad = event => { const { height, width } = event.naturalSize; setVideoNaturalSize({ height, width }); setDisplayPlaceholder(false); // Avoid invisible, paused video on Android, presumably related to // https://github.com/react-native-video/react-native-video/issues/1979 videoRef?.current.seek(0); }; const onXCoordinateChange = x => onChange({ x: (x / 100).toFixed(2) }); const onYCoordinateChange = y => onChange({ y: (y / 100).toFixed(2) }); return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, { style: _style.default.container, children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_tooltip.default, { onPress: onTooltipPress, visible: tooltipVisible, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, { style: [_style.default.media, mediaBackground], children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, { ...panResponder.panHandlers, onLayout: onMediaLayout, style: _style.default.mediaContainer, children: [!isVideo && /*#__PURE__*/(0, _jsxRuntime.jsx)(_image.default, { editButton: false, highlightSelected: false, isSelected: !displayPlaceholder, height: "100%", url: url, style: imagePreviewStyles, onImageDataLoad: onImageDataLoad }), isVideo && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeVideo.default, { muted: true, paused: true, disableFocus: true, onLoad: onVideoLoad, ref: videoRef, resizeMode: "contain", source: { uri: url }, style: videoPreviewStyles }), !displayPlaceholder && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Animated.View, { pointerEvents: "none", style: focalPointGroupStyles, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_tooltip.default.Label, { text: (0, _i18n.__)('Drag to adjust focal point'), yOffset: -(FOCAL_POINT_SIZE / 2) }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_focalPoint.default, { height: focalPointStyles.height, style: focalPointStyles, testID: "focal-point-picker-handle", width: focalPointStyles.width })] })] }) }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_unitControl.default, { label: (0, _i18n.__)('X-Axis Position'), max: MAX_POSITION_VALUE, min: MIN_POSITION_VALUE, onChange: onXCoordinateChange, unit: "%", units: FOCAL_POINT_UNITS, value: Math.round(focalPoint.x * 100) }, `xAxis-${sliderKey}`), /*#__PURE__*/(0, _jsxRuntime.jsx)(_unitControl.default, { label: (0, _i18n.__)('Y-Axis Position'), max: MAX_POSITION_VALUE, min: MIN_POSITION_VALUE, onChange: onYCoordinateChange, unit: "%", units: FOCAL_POINT_UNITS, value: Math.round(focalPoint.y * 100) }, `yAxis-${sliderKey}`)] }) }); } var _default = exports.default = FocalPointPicker; //# sourceMappingURL=index.native.js.map