ngx-drag-to-select
Version:
A lightweight, fast, configurable and reactive drag-to-select component for Angular 8 and beyond
1 lines • 70.5 kB
Source Map (JSON)
{"version":3,"file":"ngx-drag-to-select.mjs","sources":["../../../projects/ngx-drag-to-select/src/lib/config.ts","../../../projects/ngx-drag-to-select/src/lib/constants.ts","../../../projects/ngx-drag-to-select/src/lib/utils.ts","../../../projects/ngx-drag-to-select/src/lib/operators.ts","../../../projects/ngx-drag-to-select/src/lib/keyboard-events.service.ts","../../../projects/ngx-drag-to-select/src/lib/tokens.ts","../../../projects/ngx-drag-to-select/src/lib/select-item.directive.ts","../../../projects/ngx-drag-to-select/src/lib/models.ts","../../../projects/ngx-drag-to-select/src/lib/shortcut.service.ts","../../../projects/ngx-drag-to-select/src/lib/select-container.component.ts","../../../projects/ngx-drag-to-select/src/lib/drag-to-select.module.ts","../../../projects/ngx-drag-to-select/src/public_api.ts","../../../projects/ngx-drag-to-select/src/ngx-drag-to-select.ts"],"sourcesContent":["import { DragToSelectConfig } from './models';\n\nexport const DEFAULT_CONFIG: DragToSelectConfig = {\n selectedClass: 'selected',\n shortcuts: {\n moveRangeStart: 'shift+r',\n disableSelection: 'alt',\n toggleSingleItem: 'meta',\n addToSelection: 'shift',\n removeFromSelection: 'shift+meta',\n },\n};\n","export const AUDIT_TIME = 16;\nexport const MIN_WIDTH = 5;\nexport const MIN_HEIGHT = 5;\nexport const NO_SELECT_CLASS = 'dts-no-select';\n","import { MIN_HEIGHT, MIN_WIDTH } from './constants';\nimport { BoundingBox, MousePosition, SelectBox, SelectContainerHost } from './models';\n\nexport const isObject = (item: any) => {\n return item && typeof item === 'object' && !Array.isArray(item) && item !== null;\n};\n\nexport function mergeDeep(target: Record<string, any>, source: Record<string, any>) {\n if (isObject(target) && isObject(source)) {\n Object.keys(source).forEach((key) => {\n if (isObject(source[key])) {\n if (!target[key]) {\n Object.assign(target, { [key]: {} });\n }\n mergeDeep(target[key], source[key]);\n } else {\n Object.assign(target, { [key]: source[key] });\n }\n });\n }\n\n return target;\n}\n\nexport const hasMinimumSize = (selectBox: SelectBox<number>, minWidth = MIN_WIDTH, minHeight = MIN_HEIGHT) => {\n return selectBox.width > minWidth || selectBox.height > minHeight;\n};\n\nexport const clearSelection = (window: Window) => {\n const selection = window.getSelection();\n\n if (!selection) {\n return;\n }\n\n if (selection.removeAllRanges) {\n selection.removeAllRanges();\n } else if (selection.empty) {\n selection.empty();\n }\n};\n\nexport const inBoundingBox = (point: MousePosition, box: BoundingBox) => {\n return (\n box.left <= point.x && point.x <= box.left + box.width && box.top <= point.y && point.y <= box.top + box.height\n );\n};\n\nexport const boxIntersects = (boxA: BoundingBox, boxB: BoundingBox) => {\n return (\n boxA.left <= boxB.left + boxB.width &&\n boxA.left + boxA.width >= boxB.left &&\n boxA.top <= boxB.top + boxB.height &&\n boxA.top + boxA.height >= boxB.top\n );\n};\n\nexport const calculateBoundingClientRect = (element: HTMLElement): BoundingBox => {\n return element.getBoundingClientRect();\n};\n\nexport const getMousePosition = (event: MouseEvent) => {\n return {\n x: event.clientX,\n y: event.clientY,\n };\n};\n\nexport const getScroll = () => {\n if (!document || !document.documentElement) {\n return {\n x: 0,\n y: 0,\n };\n }\n\n return {\n x: document.documentElement.scrollLeft || document.body.scrollLeft,\n y: document.documentElement.scrollTop || document.body.scrollTop,\n };\n};\n\nexport const getRelativeMousePosition = (event: MouseEvent, container: SelectContainerHost): MousePosition => {\n const { x: clientX, y: clientY } = getMousePosition(event);\n const scroll = getScroll();\n\n const borderSize = (container.boundingClientRect.width - container.clientWidth) / 2;\n const offsetLeft = container.boundingClientRect.left + scroll.x;\n const offsetTop = container.boundingClientRect.top + scroll.y;\n\n return {\n x: clientX - borderSize - (offsetLeft - window.pageXOffset) + container.scrollLeft,\n y: clientY - borderSize - (offsetTop - window.pageYOffset) + container.scrollTop,\n };\n};\n\nexport const cursorWithinElement = (event: MouseEvent, element: HTMLElement) => {\n const mousePoint = getMousePosition(event);\n return inBoundingBox(mousePoint, calculateBoundingClientRect(element));\n};\n","import { Observable } from 'rxjs';\nimport { distinctUntilChanged, filter, map, withLatestFrom } from 'rxjs/operators';\nimport { MousePosition, SelectBox, SelectBoxInput, SelectContainerHost } from './models';\nimport { getRelativeMousePosition, hasMinimumSize } from './utils';\n\nexport const createSelectBox = (container: SelectContainerHost) => {\n return (source: Observable<SelectBoxInput>): Observable<SelectBox<number>> => {\n return source.pipe(\n map(([event, opacity, { x, y }]) => {\n // Type annotation is required here, because `getRelativeMousePosition` returns a `MousePosition`,\n // the TS compiler cannot figure out the shape of this type.\n const mousePosition: MousePosition = getRelativeMousePosition(event, container);\n\n const width = opacity > 0 ? mousePosition.x - x : 0;\n const height = opacity > 0 ? mousePosition.y - y : 0;\n\n return {\n top: height < 0 ? mousePosition.y : y,\n left: width < 0 ? mousePosition.x : x,\n width: Math.abs(width),\n height: Math.abs(height),\n opacity,\n };\n })\n );\n };\n};\n\nexport const whenSelectBoxVisible = (selectBox$: Observable<SelectBox<number>>) => (source: Observable<Event>) =>\n source.pipe(\n withLatestFrom(selectBox$),\n filter(([, selectBox]) => hasMinimumSize(selectBox, 0, 0)),\n map(([event, _]) => event)\n );\n\nexport const distinctKeyEvents = () => (source: Observable<KeyboardEvent>) =>\n source.pipe(\n distinctUntilChanged((prev, curr) => {\n return prev && curr && prev.code === curr.code;\n })\n );\n","import { isPlatformBrowser } from '@angular/common';\nimport { Inject, Injectable, PLATFORM_ID } from '@angular/core';\nimport { fromEvent, Observable } from 'rxjs';\nimport { share } from 'rxjs/operators';\nimport { distinctKeyEvents } from './operators';\n\n@Injectable()\nexport class KeyboardEventsService {\n keydown$: Observable<KeyboardEvent>;\n keyup$: Observable<KeyboardEvent>;\n distinctKeydown$: Observable<KeyboardEvent>;\n distinctKeyup$: Observable<KeyboardEvent>;\n mouseup$: Observable<MouseEvent>;\n mousemove$: Observable<MouseEvent>;\n\n constructor(@Inject(PLATFORM_ID) private platformId: Record<string, unknown>) {\n if (isPlatformBrowser(this.platformId)) {\n this._initializeKeyboardStreams();\n }\n }\n\n private _initializeKeyboardStreams() {\n this.keydown$ = fromEvent<KeyboardEvent>(window, 'keydown').pipe(share());\n this.keyup$ = fromEvent<KeyboardEvent>(window, 'keyup').pipe(share());\n\n // distinctKeyEvents is used to prevent multiple key events to be fired repeatedly\n // on Windows when a key is being pressed\n\n this.distinctKeydown$ = this.keydown$.pipe(distinctKeyEvents(), share());\n\n this.distinctKeyup$ = this.keyup$.pipe(distinctKeyEvents(), share());\n\n this.mouseup$ = fromEvent<MouseEvent>(window, 'mouseup').pipe(share());\n this.mousemove$ = fromEvent<MouseEvent>(window, 'mousemove').pipe(share());\n }\n}\n","import { InjectionToken } from '@angular/core';\nimport { DragToSelectConfig } from './models';\n\nexport const CONFIG = new InjectionToken<DragToSelectConfig>('DRAG_TO_SELECT_CONFIG');\nexport const USER_CONFIG = new InjectionToken<DragToSelectConfig>('USER_CONFIG');\n","import { isPlatformBrowser } from '@angular/common';\n\nimport {\n Directive,\n DoCheck,\n ElementRef,\n Inject,\n Input,\n PLATFORM_ID,\n Renderer2,\n OnInit,\n HostBinding,\n} from '@angular/core';\n\nimport { DragToSelectConfig, BoundingBox } from './models';\nimport { CONFIG } from './tokens';\nimport { calculateBoundingClientRect } from './utils';\n\nexport const SELECT_ITEM_INSTANCE = Symbol();\n\n@Directive({\n selector: '[dtsSelectItem]',\n exportAs: 'dtsSelectItem',\n})\nexport class SelectItemDirective implements OnInit, DoCheck {\n private _boundingClientRect: BoundingBox | undefined;\n\n selected = false;\n\n @HostBinding('class.dts-range-start')\n rangeStart = false;\n\n @HostBinding('class.dts-select-item')\n readonly hostClass = true;\n\n @Input() dtsSelectItem: any | undefined;\n\n @Input()\n @HostBinding('class.dts-disabled')\n dtsDisabled = false;\n\n get value(): SelectItemDirective | any {\n return this.dtsSelectItem ? this.dtsSelectItem : this;\n }\n\n constructor(\n @Inject(CONFIG) private config: DragToSelectConfig,\n @Inject(PLATFORM_ID) private platformId: Record<string, unknown>,\n private host: ElementRef,\n private renderer: Renderer2\n ) {}\n\n ngOnInit() {\n this.nativeElememnt[SELECT_ITEM_INSTANCE] = this;\n }\n\n ngDoCheck() {\n this.applySelectedClass();\n }\n\n toggleRangeStart() {\n this.rangeStart = !this.rangeStart;\n }\n\n get nativeElememnt() {\n return this.host.nativeElement;\n }\n\n getBoundingClientRect() {\n if (isPlatformBrowser(this.platformId) && !this._boundingClientRect) {\n this.calculateBoundingClientRect();\n }\n return this._boundingClientRect;\n }\n\n calculateBoundingClientRect() {\n const boundingBox = calculateBoundingClientRect(this.host.nativeElement);\n this._boundingClientRect = boundingBox;\n return boundingBox;\n }\n\n _select() {\n this.selected = true;\n }\n\n _deselect() {\n this.selected = false;\n }\n\n private applySelectedClass() {\n if (this.selected) {\n this.renderer.addClass(this.host.nativeElement, this.config.selectedClass);\n } else {\n this.renderer.removeClass(this.host.nativeElement, this.config.selectedClass);\n }\n }\n}\n","import { Observable } from 'rxjs';\nimport { SelectItemDirective } from './select-item.directive';\n\nexport type PredicateFn<T> = (item: T) => boolean;\n\nexport enum UpdateActions {\n Add,\n Remove,\n}\n\nexport interface UpdateAction {\n type: UpdateActions;\n item: SelectItemDirective;\n}\n\nexport interface ObservableProxy<T> {\n proxy$: Observable<any>;\n proxy: T;\n}\n\nexport interface SelectContainerHost extends HTMLElement {\n boundingClientRect: BoundingBox;\n}\n\nexport interface Shortcuts {\n moveRangeStart: string;\n disableSelection: string;\n toggleSingleItem: string;\n addToSelection: string;\n removeFromSelection: string;\n}\n\nexport interface DragToSelectConfig {\n selectedClass: string;\n shortcuts: Partial<Shortcuts>;\n}\n\nexport interface MousePosition {\n x: number;\n y: number;\n}\n\nexport interface BoundingBox {\n top: number;\n left: number;\n width: number;\n height: number;\n}\n\nexport type SelectBoxInput = [MouseEvent, number, MousePosition];\n\nexport interface SelectBox<T> {\n top: T;\n left: T;\n width: T;\n height: T;\n opacity: number;\n}\n\nexport enum Action {\n Add,\n Delete,\n None,\n}\n","import { isPlatformBrowser } from '@angular/common';\nimport { Inject, Injectable, PLATFORM_ID } from '@angular/core';\nimport { merge } from 'rxjs';\nimport { distinctUntilChanged, map } from 'rxjs/operators';\nimport { KeyboardEventsService } from './keyboard-events.service';\nimport { DragToSelectConfig } from './models';\nimport { CONFIG } from './tokens';\n\nconst SUPPORTED_META_KEYS = {\n alt: true,\n shift: true,\n meta: true,\n ctrl: true,\n};\n\nconst SUPPORTED_KEYS = /[a-z]/;\n\nconst META_KEY = 'meta';\n\nconst KEY_ALIASES = {\n [META_KEY]: ['ctrl', 'meta'],\n};\n\nconst SUPPORTED_SHORTCUTS = {\n moveRangeStart: true,\n disableSelection: true,\n toggleSingleItem: true,\n addToSelection: true,\n removeFromSelection: true,\n};\n\nconst ERROR_PREFIX = '[ShortcutService]';\n\ninterface KeyState {\n code: string;\n pressed: boolean;\n}\n\n@Injectable()\nexport class ShortcutService {\n private _shortcuts: { [key: string]: string[][] } = {};\n\n private _latestShortcut: Map<string, boolean> = new Map();\n\n constructor(\n @Inject(PLATFORM_ID) private platformId: Record<string, unknown>,\n @Inject(CONFIG) config: DragToSelectConfig,\n private keyboardEvents: KeyboardEventsService\n ) {\n this._shortcuts = this._createShortcutsFromConfig(config.shortcuts);\n\n if (isPlatformBrowser(this.platformId)) {\n const keydown$ = this.keyboardEvents.keydown$.pipe(\n map<KeyboardEvent, KeyState>((event) => ({ code: event.code, pressed: true }))\n );\n\n const keyup$ = this.keyboardEvents.keyup$.pipe(\n map<KeyboardEvent, KeyState>((event) => ({ code: event.code, pressed: false }))\n );\n\n merge<KeyState>(keydown$, keyup$)\n .pipe(\n distinctUntilChanged((prev, curr) => {\n return prev.pressed === curr.pressed && prev.code === curr.code;\n })\n )\n .subscribe((keyState) => {\n if (keyState.pressed) {\n this._latestShortcut.set(keyState.code, true);\n } else {\n this._latestShortcut.delete(keyState.code);\n }\n });\n }\n }\n\n disableSelection(event: Event) {\n return this._isShortcutPressed('disableSelection', event);\n }\n\n moveRangeStart(event: Event) {\n return this._isShortcutPressed('moveRangeStart', event);\n }\n\n toggleSingleItem(event: Event) {\n return this._isShortcutPressed('toggleSingleItem', event);\n }\n\n addToSelection(event: Event) {\n return this._isShortcutPressed('addToSelection', event);\n }\n\n removeFromSelection(event: Event) {\n return this._isShortcutPressed('removeFromSelection', event);\n }\n\n extendedSelectionShortcut(event: Event) {\n return this.addToSelection(event) || this.removeFromSelection(event);\n }\n\n private _createShortcutsFromConfig(shortcuts: { [key: string]: string }) {\n const shortcutMap = {};\n\n for (const [key, shortcutsForCommand] of Object.entries(shortcuts)) {\n if (!this._isSupportedShortcut(key)) {\n throw new Error(this._getErrorMessage(`Shortcut ${key} not supported`));\n }\n\n shortcutsForCommand\n .replace(/ /g, '')\n .split(',')\n .forEach((shortcut) => {\n if (!shortcutMap[key]) {\n shortcutMap[key] = [];\n }\n\n const combo = shortcut.split('+');\n const cleanCombos = this._substituteKey(shortcut, combo, META_KEY);\n\n cleanCombos.forEach((cleanCombo) => {\n const unsupportedKey = this._isSupportedCombo(cleanCombo);\n\n if (unsupportedKey) {\n throw new Error(this._getErrorMessage(`Key '${unsupportedKey}' in shortcut ${shortcut} not supported`));\n }\n\n shortcutMap[key].push(\n cleanCombo.map((comboKey) => {\n return SUPPORTED_META_KEYS[comboKey] ? `${comboKey}Key` : `Key${comboKey.toUpperCase()}`;\n })\n );\n });\n });\n }\n\n return shortcutMap;\n }\n\n private _substituteKey(shortcut: string, combo: Array<string>, substituteKey: string) {\n const hasSpecialKey = shortcut.includes(substituteKey);\n const substitutedShortcut: string[][] = [];\n\n if (hasSpecialKey) {\n const cleanShortcut = combo.filter((element) => element !== META_KEY);\n\n KEY_ALIASES.meta.forEach((alias) => {\n substitutedShortcut.push([...cleanShortcut, alias]);\n });\n } else {\n substitutedShortcut.push(combo);\n }\n\n return substitutedShortcut;\n }\n\n private _getErrorMessage(message: string) {\n return `${ERROR_PREFIX} ${message}`;\n }\n\n private _isShortcutPressed(shortcutName: string, event: Event) {\n const shortcuts = this._shortcuts[shortcutName];\n\n return shortcuts.some((shortcut) => {\n return shortcut.every((key) => this._isKeyPressed(event, key));\n });\n }\n\n private _isKeyPressed(event: Event, key: string) {\n return key.startsWith('Key') ? this._latestShortcut.has(key) : event[key];\n }\n\n private _isSupportedCombo(combo: Array<string>) {\n let unsupportedKey = null;\n\n combo.forEach((key) => {\n if (!SUPPORTED_META_KEYS[key] && (!SUPPORTED_KEYS.test(key) || this._isSingleChar(key))) {\n unsupportedKey = key;\n return;\n }\n });\n\n return unsupportedKey;\n }\n\n private _isSingleChar(key: string) {\n return key.length > 1;\n }\n\n private _isSupportedShortcut(shortcut: string) {\n return SUPPORTED_SHORTCUTS[shortcut];\n }\n}\n","import {\n Component,\n ElementRef,\n Output,\n EventEmitter,\n Input,\n OnDestroy,\n Renderer2,\n ViewChild,\n NgZone,\n ContentChildren,\n QueryList,\n HostBinding,\n AfterViewInit,\n PLATFORM_ID,\n Inject,\n AfterContentInit,\n} from '@angular/core';\n\nimport { isPlatformBrowser } from '@angular/common';\n\nimport { Observable, Subject, combineLatest, merge, from, fromEvent, BehaviorSubject, asyncScheduler } from 'rxjs';\n\nimport {\n switchMap,\n takeUntil,\n map,\n tap,\n filter,\n auditTime,\n mapTo,\n share,\n withLatestFrom,\n distinctUntilChanged,\n observeOn,\n startWith,\n concatMapTo,\n first,\n} from 'rxjs/operators';\n\nimport { SelectItemDirective, SELECT_ITEM_INSTANCE } from './select-item.directive';\nimport { ShortcutService } from './shortcut.service';\n\nimport { createSelectBox, whenSelectBoxVisible, distinctKeyEvents } from './operators';\n\nimport {\n Action,\n SelectBox,\n MousePosition,\n SelectContainerHost,\n UpdateAction,\n UpdateActions,\n PredicateFn,\n BoundingBox,\n} from './models';\n\nimport { AUDIT_TIME, NO_SELECT_CLASS } from './constants';\n\nimport {\n inBoundingBox,\n cursorWithinElement,\n clearSelection,\n boxIntersects,\n calculateBoundingClientRect,\n getRelativeMousePosition,\n getMousePosition,\n hasMinimumSize,\n} from './utils';\nimport { KeyboardEventsService } from './keyboard-events.service';\n\n@Component({\n selector: 'dts-select-container',\n exportAs: 'dts-select-container',\n template: `\n <ng-content></ng-content>\n <div\n class=\"dts-select-box\"\n #selectBox\n [ngClass]=\"selectBoxClasses$ | async\"\n [ngStyle]=\"selectBoxStyles$ | async\"\n ></div>\n `,\n styleUrls: ['./select-container.component.scss'],\n})\nexport class SelectContainerComponent implements AfterViewInit, OnDestroy, AfterContentInit {\n host: SelectContainerHost;\n selectBoxStyles$: Observable<SelectBox<string>>;\n selectBoxClasses$: Observable<{ [key: string]: boolean }>;\n\n @ViewChild('selectBox', { static: true })\n private $selectBox: ElementRef;\n\n @ContentChildren(SelectItemDirective, { descendants: true })\n private $selectableItems: QueryList<SelectItemDirective>;\n\n @Input() selectedItems: any;\n @Input() selectOnDrag = true;\n @Input() disabled = false;\n @Input() disableDrag = false;\n @Input() selectOnClick = true;\n @Input() dragOverItems = true;\n @Input() disableRangeSelection = false;\n @Input() selectMode = false;\n @Input() selectWithShortcut = false;\n\n @Input()\n @HostBinding('class.dts-custom')\n custom = false;\n\n @HostBinding('class.dts-select-container')\n readonly hostClass = true;\n\n @Output()\n selectedItemsChange = new EventEmitter<any>();\n @Output() select = new EventEmitter<any>();\n @Output() itemSelected = new EventEmitter<any>();\n @Output() itemDeselected = new EventEmitter<any>();\n @Output() selectionStarted = new EventEmitter<void>();\n @Output() selectionEnded = new EventEmitter<Array<any>>();\n\n private _tmpItems = new Map<SelectItemDirective, Action>();\n\n private _selectedItems$ = new BehaviorSubject<Array<any>>([]);\n private _selectableItems: Array<SelectItemDirective> = [];\n private updateItems$ = new Subject<UpdateAction>();\n private destroy$ = new Subject<void>();\n\n private _lastRange: [number, number] = [-1, -1];\n private _lastStartIndex: number | undefined = undefined;\n private _newRangeStart = false;\n private _lastRangeSelection: Map<SelectItemDirective, boolean> = new Map();\n\n constructor(\n @Inject(PLATFORM_ID) private platformId: Record<string, unknown>,\n private shortcuts: ShortcutService,\n private keyboardEvents: KeyboardEventsService,\n private hostElementRef: ElementRef,\n private renderer: Renderer2,\n private ngZone: NgZone\n ) {}\n\n ngAfterViewInit() {\n if (isPlatformBrowser(this.platformId)) {\n this.host = this.hostElementRef.nativeElement;\n\n this._initSelectedItemsChange();\n\n this._calculateBoundingClientRect();\n this._observeBoundingRectChanges();\n this._observeSelectableItems();\n\n const mouseup$ = this.keyboardEvents.mouseup$.pipe(\n filter(() => !this.disabled),\n tap(() => this._onMouseUp()),\n share()\n );\n\n const mousemove$ = this.keyboardEvents.mousemove$.pipe(\n filter(() => !this.disabled),\n share()\n );\n\n const mousedown$ = fromEvent<MouseEvent>(this.host, 'mousedown').pipe(\n filter((event) => event.button === 0), // only emit left mouse\n filter(() => !this.disabled),\n filter((event) => this.selectOnClick || event.target === this.host),\n tap((event) => this._onMouseDown(event)),\n share()\n );\n\n const dragging$ = mousedown$.pipe(\n filter((event) => !this.shortcuts.disableSelection(event)),\n filter(() => !this.selectMode),\n filter(() => !this.disableDrag),\n filter((event) => this.dragOverItems || event.target === this.host),\n switchMap(() => mousemove$.pipe(takeUntil(mouseup$))),\n share()\n );\n\n const currentMousePosition$: Observable<MousePosition> = mousedown$.pipe(\n map((event: MouseEvent) => getRelativeMousePosition(event, this.host))\n );\n\n const show$ = dragging$.pipe(mapTo(1));\n const hide$ = mouseup$.pipe(mapTo(0));\n const opacity$ = merge(show$, hide$).pipe(distinctUntilChanged());\n\n const selectBox$ = combineLatest([dragging$, opacity$, currentMousePosition$]).pipe(\n createSelectBox(this.host),\n share()\n );\n\n this.selectBoxClasses$ = merge(\n dragging$,\n mouseup$,\n this.keyboardEvents.distinctKeydown$,\n this.keyboardEvents.distinctKeyup$\n ).pipe(\n auditTime(AUDIT_TIME),\n withLatestFrom(selectBox$),\n map(([event, selectBox]) => {\n return {\n 'dts-adding': hasMinimumSize(selectBox, 0, 0) && !this.shortcuts.removeFromSelection(event),\n 'dts-removing': this.shortcuts.removeFromSelection(event),\n };\n }),\n distinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b))\n );\n\n const selectOnMouseUp$ = dragging$.pipe(\n filter(() => !this.selectOnDrag),\n filter(() => !this.selectMode),\n filter((event) => this._cursorWithinHost(event)),\n switchMap((_) => mouseup$.pipe(first())),\n filter(\n (event) =>\n (!this.shortcuts.disableSelection(event) && !this.shortcuts.toggleSingleItem(event)) ||\n this.shortcuts.removeFromSelection(event)\n )\n );\n\n const selectOnDrag$ = selectBox$.pipe(\n auditTime(AUDIT_TIME),\n withLatestFrom(mousemove$, (selectBox, event: MouseEvent) => ({\n selectBox,\n event,\n })),\n filter(() => this.selectOnDrag),\n filter(({ selectBox }) => hasMinimumSize(selectBox)),\n map(({ event }) => event)\n );\n\n const selectOnKeyboardEvent$ = merge(\n this.keyboardEvents.distinctKeydown$,\n this.keyboardEvents.distinctKeyup$\n ).pipe(\n auditTime(AUDIT_TIME),\n whenSelectBoxVisible(selectBox$),\n tap((event) => {\n if (this._isExtendedSelection(event)) {\n this._tmpItems.clear();\n } else {\n this._flushItems();\n }\n })\n );\n\n merge(selectOnMouseUp$, selectOnDrag$, selectOnKeyboardEvent$)\n .pipe(takeUntil(this.destroy$))\n .subscribe((event) => this._selectItems(event));\n\n this.selectBoxStyles$ = selectBox$.pipe(\n map((selectBox) => ({\n top: `${selectBox.top}px`,\n left: `${selectBox.left}px`,\n width: `${selectBox.width}px`,\n height: `${selectBox.height}px`,\n opacity: selectBox.opacity,\n }))\n );\n\n this._initSelectionOutputs(mousedown$, mouseup$);\n }\n }\n\n ngAfterContentInit() {\n this._selectableItems = this.$selectableItems.toArray();\n }\n\n selectAll() {\n this.$selectableItems.forEach((item) => {\n this._selectItem(item);\n });\n }\n\n toggleItems<T>(predicate: PredicateFn<T>) {\n this._filterSelectableItems(predicate).subscribe((item: SelectItemDirective) => this._toggleItem(item));\n }\n\n selectItems<T>(predicate: PredicateFn<T>) {\n this._filterSelectableItems(predicate).subscribe((item: SelectItemDirective) => this._selectItem(item));\n }\n\n deselectItems<T>(predicate: PredicateFn<T>) {\n this._filterSelectableItems(predicate).subscribe((item: SelectItemDirective) => this._deselectItem(item));\n }\n\n clearSelection() {\n this.$selectableItems.forEach((item) => {\n this._deselectItem(item);\n });\n }\n\n update() {\n this._calculateBoundingClientRect();\n this.$selectableItems.forEach((item) => item.calculateBoundingClientRect());\n }\n\n ngOnDestroy() {\n this.destroy$.next();\n this.destroy$.complete();\n }\n\n private _filterSelectableItems<T>(predicate: PredicateFn<T>) {\n // Wrap select items in an observable for better efficiency as\n // no intermediate arrays are created and we only need to process\n // every item once.\n return from(this._selectableItems).pipe(filter((item) => predicate(item.value)));\n }\n\n private _initSelectedItemsChange() {\n this._selectedItems$.pipe(auditTime(AUDIT_TIME), takeUntil(this.destroy$)).subscribe({\n next: (selectedItems) => {\n this.selectedItemsChange.emit(selectedItems);\n this.select.emit(selectedItems);\n },\n complete: () => {\n this.selectedItemsChange.emit([]);\n },\n });\n }\n\n private _observeSelectableItems() {\n // Listen for updates and either select or deselect an item\n this.updateItems$\n .pipe(\n withLatestFrom(this._selectedItems$),\n takeUntil(this.destroy$),\n filter(([update]) => !update.item.dtsDisabled)\n )\n .subscribe(([update, selectedItems]: [UpdateAction, any[]]) => {\n const item = update.item;\n\n switch (update.type) {\n case UpdateActions.Add:\n if (this._addItem(item, selectedItems)) {\n item._select();\n }\n break;\n case UpdateActions.Remove:\n if (this._removeItem(item, selectedItems)) {\n item._deselect();\n }\n break;\n }\n });\n\n // Update the container as well as all selectable items if the list has changed\n this.$selectableItems.changes\n .pipe(withLatestFrom(this._selectedItems$), observeOn(asyncScheduler), takeUntil(this.destroy$))\n .subscribe(([items, selectedItems]: [QueryList<SelectItemDirective>, any[]]) => {\n const newList = items.toArray();\n this._selectableItems = newList;\n const newValues = newList.map((item) => item.value);\n const removedItems = selectedItems.filter((item) => !newValues.includes(item));\n\n if (removedItems.length) {\n removedItems.forEach((item) => this._removeItem(item, selectedItems));\n }\n\n this.update();\n });\n }\n\n private _observeBoundingRectChanges() {\n this.ngZone.runOutsideAngular(() => {\n const resize$ = fromEvent(window, 'resize');\n const windowScroll$ = fromEvent(window, 'scroll');\n const containerScroll$ = fromEvent(this.host, 'scroll');\n\n merge(resize$, windowScroll$, containerScroll$)\n .pipe(startWith('INITIAL_UPDATE'), auditTime(AUDIT_TIME), takeUntil(this.destroy$))\n .subscribe(() => {\n this.update();\n });\n });\n }\n\n private _initSelectionOutputs(mousedown$: Observable<MouseEvent>, mouseup$: Observable<MouseEvent>) {\n mousedown$\n .pipe(\n filter((event) => this._cursorWithinHost(event)),\n tap(() => this.selectionStarted.emit()),\n concatMapTo(mouseup$.pipe(first())),\n withLatestFrom(this._selectedItems$),\n map(([, items]) => items),\n takeUntil(this.destroy$)\n )\n .subscribe((items) => {\n this.selectionEnded.emit(items);\n });\n }\n\n private _calculateBoundingClientRect() {\n this.host.boundingClientRect = calculateBoundingClientRect(this.host);\n }\n\n private _cursorWithinHost(event: MouseEvent) {\n return cursorWithinElement(event, this.host);\n }\n\n private _onMouseUp() {\n this._flushItems();\n this.renderer.removeClass(document.body, NO_SELECT_CLASS);\n }\n\n private _onMouseDown(event: MouseEvent) {\n if (this.shortcuts.disableSelection(event) || this.disabled) {\n return;\n }\n\n clearSelection(window);\n\n if (!this.disableDrag) {\n this.renderer.addClass(document.body, NO_SELECT_CLASS);\n }\n\n if (this.shortcuts.removeFromSelection(event)) {\n return;\n }\n\n const mousePoint = getMousePosition(event);\n const [currentIndex, clickedItem] = this._getClosestSelectItem(event);\n\n let [startIndex, endIndex] = this._lastRange;\n\n const isMoveRangeStart = this.shortcuts.moveRangeStart(event);\n\n const shouldResetRangeSelection =\n !this.shortcuts.extendedSelectionShortcut(event) || isMoveRangeStart || this.disableRangeSelection;\n\n if (shouldResetRangeSelection) {\n this._resetRangeStart();\n }\n\n // move range start\n if (shouldResetRangeSelection && !this.disableRangeSelection) {\n if (currentIndex > -1) {\n this._newRangeStart = true;\n this._lastStartIndex = currentIndex;\n clickedItem.toggleRangeStart();\n\n this._lastRangeSelection.clear();\n } else {\n this._lastStartIndex = -1;\n }\n }\n\n if (currentIndex > -1) {\n startIndex = Math.min(this._lastStartIndex, currentIndex);\n endIndex = Math.max(this._lastStartIndex, currentIndex);\n this._lastRange = [startIndex, endIndex];\n }\n\n if (isMoveRangeStart) {\n return;\n }\n\n this.$selectableItems.forEach((item, index) => {\n const itemRect = item.getBoundingClientRect();\n const withinBoundingBox = inBoundingBox(mousePoint, itemRect);\n\n if (this.shortcuts.extendedSelectionShortcut(event) && this.disableRangeSelection) {\n return;\n }\n\n const withinRange =\n this.shortcuts.extendedSelectionShortcut(event) &&\n startIndex > -1 &&\n endIndex > -1 &&\n index >= startIndex &&\n index <= endIndex &&\n startIndex !== endIndex;\n\n const shouldAdd =\n (withinBoundingBox &&\n !this.shortcuts.toggleSingleItem(event) &&\n !this.selectMode &&\n !this.selectWithShortcut) ||\n (this.shortcuts.extendedSelectionShortcut(event) && item.selected && !this._lastRangeSelection.get(item)) ||\n withinRange ||\n (withinBoundingBox && this.shortcuts.toggleSingleItem(event) && !item.selected) ||\n (!withinBoundingBox && this.shortcuts.toggleSingleItem(event) && item.selected) ||\n (withinBoundingBox && !item.selected && this.selectMode) ||\n (!withinBoundingBox && item.selected && this.selectMode);\n\n const shouldRemove =\n (!withinBoundingBox &&\n !this.shortcuts.toggleSingleItem(event) &&\n !this.selectMode &&\n !this.shortcuts.extendedSelectionShortcut(event) &&\n !this.selectWithShortcut) ||\n (this.shortcuts.extendedSelectionShortcut(event) && currentIndex > -1) ||\n (!withinBoundingBox && this.shortcuts.toggleSingleItem(event) && !item.selected) ||\n (withinBoundingBox && this.shortcuts.toggleSingleItem(event) && item.selected) ||\n (!withinBoundingBox && !item.selected && this.selectMode) ||\n (withinBoundingBox && item.selected && this.selectMode);\n\n if (shouldAdd) {\n this._selectItem(item);\n } else if (shouldRemove) {\n this._deselectItem(item);\n }\n\n if (withinRange && !this._lastRangeSelection.get(item)) {\n this._lastRangeSelection.set(item, true);\n } else if (!withinRange && !this._newRangeStart && !item.selected) {\n this._lastRangeSelection.delete(item);\n }\n });\n\n // if we don't toggle a single item, we set `newRangeStart` to `false`\n // meaning that we are building up a range\n if (!this.shortcuts.toggleSingleItem(event)) {\n this._newRangeStart = false;\n }\n }\n\n private _selectItems(event: Event) {\n const selectionBox = calculateBoundingClientRect(this.$selectBox.nativeElement);\n\n this.$selectableItems.forEach((item, index) => {\n if (this._isExtendedSelection(event)) {\n this._extendedSelectionMode(selectionBox, item, event);\n } else {\n this._normalSelectionMode(selectionBox, item, event);\n\n if (this._lastStartIndex < 0 && item.selected) {\n item.toggleRangeStart();\n this._lastStartIndex = index;\n }\n }\n });\n }\n\n private _isExtendedSelection(event: Event) {\n return this.shortcuts.extendedSelectionShortcut(event) && this.selectOnDrag;\n }\n\n private _normalSelectionMode(selectBox: BoundingBox, item: SelectItemDirective, event: Event) {\n const inSelection = boxIntersects(selectBox, item.getBoundingClientRect());\n\n const shouldAdd = inSelection && !item.selected && !this.shortcuts.removeFromSelection(event);\n\n const shouldRemove =\n (!inSelection && item.selected && !this.shortcuts.addToSelection(event)) ||\n (inSelection && item.selected && this.shortcuts.removeFromSelection(event));\n\n if (shouldAdd) {\n this._selectItem(item);\n } else if (shouldRemove) {\n this._deselectItem(item);\n }\n }\n\n private _extendedSelectionMode(selectBox, item: SelectItemDirective, event: Event) {\n const inSelection = boxIntersects(selectBox, item.getBoundingClientRect());\n\n const shoudlAdd =\n (inSelection && !item.selected && !this.shortcuts.removeFromSelection(event) && !this._tmpItems.has(item)) ||\n (inSelection && item.selected && this.shortcuts.removeFromSelection(event) && !this._tmpItems.has(item));\n\n const shouldRemove =\n (!inSelection && item.selected && this.shortcuts.addToSelection(event) && this._tmpItems.has(item)) ||\n (!inSelection && !item.selected && this.shortcuts.removeFromSelection(event) && this._tmpItems.has(item));\n\n if (shoudlAdd) {\n if (item.selected) {\n item._deselect();\n } else {\n item._select();\n }\n\n const action = this.shortcuts.removeFromSelection(event)\n ? Action.Delete\n : this.shortcuts.addToSelection(event)\n ? Action.Add\n : Action.None;\n\n this._tmpItems.set(item, action);\n } else if (shouldRemove) {\n if (this.shortcuts.removeFromSelection(event)) {\n item._select();\n } else {\n item._deselect();\n }\n\n this._tmpItems.delete(item);\n }\n }\n\n private _flushItems() {\n this._tmpItems.forEach((action, item) => {\n if (action === Action.Add) {\n this._selectItem(item);\n }\n\n if (action === Action.Delete) {\n this._deselectItem(item);\n }\n });\n\n this._tmpItems.clear();\n }\n\n private _addItem(item: SelectItemDirective, selectedItems: Array<any>) {\n let success = false;\n\n if (!this._hasItem(item, selectedItems)) {\n success = true;\n selectedItems.push(item.value);\n this._selectedItems$.next(selectedItems);\n this.itemSelected.emit(item.value);\n }\n\n return success;\n }\n\n private _removeItem(item: SelectItemDirective, selectedItems: Array<any>) {\n let success = false;\n const value = item instanceof SelectItemDirective ? item.value : item;\n const index = selectedItems.indexOf(value);\n\n if (index > -1) {\n success = true;\n selectedItems.splice(index, 1);\n this._selectedItems$.next(selectedItems);\n this.itemDeselected.emit(value);\n }\n\n return success;\n }\n\n private _toggleItem(item: SelectItemDirective) {\n if (item.selected) {\n this._deselectItem(item);\n } else {\n this._selectItem(item);\n }\n }\n\n private _selectItem(item: SelectItemDirective) {\n this.updateItems$.next({ type: UpdateActions.Add, item });\n }\n\n private _deselectItem(item: SelectItemDirective) {\n this.updateItems$.next({ type: UpdateActions.Remove, item });\n }\n\n private _hasItem(item: SelectItemDirective, selectedItems: Array<any>) {\n return selectedItems.includes(item.value);\n }\n\n private _getClosestSelectItem(event: Event): [number, SelectItemDirective] {\n const target = (event.target as HTMLElement).closest('.dts-select-item');\n let index = -1;\n let targetItem = null;\n\n if (target) {\n targetItem = target[SELECT_ITEM_INSTANCE];\n index = this._selectableItems.indexOf(targetItem);\n }\n\n return [index, targetItem];\n }\n\n private _resetRangeStart() {\n this._lastRange = [-1, -1];\n const lastRangeStart = this._getLastRangeSelection();\n\n if (lastRangeStart && lastRangeStart.rangeStart) {\n lastRangeStart.toggleRangeStart();\n }\n }\n\n private _getLastRangeSelection(): SelectItemDirective | null {\n if (this._lastStartIndex >= 0) {\n return this._selectableItems[this._lastStartIndex];\n }\n\n return null;\n }\n}\n","import { CommonModule } from '@angular/common';\nimport { ModuleWithProviders, NgModule } from '@angular/core';\nimport { DEFAULT_CONFIG } from './config';\nimport { KeyboardEventsService } from './keyboard-events.service';\nimport { DragToSelectConfig } from './models';\nimport { SelectContainerComponent } from './select-container.component';\nimport { SelectItemDirective } from './select-item.directive';\nimport { ShortcutService } from './shortcut.service';\nimport { CONFIG, USER_CONFIG } from './tokens';\nimport { mergeDeep } from './utils';\n\nconst COMPONENTS = [SelectContainerComponent, SelectItemDirective];\n\nfunction configFactory(config: Partial<DragToSelectConfig>) {\n return mergeDeep(DEFAULT_CONFIG, config);\n}\n\n@NgModule({\n imports: [CommonModule],\n declarations: [...COMPONENTS],\n exports: [...COMPONENTS],\n})\nexport class DragToSelectModule {\n static forRoot(config: Partial<DragToSelectConfig> = {}): ModuleWithProviders<DragToSelectModule> {\n return {\n ngModule: DragToSelectModule,\n providers: [\n ShortcutService,\n KeyboardEventsService,\n { provide: USER_CONFIG, useValue: config },\n {\n provide: CONFIG,\n useFactory: configFactory,\n deps: [USER_CONFIG],\n },\n ],\n };\n }\n}\n","/*\n * Public API Surface of ngx-drag-to-select\n */\n\nexport * from './lib/drag-to-select.module';\nexport * from './lib/select-container.component';\nexport * from './lib/select-item.directive';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public_api';\n"],"names":[],"mappings":"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