Viselect Documentation

repository·master·Indexed 25 days ago

https://github.com/simonwep/viselect

A lightweight (~4kb), zero-dependency visual DOM-selection library that enables drag-to-select interactions. It supports mouse and touch interfaces, vertical/horizontal scrolling, and provides specific packages for Vanilla JS, React, Preact, and Vue. The library features a SelectionArea class for managing the selection process, a SelectionStore for state tracking, and support for standard keyboard modifiers like Ctrl, Cmd, and Shift.

Tokens
13.5K
Snippets
25
Records
61
Agent score
83%

What's inside Viselect

  1. Overview of Viselect

    master
    Viselect is a visual DOM-selection library designed for high performance and minimal footprint. It allows users to perform drag-to-select actions on DOM elements, supporting both mouse and touch interfaces. It is highly optimized, has zero dependencies, and is compatible with various modern frameworks.
  2. Quickstart with @viselect/vanilla

    master

    To set up a selection area using the vanilla JavaScript package, import SelectionArea and instantiate it with a configuration object. You must specify selectables (elements that can be selected) and boundaries (the area within which selection occurs). You can listen to events like start and move to manage selection state, such as adding or removing CSS classes from elements as they are selected or deselected.

    import SelectionArea from '@viselect/vanilla';
    
    const selection = new SelectionArea({
      selectables: ['.container > div'],
      boundaries: ['.container'],
      selectionAreaClass: 'selectionArea'
    }).on('start', ({ store, event }) => {
      // Example: Clear selection if Ctrl/Meta key is not held
      if (!event.ctrlKey && !event.metaKey) {
        store.stored.forEach(el => el.classList.remove('selected'));
        selection.clearSelection();
      }
    }).on('move', ({ store: { changed: { added, removed } } }) => {
      // Example: Update visual state during selection movement
      added.forEach(el => el.classList.add('selected'));
      removed.forEach(el => el.classList.remove('selected'));
    });
  3. Install @viselect/vanilla

    master

    To use Viselect without a framework, install the vanilla package using your preferred package manager or via CDN.

    $ npm add -D @viselect/vanilla
    $ pnpm add -D @viselect/vanilla
    $ yarn add -D @viselect/vanilla
    <script src="https://cdn.jsdelivr.net/npm/@viselect/vanilla/dist/viselect.umd.js"></script>
    import SelectionArea from "https://cdn.jsdelivr.net/npm/@viselect/vanilla/dist/viselect.mjs"
  4. Use the SelectionArea component in React

    master

    Import SelectionArea from @viselect/react to enable selection functionality in your React application.

    Key Implementation Details:

    • Props: All Viselect options are exposed as direct props on the SelectionArea component (a one-to-one mapping to the original SelectionOptions).
    • Re-renders: React does not deep-compare props for this component. Changing props will not trigger updates. To force a re-render with new configuration, you must add or change the key prop of the SelectionArea component.
    • Event Types: Selection events use the SelectionEvent type.
    import {SelectionArea, SelectionEvent} from '@viselect/react';
    import React, {FunctionComponent, useState} from 'react';
    import './styles.css';
    
    const App: FunctionComponent = () => {
      const [selected, setSelected] = useState<Set<number>>(() => new Set());
    
      const extractIds = (els: Element[]): number[] =>
        els.map(v => v.getAttribute('data-key'))
          .filter(Boolean)
          .map(Number);
    
      const onStart = ({ event, selection }: SelectionEvent) => {
        if (!event?.ctrlKey && !event?.metaKey) {
          selection.clearSelection();
          setSelected(() => new Set());
        }
      };
    
      const onMove = ({ store: { changed: { added, removed } } }: SelectionEvent) => {
        setSelected(prev => {
          const next = new Set(prev);
          extractIds(added).forEach(id => next.add(id));
          extractIds(removed).forEach(id => next.delete(id));
          return next;
        });
      };
    
      return (
        <>
          <SelectionArea className="container"
                   onStart={onStart}
                   onMove={onMove}
                   selectables=".selectable">
            {new Array(42).fill(0).map((_, index) => (
              <div className={selected.has(index) ? 'selected selectable' : 'selectable'}
                 data-key={index}
                 key={index}/>
            ))}
          </SelectionArea>
        </>
      );
    }
  5. Get started with Viselect

    master
    To begin using Viselect in your project, refer to the official documentation for installation and setup instructions. The library provides specific packages for different environments including Vanilla JS, React, Preact, and Vue.
  6. Use SelectionArea in Vue projects

    master

    Import the SelectionArea component from @viselect/vue to enable selection capabilities in your Vue templates.

    Configuration and Events

    • Options: All configuration options are passed via a single :options prop. These are a one-to-one mapping of the original SelectionOptions.
    • Events: Events are handled as props suffixed with on (e.g., :onMove, :onStart). This pattern is used because events cannot return values synchronously in this integration.
    <template>
      <SelectionArea class="container"
                     :options="{ selectables: '.selectable' }"
                     :onMove="onMove"
                     :onStart="onStart">
        <div v-for="id of 42"
             class="selectable"
             :key="id" 
             :data-key="id"
             :class="{ selected: selected.has(id) }"/>
      </SelectionArea>
    </template>
    
    <script lang="ts" setup>
    import { SelectionArea, SelectionEvent } from '@viselect/vue';
    import { reactive } from 'vue';
    
    const selected = reactive<Set<number>>(new Set());
    
    const extractIds = (els: Element[]): number[] => {
      return els.map(v => v.getAttribute('data-key'))
          .filter(Boolean)
          .map(Number);
    };
    
    const onStart = ({ event, selection }: SelectionEvent) => {
      if (!event?.ctrlKey && !event?.metaKey) {
        selection.clearSelection();
        selected.clear();
      }
    };
    
    const onMove = ({ store: { changed: { added, removed } } }: SelectionEvent) => {
      extractIds(added).forEach(id => selected.add(id));
      extractIds(removed).forEach(id => selected.delete(id));
    };
    </script>
  7. Use Viselect in vanilla JavaScript

    master

    Import the SelectionArea class from @viselect/vanilla to manage element selection. You can configure selectables (the elements that can be selected) and boundaries (the containers that define the selection area). Use event listeners like on('start', ...) and on('move', ...) to react to selection changes.

    import { SelectionArea } from '@viselect/vanilla';
    import './styles.css';
    
    // Generate some divs to select later
    [
      ['.container.blue', 33],
      ['.container.green', 33]
    ].forEach(([selector, items]) => {
      const container = document.querySelector(selector);
    
      for (let i = 0; i < items; i++) {
        container.appendChild(document.createElement('div'));
      }
    });
    
    // Instantiate the selection area
    const selection = new SelectionArea({
      selectables: ['.container > div'], // Specifies the elements that can be selected
      boundaries: ['.container'], // Specifies the boundaries of each selection
    }).on('start', ({ store, event }) => {
      if (!event.ctrlKey && !event.metaKey && !event.shiftKey) { // Clear selection if no modifier key is pressed
        store.stored.forEach(el => el.classList.remove('selected'));
        selection.clearSelection();
      }
    }).on('move', ({ store: { changed: { added, removed } } }) => {
      added.forEach(el => el.classList.add('selected'));
      removed.forEach(el => el.classList.remove('selected'));
    });