You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
153 lines
5.3 KiB
153 lines
5.3 KiB
import { invariant } from '@react-dnd/invariant';
|
|
import matchesType from './utils/matchesType';
|
|
import { getSourceClientOffset, getDifferenceFromInitialOffset, } from './utils/coords';
|
|
import { areDirty } from './utils/dirtiness';
|
|
export default class DragDropMonitorImpl {
|
|
constructor(store, registry) {
|
|
this.store = store;
|
|
this.registry = registry;
|
|
}
|
|
subscribeToStateChange(listener, options = { handlerIds: undefined }) {
|
|
const { handlerIds } = options;
|
|
invariant(typeof listener === 'function', 'listener must be a function.');
|
|
invariant(typeof handlerIds === 'undefined' || Array.isArray(handlerIds), 'handlerIds, when specified, must be an array of strings.');
|
|
let prevStateId = this.store.getState().stateId;
|
|
const handleChange = () => {
|
|
const state = this.store.getState();
|
|
const currentStateId = state.stateId;
|
|
try {
|
|
const canSkipListener = currentStateId === prevStateId ||
|
|
(currentStateId === prevStateId + 1 &&
|
|
!areDirty(state.dirtyHandlerIds, handlerIds));
|
|
if (!canSkipListener) {
|
|
listener();
|
|
}
|
|
}
|
|
finally {
|
|
prevStateId = currentStateId;
|
|
}
|
|
};
|
|
return this.store.subscribe(handleChange);
|
|
}
|
|
subscribeToOffsetChange(listener) {
|
|
invariant(typeof listener === 'function', 'listener must be a function.');
|
|
let previousState = this.store.getState().dragOffset;
|
|
const handleChange = () => {
|
|
const nextState = this.store.getState().dragOffset;
|
|
if (nextState === previousState) {
|
|
return;
|
|
}
|
|
previousState = nextState;
|
|
listener();
|
|
};
|
|
return this.store.subscribe(handleChange);
|
|
}
|
|
canDragSource(sourceId) {
|
|
if (!sourceId) {
|
|
return false;
|
|
}
|
|
const source = this.registry.getSource(sourceId);
|
|
invariant(source, 'Expected to find a valid source.');
|
|
if (this.isDragging()) {
|
|
return false;
|
|
}
|
|
return source.canDrag(this, sourceId);
|
|
}
|
|
canDropOnTarget(targetId) {
|
|
// undefined on initial render
|
|
if (!targetId) {
|
|
return false;
|
|
}
|
|
const target = this.registry.getTarget(targetId);
|
|
invariant(target, 'Expected to find a valid target.');
|
|
if (!this.isDragging() || this.didDrop()) {
|
|
return false;
|
|
}
|
|
const targetType = this.registry.getTargetType(targetId);
|
|
const draggedItemType = this.getItemType();
|
|
return (matchesType(targetType, draggedItemType) && target.canDrop(this, targetId));
|
|
}
|
|
isDragging() {
|
|
return Boolean(this.getItemType());
|
|
}
|
|
isDraggingSource(sourceId) {
|
|
// undefined on initial render
|
|
if (!sourceId) {
|
|
return false;
|
|
}
|
|
const source = this.registry.getSource(sourceId, true);
|
|
invariant(source, 'Expected to find a valid source.');
|
|
if (!this.isDragging() || !this.isSourcePublic()) {
|
|
return false;
|
|
}
|
|
const sourceType = this.registry.getSourceType(sourceId);
|
|
const draggedItemType = this.getItemType();
|
|
if (sourceType !== draggedItemType) {
|
|
return false;
|
|
}
|
|
return source.isDragging(this, sourceId);
|
|
}
|
|
isOverTarget(targetId, options = { shallow: false }) {
|
|
// undefined on initial render
|
|
if (!targetId) {
|
|
return false;
|
|
}
|
|
const { shallow } = options;
|
|
if (!this.isDragging()) {
|
|
return false;
|
|
}
|
|
const targetType = this.registry.getTargetType(targetId);
|
|
const draggedItemType = this.getItemType();
|
|
if (draggedItemType && !matchesType(targetType, draggedItemType)) {
|
|
return false;
|
|
}
|
|
const targetIds = this.getTargetIds();
|
|
if (!targetIds.length) {
|
|
return false;
|
|
}
|
|
const index = targetIds.indexOf(targetId);
|
|
if (shallow) {
|
|
return index === targetIds.length - 1;
|
|
}
|
|
else {
|
|
return index > -1;
|
|
}
|
|
}
|
|
getItemType() {
|
|
return this.store.getState().dragOperation.itemType;
|
|
}
|
|
getItem() {
|
|
return this.store.getState().dragOperation.item;
|
|
}
|
|
getSourceId() {
|
|
return this.store.getState().dragOperation.sourceId;
|
|
}
|
|
getTargetIds() {
|
|
return this.store.getState().dragOperation.targetIds;
|
|
}
|
|
getDropResult() {
|
|
return this.store.getState().dragOperation.dropResult;
|
|
}
|
|
didDrop() {
|
|
return this.store.getState().dragOperation.didDrop;
|
|
}
|
|
isSourcePublic() {
|
|
return this.store.getState().dragOperation.isSourcePublic;
|
|
}
|
|
getInitialClientOffset() {
|
|
return this.store.getState().dragOffset.initialClientOffset;
|
|
}
|
|
getInitialSourceClientOffset() {
|
|
return this.store.getState().dragOffset.initialSourceClientOffset;
|
|
}
|
|
getClientOffset() {
|
|
return this.store.getState().dragOffset.clientOffset;
|
|
}
|
|
getSourceClientOffset() {
|
|
return getSourceClientOffset(this.store.getState().dragOffset);
|
|
}
|
|
getDifferenceFromInitialOffset() {
|
|
return getDifferenceFromInitialOffset(this.store.getState().dragOffset);
|
|
}
|
|
}
|