UNPKG

@wordpress/components

Version:
283 lines (246 loc) 9.89 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _element = require("@wordpress/element"); var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _reactNative = require("react-native"); var _reactNativeVideo = _interopRequireDefault(require("react-native-video")); var _lodash = require("lodash"); var _reactNativeBridge = require("@wordpress/react-native-bridge"); var _i18n = require("@wordpress/i18n"); var _components = require("@wordpress/components"); 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"); /** * 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) { var _styles$focalPoint, _styles$focalPoint2; 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); let locationPageOffsetX = (0, _element.useRef)().current; let locationPageOffsetY = (0, _element.useRef)().current; 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 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 = pageX - x; locationPageOffsetY = 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 }]), 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://git.io/JtWmi const x = pageX - locationPageOffsetX; const y = pageY - locationPageOffsetY; onChange({ x: (0, _lodash.clamp)(x / (containerSize === null || containerSize === void 0 ? void 0 : containerSize.width), 0, 1).toFixed(2), y: (0, _lodash.clamp)(y / (containerSize === null || containerSize === void 0 ? void 0 : 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://git.io/JTe4A setSliderKey(prevState => prevState + 1); } }), [containerSize]); 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 === null || containerSize === void 0 ? void 0 : containerSize.width) || 0], outputRange: [0, (containerSize === null || containerSize === void 0 ? void 0 : containerSize.width) || 0], extrapolate: 'clamp' }) }, { translateY: pan.y.interpolate({ inputRange: [0, (containerSize === null || containerSize === void 0 ? void 0 : containerSize.height) || 0], outputRange: [0, (containerSize === null || containerSize === void 0 ? void 0 : containerSize.height) || 0], extrapolate: 'clamp' }) }] }]; const FOCAL_POINT_SIZE = 50; const focalPointStyles = [_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 === null || containerSize === void 0 ? void 0 : containerSize.width) !== width || (containerSize === null || containerSize === void 0 ? void 0 : 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://git.io/Jt6Dr videoRef === null || videoRef === void 0 ? void 0 : videoRef.current.seek(0); }; const onXCoordinateChange = x => onChange({ x: (x / 100).toFixed(2) }); const onYCoordinateChange = y => onChange({ y: (y / 100).toFixed(2) }); return (0, _element.createElement)(_reactNative.View, { style: _style.default.container }, (0, _element.createElement)(_tooltip.default, { onPress: onTooltipPress, visible: tooltipVisible }, (0, _element.createElement)(_reactNative.View, { style: [_style.default.media, mediaBackground] }, (0, _element.createElement)(_reactNative.View, (0, _extends2.default)({}, panResponder.panHandlers, { onLayout: onMediaLayout, style: _style.default.mediaContainer }), !isVideo && (0, _element.createElement)(_components.Image, { editButton: false, highlightSelected: false, isSelected: !displayPlaceholder, height: "100%", url: url, style: imagePreviewStyles, onImageDataLoad: onImageDataLoad }), isVideo && (0, _element.createElement)(_reactNativeVideo.default, { muted: true, paused: true, disableFocus: true, onLoad: onVideoLoad, ref: videoRef, resizeMode: "contain", source: { uri: url }, style: videoPreviewStyles }), !displayPlaceholder && (0, _element.createElement)(_reactNative.Animated.View, { pointerEvents: "none", style: focalPointGroupStyles }, (0, _element.createElement)(_tooltip.default.Label, { text: (0, _i18n.__)('Drag to adjust focal point'), yOffset: -(FOCAL_POINT_SIZE / 2) }), (0, _element.createElement)(_focalPoint.default, { height: (_styles$focalPoint = _style.default.focalPoint) === null || _styles$focalPoint === void 0 ? void 0 : _styles$focalPoint.height, style: focalPointStyles, width: (_styles$focalPoint2 = _style.default.focalPoint) === null || _styles$focalPoint2 === void 0 ? void 0 : _styles$focalPoint2.width })))), (0, _element.createElement)(_components.UnitControl, { key: `xAxis-${sliderKey}`, 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) }), (0, _element.createElement)(_components.UnitControl, { key: `yAxis-${sliderKey}`, 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) }))); } var _default = FocalPointPicker; exports.default = _default; //# sourceMappingURL=index.native.js.map