@wordpress/components
Version:
UI components for WordPress.
270 lines (251 loc) • 9.7 kB
JavaScript
import _extends from "@babel/runtime/helpers/esm/extends";
import { createElement, Fragment } from "@wordpress/element";
/**
* External dependencies
*/
import classnames from 'classnames';
import { colord } from 'colord';
/**
* WordPress dependencies
*/
import { useInstanceId } from '@wordpress/compose';
import { useEffect, useRef, useState, useMemo } from '@wordpress/element';
import { __, sprintf } from '@wordpress/i18n';
import { plus } from '@wordpress/icons';
/**
* Internal dependencies
*/
import Button from '../../button';
import { HStack } from '../../h-stack';
import { ColorPicker } from '../../color-picker';
import { VisuallyHidden } from '../../visually-hidden';
import { CustomColorPickerDropdown } from '../../color-palette';
import { addControlPoint, clampPercent, removeControlPoint, updateControlPointColor, updateControlPointColorByPosition, updateControlPointPosition, getHorizontalRelativeGradientPosition } from './utils';
import { MINIMUM_SIGNIFICANT_MOVE, KEYBOARD_CONTROL_POINT_VARIATION } from './constants';
function ControlPointButton(_ref) {
let {
isOpen,
position,
color,
...additionalProps
} = _ref;
const instanceId = useInstanceId(ControlPointButton);
const descriptionId = `components-custom-gradient-picker__control-point-button-description-${instanceId}`;
return createElement(Fragment, null, createElement(Button, _extends({
"aria-label": sprintf( // translators: %1$s: gradient position e.g: 70, %2$s: gradient color code e.g: rgb(52,121,151).
__('Gradient control point at position %1$s%% with color code %2$s.'), position, color),
"aria-describedby": descriptionId,
"aria-haspopup": "true",
"aria-expanded": isOpen,
className: classnames('components-custom-gradient-picker__control-point-button', {
'is-active': isOpen
})
}, additionalProps)), createElement(VisuallyHidden, {
id: descriptionId
}, __('Use your left or right arrow keys or drag and drop with the mouse to change the gradient position. Press the button to change the color or remove the control point.')));
}
function GradientColorPickerDropdown(_ref2) {
let {
isRenderedInSidebar,
className,
...props
} = _ref2;
// Open the popover below the gradient control/insertion point
const popoverProps = useMemo(() => ({
placement: 'bottom',
offset: 8
}), []);
const mergedClassName = classnames('components-custom-gradient-picker__control-point-dropdown', className);
return createElement(CustomColorPickerDropdown, _extends({
isRenderedInSidebar: isRenderedInSidebar,
popoverProps: popoverProps,
className: mergedClassName
}, props));
}
function ControlPoints(_ref3) {
let {
disableRemove,
disableAlpha,
gradientPickerDomRef,
ignoreMarkerPosition,
value: controlPoints,
onChange,
onStartControlPointChange,
onStopControlPointChange,
__experimentalIsRenderedInSidebar
} = _ref3;
const controlPointMoveState = useRef();
const onMouseMove = event => {
if (controlPointMoveState.current === undefined || gradientPickerDomRef.current === null) {
return;
}
const relativePosition = getHorizontalRelativeGradientPosition(event.clientX, gradientPickerDomRef.current);
const {
initialPosition,
index,
significantMoveHappened
} = controlPointMoveState.current;
if (!significantMoveHappened && Math.abs(initialPosition - relativePosition) >= MINIMUM_SIGNIFICANT_MOVE) {
controlPointMoveState.current.significantMoveHappened = true;
}
onChange(updateControlPointPosition(controlPoints, index, relativePosition));
};
const cleanEventListeners = () => {
if (window && window.removeEventListener && controlPointMoveState.current && controlPointMoveState.current.listenersActivated) {
window.removeEventListener('mousemove', onMouseMove);
window.removeEventListener('mouseup', cleanEventListeners);
onStopControlPointChange();
controlPointMoveState.current.listenersActivated = false;
}
}; // Adding `cleanEventListeners` to the dependency array below requires the function itself to be wrapped in a `useCallback`
// This memoization would prevent the event listeners from being properly cleaned.
// Instead, we'll pass a ref to the function in our `useEffect` so `cleanEventListeners` itself is no longer a dependency.
const cleanEventListenersRef = useRef();
cleanEventListenersRef.current = cleanEventListeners;
useEffect(() => {
return () => {
var _cleanEventListenersR;
(_cleanEventListenersR = cleanEventListenersRef.current) === null || _cleanEventListenersR === void 0 ? void 0 : _cleanEventListenersR.call(cleanEventListenersRef);
};
}, []);
return createElement(Fragment, null, controlPoints.map((point, index) => {
const initialPosition = point === null || point === void 0 ? void 0 : point.position;
return ignoreMarkerPosition !== initialPosition && createElement(GradientColorPickerDropdown, {
isRenderedInSidebar: __experimentalIsRenderedInSidebar,
key: index,
onClose: onStopControlPointChange,
renderToggle: _ref4 => {
let {
isOpen,
onToggle
} = _ref4;
return createElement(ControlPointButton, {
key: index,
onClick: () => {
if (controlPointMoveState.current && controlPointMoveState.current.significantMoveHappened) {
return;
}
if (isOpen) {
onStopControlPointChange();
} else {
onStartControlPointChange();
}
onToggle();
},
onMouseDown: () => {
if (window && window.addEventListener) {
controlPointMoveState.current = {
initialPosition,
index,
significantMoveHappened: false,
listenersActivated: true
};
onStartControlPointChange();
window.addEventListener('mousemove', onMouseMove);
window.addEventListener('mouseup', cleanEventListeners);
}
},
onKeyDown: event => {
if (event.code === 'ArrowLeft') {
// Stop propagation of the key press event to avoid focus moving
// to another editor area.
event.stopPropagation();
onChange(updateControlPointPosition(controlPoints, index, clampPercent(point.position - KEYBOARD_CONTROL_POINT_VARIATION)));
} else if (event.code === 'ArrowRight') {
// Stop propagation of the key press event to avoid focus moving
// to another editor area.
event.stopPropagation();
onChange(updateControlPointPosition(controlPoints, index, clampPercent(point.position + KEYBOARD_CONTROL_POINT_VARIATION)));
}
},
isOpen: isOpen,
position: point.position,
color: point.color
});
},
renderContent: _ref5 => {
let {
onClose
} = _ref5;
return createElement(Fragment, null, createElement(ColorPicker, {
enableAlpha: !disableAlpha,
color: point.color,
onChange: color => {
onChange(updateControlPointColor(controlPoints, index, colord(color).toRgbString()));
}
}), !disableRemove && controlPoints.length > 2 && createElement(HStack, {
className: "components-custom-gradient-picker__remove-control-point-wrapper",
alignment: "center"
}, createElement(Button, {
onClick: () => {
onChange(removeControlPoint(controlPoints, index));
onClose();
},
variant: "link"
}, __('Remove Control Point'))));
},
style: {
left: `${point.position}%`,
transform: 'translateX( -50% )'
}
});
}));
}
function InsertPoint(_ref6) {
let {
value: controlPoints,
onChange,
onOpenInserter,
onCloseInserter,
insertPosition,
disableAlpha,
__experimentalIsRenderedInSidebar
} = _ref6;
const [alreadyInsertedPoint, setAlreadyInsertedPoint] = useState(false);
return createElement(GradientColorPickerDropdown, {
isRenderedInSidebar: __experimentalIsRenderedInSidebar,
className: "components-custom-gradient-picker__inserter",
onClose: () => {
onCloseInserter();
},
renderToggle: _ref7 => {
let {
isOpen,
onToggle
} = _ref7;
return createElement(Button, {
"aria-expanded": isOpen,
"aria-haspopup": "true",
onClick: () => {
if (isOpen) {
onCloseInserter();
} else {
setAlreadyInsertedPoint(false);
onOpenInserter();
}
onToggle();
},
className: "components-custom-gradient-picker__insert-point-dropdown",
icon: plus
});
},
renderContent: () => createElement(ColorPicker, {
enableAlpha: !disableAlpha,
onChange: color => {
if (!alreadyInsertedPoint) {
onChange(addControlPoint(controlPoints, insertPosition, colord(color).toRgbString()));
setAlreadyInsertedPoint(true);
} else {
onChange(updateControlPointColorByPosition(controlPoints, insertPosition, colord(color).toRgbString()));
}
}
}),
style: insertPosition !== null ? {
left: `${insertPosition}%`,
transform: 'translateX( -50% )'
} : undefined
});
}
ControlPoints.InsertPoint = InsertPoint;
export default ControlPoints;
//# sourceMappingURL=control-points.js.map