Selecting DOM elements by moving the mouse for React

Компонент предназанчен для визуализации выделения DOM элементов с помощью движения курсора по экрану, реализацию дальнейшего взаимодействия с выделенными файлами мы оставляем за вам через callback finishSelectionCallback

Кажется что такой подход делает бибилотеку более универсальной, потому что дальшейнее взаимодействие с выделенными объектами всегда уникально. В одном случае вам нужно получить id из datasets и обновить redux-store. В другом случае добавить класс к выледенным элементам и отправить запрос на сервер. Насколько сложным не был бы ваш кейс, вы сможете реализовать его в finishSelectionCallback имея массив всех выделенных элементов

DEMO

Example

Try it out

Installation

npm install --save react-mouse-select

Usage

import { ReactMouseSelect } from 'react-mouse-select';

function App() {
  const borderSelectionContainer = document.getElementById('portal') as HTMLElement;
  const containerRef = useRef<HTMLElement>(null);

  const itemClassName = 'mouse-select__selectable';
  
  return (
    <div className="App">
      <main className="container" ref={containerRef}>
        {[...Array(10)].map((item, idx) => {
          return (
            <div key={idx} className={itemClassName} data-id={idx}>
              Selectable block
            </div>
          )
        })}
      </main>
      <ReactMouseSelect
        containerRef={containerRef}
        portalContainer={borderSelectionContainer}
        itemClassName={itemClassName}
      />
    </div>
  );
}

export default App;

!!! ОБРАТИТЕ ВНИМАНИЕ

Вам самостоятельно нужно позаботиться о том что бы контейнер containerRef содержал элементы с классом itemClassName, как это показано в примере выше.

Также вам нужно описать стили для рамки и выделенных элементов, чтобы выделение было видно визуально

Вы можете стилизовать рамку выделения с помощью классов frameClassName и openFrameClassName или же оставить ее невидимой

Стилизовать элементы можно с помощью itemClassName и selectedItemClassName

Example:

.mouse-select__selectable {
    width: 100px;
    height: 100px;
    margin: 10px;
    background: gray;
}

.mouse-select__selectable .selected {
    border: 2px solid red;
}

.mouse-select__frame {
    background: red;
    opacity: 0.5;
}

Configuration

The ReactMouseSelect component accepts a few props:

  • containerRef [required]: Container ref in which selecting should work

  • portalContainer [required]: Portal container in which the highlighting frame will be rendered

  • sensitivity (number) default = 10: Sensitivity in pixels. Selection starts working only if the cursor is shifted for the specified number of pixels

  • tolerance (number) default = 0: The number of pixels that must be contained in a frame for the element to be selected

  • onClickPreventDefault (boolean) default = false: When the selection ends, after the onMouseUp event, the onClick event is dispatched by default If = true, the event bubbling is prevented after the selection With a normal click (without selection) the event happens standardly Useful, when there is a click handler on the container, which shouldn’t happen in case of selection

  • itemClassName (string) default = ‘mouse-select__selectable’: The class by which it is determined which elements we can select

  • selectedItemClassName (string) default = ‘selected’: The class that is added to the elements that come into the selecting frame

  • frameClassName (string) default = ‘mouse-select__frame’: Highlighting frame className

  • openFrameClassName (string) default = ‘open’: The class that is added to the highlighting frame when it is active

  • notStartWithSelectableElements (boolean) default = false: If true, then the selection will not start with the selected elements, but only with the space between them It can be useful, if the selecting elements, aside from the selection, are involved in drag and drop

  • saveSelectAfterFinish (boolean) default = false: Keep selected Item ClassName on selected items after selection is complete

  • startSelectionCallback (function (e: MouseEvent) => void;): Callback that calls at the start of the selection (when the frame appears)

  • finishSelectionCallback (function (items: Element[], e: MouseEvent) => void;): Callback that calls at the end of the selection

Development plans

If you have a desire, you can help the development of this library

  • поддержка касаний на мобильных телефонах
  • оптимизация производительности за счет перебора циклом не всех элементов, а только необходимой части Идея: имеем массив выделенных элементов и массив не выделенных элементов. В случае увеличения рамки по одной из сторон проходим массив не выделенных элементов и перемещаем в выделенные. В случае уменьшения рамки по двум сторонам проходим массив выделенных элементво и необхожимые перемещаем в массив не выделенных элементов
  • Для простоты использования компонета, добавить WrapperComponent в котором будет реализован рендер container и portal для рамки

GitHub

View Github