planning
All checks were successful
Publish To Prod / deploy_and_publish (push) Successful in 35s

This commit is contained in:
2024-10-14 09:15:30 +02:00
parent bcba00a730
commit 6e64e138e2
21059 changed files with 2317811 additions and 1 deletions

View File

@@ -0,0 +1,17 @@
import { Store, Action } from 'redux';
import { Backend, DragDropActions, DragDropMonitor, DragDropManager, HandlerRegistry } from '../interfaces';
import { State } from '../reducers';
export declare class DragDropManagerImpl implements DragDropManager {
private store;
private monitor;
private backend;
private isSetUp;
constructor(store: Store<State>, monitor: DragDropMonitor);
receiveBackend(backend: Backend): void;
getMonitor(): DragDropMonitor;
getBackend(): Backend;
getRegistry(): HandlerRegistry;
getActions(): DragDropActions;
dispatch(action: Action<any>): void;
private handleRefCountChange;
}

View File

@@ -0,0 +1,59 @@
import { createDragDropActions } from '../actions/dragDrop';
export class DragDropManagerImpl {
store;
monitor;
backend;
isSetUp = false;
constructor(store, monitor) {
this.store = store;
this.monitor = monitor;
store.subscribe(this.handleRefCountChange);
}
receiveBackend(backend) {
this.backend = backend;
}
getMonitor() {
return this.monitor;
}
getBackend() {
return this.backend;
}
getRegistry() {
return this.monitor.registry;
}
getActions() {
/* eslint-disable-next-line @typescript-eslint/no-this-alias */
const manager = this;
const { dispatch } = this.store;
function bindActionCreator(actionCreator) {
return (...args) => {
const action = actionCreator.apply(manager, args);
if (typeof action !== 'undefined') {
dispatch(action);
}
};
}
const actions = createDragDropActions(this);
return Object.keys(actions).reduce((boundActions, key) => {
const action = actions[key];
boundActions[key] = bindActionCreator(action);
return boundActions;
}, {});
}
dispatch(action) {
this.store.dispatch(action);
}
handleRefCountChange = () => {
const shouldSetUp = this.store.getState().refCount > 0;
if (this.backend) {
if (shouldSetUp && !this.isSetUp) {
this.backend.setup();
this.isSetUp = true;
}
else if (!shouldSetUp && this.isSetUp) {
this.backend.teardown();
this.isSetUp = false;
}
}
};
}

View File

@@ -0,0 +1,31 @@
import { Store } from 'redux';
import { State } from '../reducers';
import { DragDropMonitor, Listener, Unsubscribe, XYCoord, HandlerRegistry, Identifier } from '../interfaces';
export declare class DragDropMonitorImpl implements DragDropMonitor {
private store;
readonly registry: HandlerRegistry;
constructor(store: Store<State>, registry: HandlerRegistry);
subscribeToStateChange(listener: Listener, options?: {
handlerIds: string[] | undefined;
}): Unsubscribe;
subscribeToOffsetChange(listener: Listener): Unsubscribe;
canDragSource(sourceId: string | undefined): boolean;
canDropOnTarget(targetId: string | undefined): boolean;
isDragging(): boolean;
isDraggingSource(sourceId: string | undefined): boolean;
isOverTarget(targetId: string | undefined, options?: {
shallow: boolean;
}): boolean;
getItemType(): Identifier;
getItem(): any;
getSourceId(): string | null;
getTargetIds(): string[];
getDropResult(): any;
didDrop(): boolean;
isSourcePublic(): boolean;
getInitialClientOffset(): XYCoord | null;
getInitialSourceClientOffset(): XYCoord | null;
getClientOffset(): XYCoord | null;
getSourceClientOffset(): XYCoord | null;
getDifferenceFromInitialOffset(): XYCoord | null;
}

View File

@@ -0,0 +1,154 @@
import { invariant } from '@react-dnd/invariant';
import { matchesType } from '../utils/matchesType';
import { getSourceClientOffset, getDifferenceFromInitialOffset, } from '../utils/coords';
import { areDirty } from '../utils/dirtiness';
export class DragDropMonitorImpl {
store;
registry;
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. sourceId=${sourceId}`);
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. targetId=${targetId}`);
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. sourceId=${sourceId}`);
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 Boolean(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);
}
}

View File

@@ -0,0 +1,26 @@
import { Store } from 'redux';
import { State } from '../reducers';
import { DragSource, DropTarget, SourceType, TargetType, Identifier, HandlerRegistry } from '../interfaces';
export declare class HandlerRegistryImpl implements HandlerRegistry {
private types;
private dragSources;
private dropTargets;
private pinnedSourceId;
private pinnedSource;
private store;
constructor(store: Store<State>);
addSource(type: SourceType, source: DragSource): string;
addTarget(type: TargetType, target: DropTarget): string;
containsHandler(handler: DragSource | DropTarget): boolean;
getSource(sourceId: string, includePinned?: boolean): DragSource;
getTarget(targetId: string): DropTarget;
getSourceType(sourceId: string): Identifier;
getTargetType(targetId: string): Identifier | Identifier[];
isSourceId(handlerId: string): boolean;
isTargetId(handlerId: string): boolean;
removeSource(sourceId: string): void;
removeTarget(targetId: string): void;
pinSource(sourceId: string): void;
unpinSource(): void;
private addHandler;
}

View File

@@ -0,0 +1,130 @@
import { invariant } from '@react-dnd/invariant';
import { addSource, addTarget, removeSource, removeTarget, } from '../actions/registry';
import { getNextUniqueId } from '../utils/getNextUniqueId';
import { HandlerRole, } from '../interfaces';
import { validateSourceContract, validateTargetContract, validateType, } from '../contracts';
import { asap } from '@react-dnd/asap';
function getNextHandlerId(role) {
const id = getNextUniqueId().toString();
switch (role) {
case HandlerRole.SOURCE:
return `S${id}`;
case HandlerRole.TARGET:
return `T${id}`;
default:
throw new Error(`Unknown Handler Role: ${role}`);
}
}
function parseRoleFromHandlerId(handlerId) {
switch (handlerId[0]) {
case 'S':
return HandlerRole.SOURCE;
case 'T':
return HandlerRole.TARGET;
default:
invariant(false, `Cannot parse handler ID: ${handlerId}`);
}
}
function mapContainsValue(map, searchValue) {
const entries = map.entries();
let isDone = false;
do {
const { done, value: [, value], } = entries.next();
if (value === searchValue) {
return true;
}
isDone = !!done;
} while (!isDone);
return false;
}
export class HandlerRegistryImpl {
types = new Map();
dragSources = new Map();
dropTargets = new Map();
pinnedSourceId = null;
pinnedSource = null;
store;
constructor(store) {
this.store = store;
}
addSource(type, source) {
validateType(type);
validateSourceContract(source);
const sourceId = this.addHandler(HandlerRole.SOURCE, type, source);
this.store.dispatch(addSource(sourceId));
return sourceId;
}
addTarget(type, target) {
validateType(type, true);
validateTargetContract(target);
const targetId = this.addHandler(HandlerRole.TARGET, type, target);
this.store.dispatch(addTarget(targetId));
return targetId;
}
containsHandler(handler) {
return (mapContainsValue(this.dragSources, handler) ||
mapContainsValue(this.dropTargets, handler));
}
getSource(sourceId, includePinned = false) {
invariant(this.isSourceId(sourceId), 'Expected a valid source ID.');
const isPinned = includePinned && sourceId === this.pinnedSourceId;
const source = isPinned ? this.pinnedSource : this.dragSources.get(sourceId);
return source;
}
getTarget(targetId) {
invariant(this.isTargetId(targetId), 'Expected a valid target ID.');
return this.dropTargets.get(targetId);
}
getSourceType(sourceId) {
invariant(this.isSourceId(sourceId), 'Expected a valid source ID.');
return this.types.get(sourceId);
}
getTargetType(targetId) {
invariant(this.isTargetId(targetId), 'Expected a valid target ID.');
return this.types.get(targetId);
}
isSourceId(handlerId) {
const role = parseRoleFromHandlerId(handlerId);
return role === HandlerRole.SOURCE;
}
isTargetId(handlerId) {
const role = parseRoleFromHandlerId(handlerId);
return role === HandlerRole.TARGET;
}
removeSource(sourceId) {
invariant(this.getSource(sourceId), 'Expected an existing source.');
this.store.dispatch(removeSource(sourceId));
asap(() => {
this.dragSources.delete(sourceId);
this.types.delete(sourceId);
});
}
removeTarget(targetId) {
invariant(this.getTarget(targetId), 'Expected an existing target.');
this.store.dispatch(removeTarget(targetId));
this.dropTargets.delete(targetId);
this.types.delete(targetId);
}
pinSource(sourceId) {
const source = this.getSource(sourceId);
invariant(source, 'Expected an existing source.');
this.pinnedSourceId = sourceId;
this.pinnedSource = source;
}
unpinSource() {
invariant(this.pinnedSource, 'No source is pinned at the time.');
this.pinnedSourceId = null;
this.pinnedSource = null;
}
addHandler(role, type, handler) {
const id = getNextHandlerId(role);
this.types.set(id, type);
if (role === HandlerRole.SOURCE) {
this.dragSources.set(id, handler);
}
else if (role === HandlerRole.TARGET) {
this.dropTargets.set(id, handler);
}
return id;
}
}