Source: components/criteria_builder/EmptyDropZone.es.js

/**
 * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 */

import getCN from 'classnames';
import PropTypes from 'prop-types';
import React, {Component} from 'react';
import {DropTarget as dropTarget} from 'react-dnd';

import ThemeContext from '../../ThemeContext.es';
import {DragTypes} from '../../utils/drag-types.es';
import EmptyPlaceholder from './EmptyPlaceholder.es';

/**
 * Prevents items from being dropped from other contributors.
 * This method must be called `canDrop`.
 * @param {Object} props Component's current props.
 * @param {DropTargetMonitor} monitor
 * @returns {boolean} True if the target should accept the item.
 */
function canDrop(props, monitor) {
	const {propertyKey: destPropertyKey} = props;
	const {propertyKey: startPropertyKey} = monitor.getItem();

	return destPropertyKey === startPropertyKey;
}

/**
 * Implements the behavior of what will occur when an item is dropped.
 * Adds the criterion dropped.
 * This method must be called `drop`.
 * @param {Object} props Component's current props.
 * @param {DropTargetMonitor} monitor
 */
function drop(props, monitor) {
	const {criterion} = monitor.getItem();

	props.onCriterionAdd(0, criterion);
}

class EmptyDropZone extends Component {
	static contextType = ThemeContext;

	static propTypes = {
		canDrop: PropTypes.bool,
		connectDropTarget: PropTypes.func,
		emptyContributors: PropTypes.bool,
		hover: PropTypes.bool,
		onCriterionAdd: PropTypes.func.isRequired,
		propertyKey: PropTypes.string.isRequired,
	};

	render() {
		const {
			canDrop,
			connectDropTarget,
			emptyContributors,
			hover,
		} = this.props;

		const displayEmptyDropZone = canDrop || !emptyContributors;

		const emptyZoneClasses = getCN('empty-drop-zone-root', {
			'empty-drop-zone-dashed border-primary rounded':
				displayEmptyDropZone && (!canDrop || !hover),
		});

		const targetClasses = getCN(
			emptyContributors
				? 'empty-drop-zone-target'
				: 'drop-zone-target p-5',
			{
				'empty-drop-zone-target-solid dnd-hover border-primary rounded':
					canDrop && hover,
			}
		);

		return (
			<div className={emptyZoneClasses}>
				{connectDropTarget(
					displayEmptyDropZone ? (
						<div className={targetClasses}>
							<div className="empty-drop-zone-indicator" />
						</div>
					) : (
						<div>
							<EmptyPlaceholder />
						</div>
					)
				)}
			</div>
		);
	}
}

export default dropTarget(
	DragTypes.PROPERTY,
	{
		canDrop,
		drop,
	},
	(connect, monitor) => ({
		canDrop: monitor.canDrop(),
		connectDropTarget: connect.dropTarget(),
		hover: monitor.isOver(),
	})
)(EmptyDropZone);