: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* @param value Array of control points.
* @param initialIndex Index of the position to test.
* @param newPosition New position of the control point.
* @param minDistance Distance considered to be overlapping.
* @return True if the point is overlapping.
function isOverlapping(value, initialIndex, newPosition, minDistance = MINIMUM_DISTANCE_BETWEEN_POINTS) {
const initialPosition = value[initialIndex].position;
const minPosition = Math.min(initialPosition, newPosition);
const maxPosition = Math.max(initialPosition, newPosition);
return index !== initialIndex && (Math.abs(position - newPosition) < minDistance || minPosition < position && position < maxPosition);
* Adds a control point from an array and returns the new array.
* @param points Array of control points.
* @param position Position to insert the new point.
* @param color Color to update the control point at index.
* @return New array of control points.
function addControlPoint(points, position, color) {
const nextIndex = points.findIndex(point => point.position > position);
const newPoints = points.slice();
newPoints.splice(nextIndex - 1, 0, newPoint);
* Removes a control point from an array and returns the new array.
* @param points Array of control points.
* @param index Index to remove.
* @return New array of control points.
function removeControlPoint(points, index) {
return points.filter((_point, pointIndex) => {
return pointIndex !== index;
* Updates a control point from an array and returns the new array.
* @param points Array of control points.
* @param index Index to update.
* @param newPoint New control point to replace the index.
* @return New array of control points.
function updateControlPoint(points, index, newPoint) {
const newValue = points.slice();
newValue[index] = newPoint;
* Updates the position of a control point from an array and returns the new array.
* @param points Array of control points.
* @param index Index to update.
* @param newPosition Position to move the control point at index.
* @return New array of control points.
function updateControlPointPosition(points, index, newPosition) {
if (isOverlapping(points, index, newPosition)) {
return updateControlPoint(points, index, newPoint);
* Updates the position of a control point from an array and returns the new array.
* @param points Array of control points.
* @param index Index to update.
* @param newColor Color to update the control point at index.
* @return New array of control points.
function updateControlPointColor(points, index, newColor) {
return updateControlPoint(points, index, newPoint);
* Updates the position of a control point from an array and returns the new array.
* @param points Array of control points.
* @param position Position of the color stop.
* @param newColor Color to update the control point at index.
* @return New array of control points.
function updateControlPointColorByPosition(points, position, newColor) {
const index = points.findIndex(point => point.position === position);
return updateControlPointColor(points, index, newColor);
* Gets the horizontal coordinate when dragging a control point with the mouse.
* @param mouseXcoordinate Horizontal coordinate of the mouse position.
* @param containerElement Container for the gradient picker.
* @return Whole number percentage from the left.
function getHorizontalRelativeGradientPosition(mouseXCoordinate, containerElement) {
} = containerElement.getBoundingClientRect();
const absolutePositionValue = mouseXCoordinate - x;
return Math.round(clampPercent(absolutePositionValue * 100 / width));
;// CONCATENATED MODULE: ./node_modules/@wordpress/components/build-module/custom-gradient-picker/gradient-bar/control-points.js
function ControlPointButton({
const instanceId = (0,external_wp_compose_namespaceObject.useInstanceId)(ControlPointButton);
const descriptionId = `components-custom-gradient-picker__control-point-button-description-${instanceId}`;
return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsxs)(external_ReactJSXRuntime_namespaceObject.Fragment, {
children: [/*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(build_module_button, {
"aria-label": (0,external_wp_i18n_namespaceObject.sprintf)(
// translators: %1$s: gradient position e.g: 70, %2$s: gradient color code e.g: rgb(52,121,151).
(0,external_wp_i18n_namespaceObject.__)('Gradient control point at position %1$s%% with color code %2$s.'), position, color),
"aria-describedby": descriptionId,
className: dist_clsx('components-custom-gradient-picker__control-point-button', {
}), /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(visually_hidden_component, {
children: (0,external_wp_i18n_namespaceObject.__)('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({
// Open the popover below the gradient control/insertion point
const popoverProps = (0,external_wp_element_namespaceObject.useMemo)(() => ({
// Disabling resize as it would otherwise cause the popover to show
// scrollbars while dragging the color picker's handle close to the
const mergedClassName = dist_clsx('components-custom-gradient-picker__control-point-dropdown', className);
return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(CustomColorPickerDropdown, {
isRenderedInSidebar: isRenderedInSidebar,
popoverProps: popoverProps,
className: mergedClassName,
onStartControlPointChange,
onStopControlPointChange,
__experimentalIsRenderedInSidebar
const controlPointMoveState = (0,external_wp_element_namespaceObject.useRef)();
const onMouseMove = event => {
if (controlPointMoveState.current === undefined || gradientPickerDomRef.current === null) {
const relativePosition = getHorizontalRelativeGradientPosition(event.clientX, gradientPickerDomRef.current);
} = 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 = (0,external_wp_element_namespaceObject.useRef)();
cleanEventListenersRef.current = cleanEventListeners;
(0,external_wp_element_namespaceObject.useEffect)(() => {
cleanEventListenersRef.current?.();
return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_ReactJSXRuntime_namespaceObject.Fragment, {
children: controlPoints.map((point, index) => {
const initialPosition = point?.position;
return ignoreMarkerPosition !== initialPosition && /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(GradientColorPickerDropdown, {
isRenderedInSidebar: __experimentalIsRenderedInSidebar,
onClose: onStopControlPointChange,
}) => /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(ControlPointButton, {
if (controlPointMoveState.current && controlPointMoveState.current.significantMoveHappened) {
onStopControlPointChange();
onStartControlPointChange();
if (window && window.addEventListener) {
controlPointMoveState.current = {
significantMoveHappened: false,
onStartControlPointChange();
window.addEventListener('mousemove', onMouseMove);
window.addEventListener('mouseup', cleanEventListeners);
if (event.code === 'ArrowLeft') {
// Stop propagation of the key press event to avoid focus moving
// to another editor area.
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.
onChange(updateControlPointPosition(controlPoints, index, clampPercent(point.position + KEYBOARD_CONTROL_POINT_VARIATION)));
position: point.position,
}) => /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsxs)(dropdown_content_wrapper, {
children: [/*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(LegacyAdapter, {
enableAlpha: !disableAlpha,
onChange(updateControlPointColor(controlPoints, index, w(color).toRgbString()));
}), !disableRemove && controlPoints.length > 2 && /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(h_stack_component, {
className: "components-custom-gradient-picker__remove-control-point-wrapper",
children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(build_module_button, {
onChange(removeControlPoint(controlPoints, index));
children: (0,external_wp_i18n_namespaceObject.__)('Remove Control Point')
left: `${point.position}%`,
transform: 'translateX( -50% )'
__experimentalIsRenderedInSidebar
const [alreadyInsertedPoint, setAlreadyInsertedPoint] = (0,external_wp_element_namespaceObject.useState)(false);
return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(GradientColorPickerDropdown, {
isRenderedInSidebar: __experimentalIsRenderedInSidebar,
className: "components-custom-gradient-picker__inserter",
}) => /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(build_module_button, {
setAlreadyInsertedPoint(false);
className: "components-custom-gradient-picker__insert-point-dropdown",
renderContent: () => /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(dropdown_content_wrapper, {
children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(LegacyAdapter, {
enableAlpha: !disableAlpha,
if (!alreadyInsertedPoint) {
onChange(addControlPoint(controlPoints, insertPosition, w(color).toRgbString()));
setAlreadyInsertedPoint(true);
onChange(updateControlPointColorByPosition(controlPoints, insertPosition, w(color).toRgbString()));
style: insertPosition !== null ? {
left: `${insertPosition}%`,
transform: 'translateX( -50% )'
ControlPoints.InsertPoint = InsertPoint;
/* harmony default export */ const control_points = (ControlPoints);
;// CONCATENATED MODULE: ./node_modules/@wordpress/components/build-module/custom-gradient-picker/gradient-bar/index.js
const customGradientBarReducer = (state, action) => {
if (state.id === 'IDLE' || state.id === 'MOVING_INSERTER') {
insertPosition: action.insertPosition
case 'STOP_INSERTER_MOVE':
if (state.id === 'MOVING_INSERTER') {
if (state.id === 'MOVING_INSERTER') {
id: 'INSERTING_CONTROL_POINT',
insertPosition: state.insertPosition
if (state.id === 'INSERTING_CONTROL_POINT') {
case 'START_CONTROL_CHANGE':
if (state.id === 'IDLE') {
id: 'MOVING_CONTROL_POINT'
case 'STOP_CONTROL_CHANGE':
if (state.id === 'MOVING_CONTROL_POINT') {
const customGradientBarReducerInitialState = {
function CustomGradientBar({
__experimentalIsRenderedInSidebar = false
const gradientMarkersContainerDomRef = (0,external_wp_element_namespaceObject.useRef)(null);
const [gradientBarState, gradientBarStateDispatch] = (0,external_wp_element_namespaceObject.useReducer)(customGradientBarReducer, customGradientBarReducerInitialState);
const onMouseEnterAndMove = event => {
if (!gradientMarkersContainerDomRef.current) {
const insertPosition = getHorizontalRelativeGradientPosition(event.clientX, gradientMarkersContainerDomRef.current);
// If the insert point is close to an existing control point don't show it.
if (controlPoints.some(({
return Math.abs(insertPosition - position) < MINIMUM_DISTANCE_BETWEEN_INSERTER_AND_POINT;
if (gradientBarState.id === 'MOVING_INSERTER') {
gradientBarStateDispatch({
type: 'STOP_INSERTER_MOVE'