JSPM

  • Created
  • Published
  • Downloads 1196
  • Score
    100M100P100Q112210F
  • License MIT

Simple, lightweight and modern library library for making visual DOM Selections.

Package Exports

  • @viselect/vue

Readme

Logo

Viselect - Vue

License MIT No dependencies Support me Buy me a coffee Build Status gzip size brotli size Vue support Preact support React support Svelte support Lit-Element support Lit-Element support


[!NOTE] This is merely a convenience wrapper around @viselect/vanilla. The core API is fairly simple, if you want to have full control over it, you should roll out your own wrapper in your app.

Installation

Install using your package manager of choice:

npm install @viselect/vue

Last but not least, you'll need to add some basic styles to make your selection-area visible:

.selection-area {
    background: rgba(46, 115, 252, 0.11);
    border: 2px solid rgba(98, 155, 255, 0.81);
    border-radius: 0.1em;
}

Additionally, to not interfere with text-selection, selection-js won't prevent any default events anymore (as of v2.0.3). This, however, can cause problems with the actual selection ("introduced" by #99, reported in #103). If you don't care about text-selection, add the following to the container where all your selectables are located:

.container {
    user-select: none;
}

Usage

[!NOTE] All options are exposed as props. They're a one-to-one mapping of the original options found in the vanilla version!

Events are handled using props because you can’t return a value in events synchronously.

<template>
  <SelectionArea class="container"
                 :options="{selectables: '.selectable'}"
                 :on-move="onMove"
                 :on-start="onStart">
    <div v-for="id of range(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 range = (to: number, offset = 0): number[] => {
  return new Array(to).fill(0).map((_, i) => offset + i);
};

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>

Component exposed API

selection

It's possible to get the current SelectionArea-instance via template refs.

<template>
  <SelectionArea 
    class="container"
    :options="{selectables: '.selectable'}"
    ref="selectionAreaRef"
  >
    <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} from '@viselect/vue';
import {ref, reactive, watchEffect} from 'vue';

const selected = reactive<Set<number>>(new Set());
const selectionAreaRef = ref<InstanceType<typeof SelectionArea>>();

watchEffect(() => {
  // log selection instance
  console.log(selectionAreaRef.value?.selection)
});
</script>