typescript
This commit is contained in:
@@ -0,0 +1,178 @@
|
||||
import { safeInvoke } from '../events';
|
||||
|
||||
export const CLICK_ACTIONS = {
|
||||
selectSingle: 'selectSingle',
|
||||
openDetail: 'openDetail',
|
||||
addCard: 'addCard',
|
||||
addStack: 'addStack',
|
||||
none: 'none',
|
||||
} as const;
|
||||
|
||||
export const DRAG_ACTIONS = {
|
||||
dragSelectSingle: 'dragSelectSingle',
|
||||
dragSelection: 'dragSelection',
|
||||
dragSelectStack: 'dragSelectStack',
|
||||
none: 'none',
|
||||
} as const;
|
||||
|
||||
export type ClickAction = (typeof CLICK_ACTIONS)[keyof typeof CLICK_ACTIONS];
|
||||
export type DragAction = (typeof DRAG_ACTIONS)[keyof typeof DRAG_ACTIONS];
|
||||
|
||||
export const STACK_HIT_EPSILON = 4;
|
||||
export const POINTER_DRAG_THRESHOLD_SQUARED = 16;
|
||||
export const LONG_PRESS_DURATION_MS = 450;
|
||||
|
||||
export const withinThreshold = (dx: number, dy: number, thresholdSquared: number): boolean => (dx * dx + dy * dy) <= thresholdSquared;
|
||||
|
||||
interface PointerIntentArgs {
|
||||
doc: { id: string | number };
|
||||
entryDescriptor: unknown;
|
||||
selectedDocumentIds: Array<string | number>;
|
||||
metaKey: boolean;
|
||||
pointerButton?: number;
|
||||
pointerType?: string;
|
||||
stackHits?: string[] | null;
|
||||
}
|
||||
|
||||
export interface PointerIntent {
|
||||
docId: string | number;
|
||||
entryDescriptor: unknown;
|
||||
pointerType?: string;
|
||||
pointerButton?: number;
|
||||
selectedAtDown: boolean;
|
||||
selectionCountAtDown: number;
|
||||
metaKey: boolean;
|
||||
clickAction: ClickAction;
|
||||
dragAction: DragAction;
|
||||
stackDocIdsForDrag: string[] | null;
|
||||
stackDocIdsForClick: string[] | null;
|
||||
stackReplaceOnClick: boolean;
|
||||
stackReplaceOnDrag: boolean;
|
||||
clickSelectionApplied: boolean;
|
||||
stackSelectionApplied: boolean;
|
||||
longPressTriggered: boolean;
|
||||
}
|
||||
|
||||
export const createPointerIntent = ({
|
||||
doc,
|
||||
entryDescriptor,
|
||||
selectedDocumentIds,
|
||||
metaKey,
|
||||
pointerButton,
|
||||
pointerType,
|
||||
stackHits,
|
||||
}: PointerIntentArgs): PointerIntent => {
|
||||
const alreadySelected = selectedDocumentIds.includes(doc.id);
|
||||
const selectionCount = Array.isArray(selectedDocumentIds) ? selectedDocumentIds.length : 0;
|
||||
|
||||
let clickAction = CLICK_ACTIONS.none;
|
||||
let dragAction = DRAG_ACTIONS.none;
|
||||
|
||||
if (metaKey) {
|
||||
clickAction = CLICK_ACTIONS.addStack;
|
||||
dragAction = DRAG_ACTIONS.dragSelectStack;
|
||||
} else if (alreadySelected) {
|
||||
clickAction = CLICK_ACTIONS.selectSingle;
|
||||
dragAction = selectionCount > 1 ? DRAG_ACTIONS.dragSelection : DRAG_ACTIONS.dragSelectSingle;
|
||||
} else {
|
||||
clickAction = CLICK_ACTIONS.selectSingle;
|
||||
dragAction = DRAG_ACTIONS.dragSelectSingle;
|
||||
}
|
||||
|
||||
const stackList = Array.isArray(stackHits) && stackHits.length > 0
|
||||
? stackHits.slice()
|
||||
: [String(doc.id)];
|
||||
|
||||
const stackDocIdsForDrag = dragAction === DRAG_ACTIONS.dragSelectStack ? stackList : null;
|
||||
const stackDocIdsForClick = clickAction === CLICK_ACTIONS.addStack ? stackList : null;
|
||||
|
||||
return {
|
||||
docId: doc.id,
|
||||
entryDescriptor,
|
||||
pointerType,
|
||||
pointerButton,
|
||||
selectedAtDown: alreadySelected,
|
||||
selectionCountAtDown: selectionCount,
|
||||
metaKey,
|
||||
clickAction,
|
||||
dragAction,
|
||||
stackDocIdsForDrag,
|
||||
stackDocIdsForClick,
|
||||
stackReplaceOnClick: clickAction === CLICK_ACTIONS.addStack,
|
||||
stackReplaceOnDrag: dragAction === DRAG_ACTIONS.dragSelectStack,
|
||||
clickSelectionApplied: false,
|
||||
stackSelectionApplied: false,
|
||||
longPressTriggered: false,
|
||||
};
|
||||
};
|
||||
|
||||
export const applyClickPlanImmediately = ({ intent, event, onEntryPointer, onDocumentStackSelect }: {
|
||||
intent: PointerIntent;
|
||||
event?: unknown;
|
||||
onEntryPointer?: (descriptor: unknown, event?: unknown) => void;
|
||||
onDocumentStackSelect?: (docIds: string[], event?: unknown, options?: { replace?: boolean }) => void;
|
||||
}) => {
|
||||
switch (intent.clickAction) {
|
||||
case CLICK_ACTIONS.selectSingle:
|
||||
case CLICK_ACTIONS.addCard:
|
||||
safeInvoke(onEntryPointer, intent.entryDescriptor, event);
|
||||
intent.clickSelectionApplied = true;
|
||||
break;
|
||||
case CLICK_ACTIONS.addStack:
|
||||
if (Array.isArray(intent.stackDocIdsForClick) && intent.stackDocIdsForClick.length > 0) {
|
||||
safeInvoke(
|
||||
onDocumentStackSelect,
|
||||
intent.stackDocIdsForClick,
|
||||
event,
|
||||
{ replace: intent.stackReplaceOnClick },
|
||||
);
|
||||
intent.clickSelectionApplied = true;
|
||||
intent.stackSelectionApplied = true;
|
||||
}
|
||||
break;
|
||||
case CLICK_ACTIONS.openDetail:
|
||||
default:
|
||||
intent.clickSelectionApplied = true;
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
export const finalizeClickSelection = ({ intent, event, onEntryPointer, onDocumentStackSelect }: {
|
||||
intent: PointerIntent;
|
||||
event?: unknown;
|
||||
onEntryPointer?: (descriptor: unknown, event?: unknown) => void;
|
||||
onDocumentStackSelect?: (docIds: string[], event?: unknown, options?: { replace?: boolean }) => void;
|
||||
}) => {
|
||||
if (!intent || intent.clickSelectionApplied) {
|
||||
return;
|
||||
}
|
||||
|
||||
applyClickPlanImmediately({ intent, event, onEntryPointer, onDocumentStackSelect });
|
||||
};
|
||||
|
||||
export const applyLongPressSelection = ({ intent, stackDocIds, syntheticEvent, onDocumentStackSelect }: {
|
||||
intent: PointerIntent;
|
||||
stackDocIds?: string[] | null;
|
||||
syntheticEvent?: unknown;
|
||||
onDocumentStackSelect?: (docIds: string[], event?: unknown, options?: { replace?: boolean }) => void;
|
||||
}) => {
|
||||
if (!intent) {
|
||||
return;
|
||||
}
|
||||
|
||||
const stackCopy = Array.isArray(stackDocIds) && stackDocIds.length > 0
|
||||
? stackDocIds.slice()
|
||||
: [intent.docId];
|
||||
|
||||
safeInvoke(onDocumentStackSelect, stackCopy, syntheticEvent, { replace: true });
|
||||
|
||||
intent.clickAction = CLICK_ACTIONS.addStack;
|
||||
intent.dragAction = DRAG_ACTIONS.dragSelectStack;
|
||||
intent.stackDocIdsForClick = stackCopy;
|
||||
intent.stackDocIdsForDrag = stackCopy;
|
||||
intent.stackReplaceOnClick = true;
|
||||
intent.stackReplaceOnDrag = true;
|
||||
intent.clickSelectionApplied = true;
|
||||
intent.stackSelectionApplied = true;
|
||||
intent.longPressTriggered = true;
|
||||
};
|
||||
Reference in New Issue
Block a user