Object(classCallCheck["a" /* default */])(this, FocalPointPicker);
_this = _super.apply(this, arguments);
_this.containerRef = Object(external_wp_element_["createRef"])();
_this.mediaRef = Object(external_wp_element_["createRef"])();
_this.handleOnClick = _this.handleOnClick.bind(Object(assertThisInitialized["a" /* default */])(_this));
_this.handleOnMouseUp = _this.handleOnMouseUp.bind(Object(assertThisInitialized["a" /* default */])(_this));
_this.handleOnKeyDown = _this.handleOnKeyDown.bind(Object(assertThisInitialized["a" /* default */])(_this));
_this.onMouseMove = _this.onMouseMove.bind(Object(assertThisInitialized["a" /* default */])(_this));
_this.updateBounds = _this.updateBounds.bind(Object(assertThisInitialized["a" /* default */])(_this));
_this.updateValue = _this.updateValue.bind(Object(assertThisInitialized["a" /* default */])(_this));
Object(createClass["a" /* default */])(FocalPointPicker, [{
key: "componentDidMount",
value: function componentDidMount() {
document.addEventListener('mouseup', this.handleOnMouseUp);
window.addEventListener('resize', this.updateBounds);
* Set initial bound values.
* This is necessary for Safari:
* https://github.com/WordPress/gutenberg/issues/25814
key: "componentDidUpdate",
value: function componentDidUpdate(prevProps) {
if (prevProps.url !== this.props.url) {
* Handles cases where the incoming value changes.
* An example is the values resetting based on an UNDO action.
if (this.props.value.x !== this.state.percentages.x || this.props.value.y !== this.state.percentages.y) {
percentages: this.props.value
key: "componentWillUnmount",
value: function componentWillUnmount() {
document.removeEventListener('mouseup', this.handleOnMouseUp);
window.removeEventListener('resize', this.updateBounds);
value: function calculateBounds() {
var bounds = INITIAL_BOUNDS;
if (!this.mediaRef.current) {
} // Prevent division by zero when updateBounds runs in componentDidMount
if (this.mediaRef.current.clientWidth === 0 || this.mediaRef.current.clientHeight === 0) {
width: this.mediaRef.current.clientWidth,
height: this.mediaRef.current.clientHeight
var pickerDimensions = this.pickerDimensions();
var widthRatio = pickerDimensions.width / dimensions.width;
var heightRatio = pickerDimensions.height / dimensions.height;
if (heightRatio >= widthRatio) {
bounds.width = bounds.right = pickerDimensions.width;
bounds.height = dimensions.height * widthRatio;
bounds.top = (pickerDimensions.height - bounds.height) / 2;
bounds.bottom = bounds.top + bounds.height;
bounds.height = bounds.bottom = pickerDimensions.height;
bounds.width = dimensions.width * heightRatio;
bounds.left = (pickerDimensions.width - bounds.width) / 2;
bounds.right = bounds.left + bounds.width;
value: function updateValue() {
var nextValue = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var onChange = this.props.onChange;
x: parseFloat(x).toFixed(2),
y: parseFloat(y).toFixed(2)
percentages: nextPercentage
onChange(nextPercentage);
value: function updateBounds() {
bounds: this.calculateBounds()
value: function handleOnClick(event) {
_this2.onMouseMove(event);
value: function handleOnMouseUp() {
value: function handleOnKeyDown(event) {
var keyCode = event.keyCode,
shiftKey = event.shiftKey;
if (![external_wp_keycodes_["UP"], external_wp_keycodes_["DOWN"], external_wp_keycodes_["LEFT"], external_wp_keycodes_["RIGHT"]].includes(keyCode)) return;
var _this$state$percentag = this.state.percentages,
x = _this$state$percentag.x,
y = _this$state$percentag.y;
event.preventDefault(); // Normalizing values for incrementing/decrementing based on arrow keys
var nextX = parseFloat(x);
var nextY = parseFloat(y);
var step = shiftKey ? 0.1 : 0.01;
case external_wp_keycodes_["UP"]:
case external_wp_keycodes_["DOWN"]:
case external_wp_keycodes_["LEFT"]:
case external_wp_keycodes_["RIGHT"]:
nextX = roundClamp(nextX, 0, 1, step);
nextY = roundClamp(nextY, 0, 1, step);
this.updateValue(percentages);
value: function onMouseMove(event) {
var _this$state = this.state,
isDragging = _this$state.isDragging,
bounds = _this$state.bounds;
if (!isDragging) return; // Prevents text-selection when dragging.
var shiftKey = event.shiftKey;
var pickerDimensions = this.pickerDimensions();
left: event.pageX - pickerDimensions.left,
top: event.pageY - pickerDimensions.top
var left = Math.max(bounds.left, Math.min(cursorPosition.left, bounds.right));
var top = Math.max(bounds.top, Math.min(cursorPosition.top, bounds.bottom));
var nextX = (left - bounds.left) / (pickerDimensions.width - bounds.left * 2);
var nextY = (top - bounds.top) / (pickerDimensions.height - bounds.top * 2); // Enables holding shift to jump values by 10%
var step = shiftKey ? 0.1 : 0.01;
nextX = roundClamp(nextX, 0, 1, step);
nextY = roundClamp(nextY, 0, 1, step);
this.updateValue(nextPercentage);
value: function pickerDimensions() {
var containerNode = this.containerRef.current;
var clientHeight = containerNode.clientHeight,
clientWidth = containerNode.clientWidth;
var _containerNode$getBou = containerNode.getBoundingClientRect(),
top = _containerNode$getBou.top,
left = _containerNode$getBou.left;
top: top + document.body.scrollTop,
value: function iconCoordinates() {
var value = this.props.value;
var bounds = this.state.bounds;
if (bounds.left === undefined || bounds.top === undefined) {
var pickerDimensions = this.pickerDimensions();
left: value.x * (pickerDimensions.width - bounds.left * 2) + bounds.left,
top: value.y * (pickerDimensions.height - bounds.top * 2) + bounds.top
} // Callback method for the withFocusOutside higher-order component
key: "handleFocusOutside",
value: function handleFocusOutside() {
value: function render() {
var _this$props = this.props,
autoPlay = _this$props.autoPlay,
className = _this$props.className,
instanceId = _this$props.instanceId,
label = _this$props.label,
_onDragStart = _this$props.onDragStart,
onDragEnd = _this$props.onDragEnd,
var _this$state2 = this.state,
bounds = _this$state2.bounds,
isDragging = _this$state2.isDragging,
percentages = _this$state2.percentages;
var iconCoordinates = this.iconCoordinates();
var classes = classnames_default()('components-focal-point-picker-control', className);
var id = "inspector-focal-point-picker-control-".concat(instanceId);
return Object(external_wp_element_["createElement"])(base_control, {
}, Object(external_wp_element_["createElement"])(MediaWrapper, {
className: "components-focal-point-picker-wrapper"
}, Object(external_wp_element_["createElement"])(MediaContainer, {
className: "components-focal-point-picker",
onDragStart: function onDragStart(event) {
onDrop: function onDrop(event) {
onKeyDown: this.handleOnKeyDown,
onMouseDown: this.handleOnClick,
onMouseMove: this.onMouseMove,
onMouseUp: this.handleOnMouseUp,
}, Object(external_wp_element_["createElement"])(FocalPointPickerGrid, {
value: percentages.x + percentages.y
}), Object(external_wp_element_["createElement"])(Media, {
alt: Object(external_wp_i18n_["__"])('Media preview'),
onLoad: this.updateBounds,
}), Object(external_wp_element_["createElement"])(FocalPoint, {
coordinates: iconCoordinates,
}))), Object(external_wp_element_["createElement"])(FocalPointPickerControls, {
percentages: percentages,
onChange: this.updateValue
}(external_wp_element_["Component"]);
focal_point_picker_FocalPointPicker.defaultProps = {
onDragStart: external_lodash_["noop"],
onDragEnd: external_lodash_["noop"],
onChange: external_lodash_["noop"],
/* harmony default export */ var focal_point_picker = (Object(external_wp_compose_["compose"])([external_wp_compose_["withInstanceId"], with_focus_outside])(focal_point_picker_FocalPointPicker));
// CONCATENATED MODULE: ./node_modules/@wordpress/components/build-module/focusable-iframe/index.js
function FocusableIframe(_ref) {
var iframeRef = _ref.iframeRef,
props = Object(objectWithoutProperties["a" /* default */])(_ref, ["iframeRef", "onFocus"]);
var fallbackRef = Object(external_wp_element_["useRef"])();
var ref = iframeRef || fallbackRef;
Object(external_wp_element_["useEffect"])(function () {
var iframe = ref.current;
var ownerDocument = iframe.ownerDocument;
var defaultView = ownerDocument.defaultView;
var FocusEvent = defaultView.FocusEvent;
* Checks whether the iframe is the activeElement, inferring that it has
* then received focus, and calls the `onFocus` prop callback.
if (ownerDocument.activeElement !== iframe) {
var focusEvent = new FocusEvent('focus', {
iframe.dispatchEvent(focusEvent);
defaultView.addEventListener('blur', checkFocus);
defaultView.removeEventListener('blur', checkFocus);
}, [onFocus]); // Disable reason: The rendered iframe is a pass-through component,
// assigning props inherited from the rendering parent. It's the
// responsibility of the parent to assign a title.
// eslint-disable-next-line jsx-a11y/iframe-has-title
return Object(external_wp_element_["createElement"])("iframe", Object(esm_extends["a" /* default */])({
// EXTERNAL MODULE: ./node_modules/@wordpress/icons/build-module/library/text-color.js
var text_color = __webpack_require__("uGfJ");
// CONCATENATED MODULE: ./node_modules/@wordpress/components/build-module/range-control/utils.js
* A float supported clamp function for a specific value.
* @param {number|null} value The value to clamp.
* @param {number} min The minimum value.
* @param {number} max The maximum value.
* @return {number} A (float) number
function floatClamp(value, min, max) {
if (typeof value !== 'number') {
return parseFloat(Object(external_lodash_["clamp"])(value, min, max));
* Hook to store a clamped value, derived from props.
* @param {Object} settings Hook settings.
* @param {number} settings.min The minimum value.
* @param {number} settings.max The maximum value.
* @param {number} settings.value The current value.
* @param {any} settings.initial The initial value.
* @return {[*, Function]} The controlled value and the value setter.
function useControlledRangeValue(_ref) {
var _useControlledState = use_controlled_state(floatClamp(valueProp, min, max), {
_useControlledState2 = Object(slicedToArray["a" /* default */])(_useControlledState, 2),
state = _useControlledState2[0],
setInternalState = _useControlledState2[1];
var setState = Object(external_wp_element_["useCallback"])(function (nextValue) {
if (nextValue === null) {
setInternalState(floatClamp(nextValue, min, max));
return [state, setState];
* Hook to encapsulate the debouncing "hover" to better handle the showing
* and hiding of the Tooltip.
* @param {Object} settings Hook settings.
* @param {Function} [settings.onShow=noop] A callback function invoked when the element is shown.
* @param {Function} [settings.onHide=noop] A callback function invoked when the element is hidden.
* @param {Function} [settings.onMouseMove=noop] A callback function invoked when the mouse is moved.
* @param {Function} [settings.onMouseLeave=noop] A callback function invoked when the mouse is moved out of the element.
* @param {number} [settings.timeout=300] Timeout before the element is shown or hidden.
* @return {Object} Bound properties for use on a React.Node.
function useDebouncedHoverInteraction(_ref2) {
var _ref2$onHide = _ref2.onHide,
onHide = _ref2$onHide === void 0 ? external_lodash_["noop"] : _ref2$onHide,
_ref2$onMouseLeave = _ref2.onMouseLeave,
onMouseLeave = _ref2$onMouseLeave === void 0 ? external_lodash_["noop"] : _ref2$onMouseLeave,
_ref2$onMouseMove = _ref2.onMouseMove,
onMouseMove = _ref2$onMouseMove === void 0 ? external_lodash_["noop"] : _ref2$onMouseMove,
_ref2$onShow = _ref2.onShow,