packages/selecto/src/types.ts

import { IObject } from "@daybrush/utils";
import { PROPERTIES, METHODS } from "./consts";
import Selecto from "./Selecto";
import {
    OnDragStart as OnParentDragStart,
    OnDrag as OnParentDrag,
    OnDragEnd as OnParentDragEnd,
} from "gesto";
import { DragScrollOptions } from "@scena/dragscroll";

export type ElementType = HTMLElement | SVGElement;
export interface ElementRef<T> {
    current?: T | undefined | null;
    value?: T | undefined | null;
}
/**
 * @memberof Selecto
 * @typedef
 */
export interface SelectoOptions {
    /**
     * The container to add a selection element for vanilla
     */
    container: HTMLElement | null;
    /**
     * Selecto's root container (No transformed container.)
     * @dfeault null
     */
    rootContainer: HTMLElement | null;
    /**
     * The area to drag selection element.
     * @default container
     */
    dragContainer: Element | Window | Element[] | string | null | undefined;
    /**
     * custom class name of selecto element
     * @default ""
     */
    className: string;
    /**
     * Targets to select. You can register a queryselector or an Element.
     * @default []
     */
    selectableTargets: Array<ElementType | string | (() => ElementType | ElementType[]) | ElementRef<ElementType>>;
    /**
     * Whether to select from the target inside (If hitTest is 0, it becomes inside select as well)
     * @default true
     */
    selectFromInside: boolean;
    /**
     * Whether to force drag end when selectFromInside, selectByClick is true.
     * @default false
     */
    selectByClick: boolean;
    /**
     * When the target is clicked, the event is stopped and selected. (If hitTest is 0, it becomes click as well.)
     * @default true
     */
    preventDragFromInside: boolean;
    /**
     * Whether to click when mouse(touch) ends while using selectByClick(true)
     * @default false
     */
    clickBySelectEnd: boolean;
    /**
     * After the select, whether to select the next target with the selected target (deselected if the target is selected again)
     * @default false
     */
    continueSelect: boolean;
    /**
     * Whether to continue the previously selected items without deselect when using `continueSelect` or `toggleContinueSelect`.
     * @default false
     */
    continueSelectWithoutDeselect: boolean;
    /**
     * Determines which key to continue selecting the next target via keydown and keyup.
     * The initially set `continueSelect` value is the inactive(keyup) value.
     */
    toggleContinueSelect: string[][] | string[] | string | null;
    /**
     * Determines which key to continue selecting the next target without deselect via keydown and keyup.
     * The initially set `continueSelectWithoutDeselect` value is the inactive(keyup) value.
     */
    toggleContinueSelectWithoutDeselect: string[][] | string[] | string | null;
    /**
     * The container for keydown and keyup events.
     */
    keyContainer: Document | HTMLElement | Window | null;
    /**
     * The rate at which the target overlaps the drag area to be selected. If you want an absolute number, set it to a px value. (ex: 10px)
     * @default 100
     */
    hitRate: number | string | ((element: Element) => number | string);
    /**
     * Container to bound the selection area. If false, do not bound. If true, it is the container of selecto.
     * @default false
     */
    boundContainer: BoundContainer | boolean | HTMLElement | string | null;
    /**
     * Set the scroll options, time, etc. to automatically scroll by dragging.
     * @default null
     */
    scrollOptions: DragScrollOptions;
    /**
     * Set the inner scroll options, time, etc. to automatically scroll by dragging.
     * @default null
     */
    innerScrollOptions: boolean | Partial<DragScrollOptions>;
    /**
     * hecks whether this is an element to input text or contentEditable, and prevents dragging.
     * @default false
     */
    checkInput: boolean;
    /**
     * When dragging, preventDefault is called. (Touch occurs unconditionally)
     * @default false
     */
    preventDefault: boolean;
    /**
     * add nonce property to style for CSP
     * @default ""
     */
    cspNonce: string;
    /**
     * Adjust the ratio of the selection.
     * @default 0
     */
    ratio: number;
    /**
     * A function to get the exact position of an element's rect
     * @default null
     */
    getElementRect: getElementRectFunction;
    /**
     * Conditional function to start dragging
     * @default null
     */
    dragCondition: ((e: OnParentDragStart) => boolean) | null;
    /**
     * Prevent click event on drag. (mousemove, touchmove)
     * @default false
     */
    preventClickEventOnDrag?: boolean;
    /**
     * Prevent click event on dragStart. (mousedown, touchstart)
     * @default false
     */
    preventClickEventOnDragStart?: boolean;
    /**
     * Prevent click event according to specific conditions.
     * Returning true allows the click event, returning false prevents it.
     * @default null
     */
    preventClickEventByCondition?: ((e: MouseEvent) => boolean) | null;
    /**
     * Whether to prevent dragging of the right mouse button
     * @default true
     */
    preventRightClick?: boolean;
    /**
     * Selection Element to apply for framework.
     * @private
     */
    portalContainer: HTMLElement | null;
    /**
     * Inspect the overflow area and exclude the outside target from the select.
     * @default false
     */
    checkOverflow: boolean;
}
/**
 * @memberof Selecto
 * @typedef
 */
export interface BoundContainer {
    element: HTMLElement | string | boolean;
    left?: boolean;
    top?: boolean;
    right?: boolean;
    bottom?: boolean;
}

export interface Hypertext {
    tag: string;
    className: string;
    style: IObject<any>;
    attributes: object;
    children: Hypertext[];
}
export interface Rect {
    top: number;
    left: number;
    bottom: number;
    right: number;
    width: number;
    height: number;
}

export interface InnerParentInfo {
    parentElement: HTMLElement;
    points: number[][];
    indexes: number[];
    paths: Element[];
}

export interface Point {
    pos1: number[];
    pos2: number[];
    pos3: number[];
    pos4: number[];
}
/**
 * @memberof Selecto
 * @typedef
 */
export interface CurrentTarget<T = Selecto> {
    /**
     * An Selecto instance itself
     */
    currentTarget: T;
}

/**
 * @memberof Selecto
 * @typedef
 */
export interface SelectedTargets {
    /**
     * before selecting elements
     */
    beforeSelected: Array<HTMLElement | SVGElement>;
    /**
     * selected elements
     */
    selected: Array<HTMLElement | SVGElement>;
    /**
     * added elements
     */
    added: Array<HTMLElement | SVGElement>;
    /**
     * removed elements
     */
    removed: Array<HTMLElement | SVGElement>;
}
/**
 * @memberof Selecto
 * @extends Selecto.SelectedTargets
 * @typedef
 */
export interface SelectedTargetsWithRect extends SelectedTargets {
    /**
     * Rect of Selection Element
     */
    rect: Rect;
}

/**
 * @memberof Selecto
 * @extends Selecto.CurrentTarget
 * @extends Selecto.SelectedTargetsWithRect
 * @typedef
 */
export interface OnSelectEvent<T = Selecto> extends CurrentTarget<T>, SelectedTargetsWithRect {
    /**
     * inputEvent
     */
    inputEvent: any;
    /**
     * Data shared from dragStart, selectStart to dragEnd, selectEnd
     */
    data: Record<string, any>;
    /**
     * Whether it ends as soon as dragStart(mousedown, touchstart)
     */
    isDragStartEnd: boolean;
    /**
     * Whether or not you directly dragged
     */
    isTrusted: boolean;
}
/**
 * @memberof Selecto
 * @extends Selecto.OnSelectEvent
 * @typedef
 */
export interface OnSelect<T = Selecto> extends OnSelectEvent<T> {
    /**
     * start selected elements
     */
    startSelected: Array<HTMLElement | SVGElement>;
    /**
     * added from start selected
     */
    startAdded: Array<HTMLElement | SVGElement>;
    /**
     * removed from start selected
     */
    startRemoved: Array<HTMLElement | SVGElement>;
}
/**
 * @memberof Selecto
 * @extends Selecto.OnSelectEvent
 * @typedef
 */
export interface OnSelectEnd<T = Selecto> extends OnSelectEvent<T> {
    /**
     * start selected elements
     */
    startSelected: Array<HTMLElement | SVGElement>;
    /**
     * after added elements
     */
    afterAdded: Array<HTMLElement | SVGElement>;
    /**
     * after removed elements
     */
    afterRemoved: Array<HTMLElement | SVGElement>;
    /**
     * Whether it is a mousedown or touchstart event
     */
    isDragStart: boolean;
    /**
     * Whether it ends as soon as dragStart(mousedown, touchstart)
     */
    isDragStartEnd: boolean;
    /**
     * Whether it is click
     */
    isClick: boolean;
    /**
     * Wheter it is double click or double start
     */
    isDouble: boolean;
}

export interface OnDragEvent {
    datas: IObject<any>;
    data: IObject<any>;
    clientX: number;
    clientY: number;
    deltaX: number;
    deltaY: number;
    distX: number;
    distY: number;
    isMouseEvent: boolean;
    isSecondaryButton: boolean;
    isClick?: boolean;
    isDouble?: boolean;
    inputEvent: any;
    isTrusted: boolean;
}
export interface OnKeyEvent<T = Selecto> extends CurrentTarget<T> {
    keydownContinueSelect: boolean;
    keydownContinueSelectWithoutDeselection: boolean;
}
export interface OnScroll {
    container: HTMLElement;
    direction: number[];
}
/**
 * @memberof Selecto
 * @typedef
 * @property - Stop all events
 */
export interface OnDragStart<T = Selecto> extends OnParentDragStart<T> {
    stop(): void;
    isClick: boolean;
}

/**
 * @memberof Selecto
 * @typedef
 * @property - Rect of Selection Element
 * @property - Whether it is in select
 */
export interface OnDrag<T = Selecto> extends OnParentDrag<T> {
    rect: Rect;
    isSelect: boolean;
}
/**
 * @memberof Selecto
 * @typedef
 * @property - Rect of Selection Element
 * @property - Whether it is in select
 */
export interface OnDragEnd<T = Selecto> extends OnParentDragEnd<T> {
    rect: Rect;
    isSelect: boolean;
}
export interface SelectoEvents {
    dragStart: OnDragStart;
    drag: OnDrag;
    dragEnd: OnDragEnd;
    selectStart: OnSelect;
    select: OnSelect;
    selectEnd: OnSelectEnd;
    keydown: OnKeyEvent;
    keyup: OnKeyEvent;
    scroll: OnScroll;
    innerScroll: OnScroll;
}
export type SelectoProperties = { [P in typeof PROPERTIES[number]]: SelectoOptions[P] };
export type SelectoMethods = { [P in typeof METHODS[number]]: Selecto[P] };
export type getElementRectFunction = (el: HTMLElement | SVGElement) => PointArea;
export interface PointArea {
    pos1: number[];
    pos2: number[];
    pos3: number[];
    pos4: number[];
}


export interface InnerGroup {
    targets: Array<HTMLElement | SVGElement>;
    points: number[][][];
    inners: boolean[];
}