npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@trellisjs/plugin-selection

v2.0.0

Published

Trellis 行選取插件 — 單選、全選、Shift 範圍選

Downloads

328

Readme

@trellisjs/plugin-selection

Selection plugin for Trellis data tables — supports single row toggle, select all, and Shift range selection.

Installation

npm install @trellisjs/plugin-selection

Events

Listens

| Event | Payload | Description | |---|---|---| | selection:toggle | { rowId: DataId } | Toggle a single row's selection state. Sets the anchor for subsequent range selections. | | selection:all | { select: boolean } | Select all rows in current state.data (true) or deselect all (false). | | selection:range | { toIndex: number } | Select all rows from the anchor to toIndex (inclusive). Replaces the current selection with exactly this range. If no anchor exists, selects only the row at toIndex. |

State Updated

  • state.selection — a Set<DataId> of currently selected row IDs.

When filtering or sorting changes state.data, any selected IDs no longer present in the data are automatically removed from state.selection.

Usage

Single Row Selection

import { Trellis } from '@trellisjs/core';
import { createSelectionPlugin } from '@trellisjs/plugin-selection';

const trellis = new Trellis({
  columns: [
    { id: 'name', accessor: 'name' },
    { id: 'email', accessor: 'email' },
  ],
  data: [
    { name: 'Alice', email: '[email protected]' },
    { name: 'Bob', email: '[email protected]' },
  ],
  rowId: 'id',
  plugins: [createSelectionPlugin()],
});

// Select a row
trellis.api.emit('selection:toggle', { rowId: '1' });

// Deselect the same row
trellis.api.emit('selection:toggle', { rowId: '1' });

// Check selection
trellis.api.getState().selection.has('1'); // false

Select All / Deselect All

// Select all visible rows
trellis.api.emit('selection:all', { select: true });

// Deselect all
trellis.api.emit('selection:all', { select: false });

selection:all operates on the current state.data — after filtering and pagination. This means "select all" selects exactly what the user sees.

Shift Range Selection

// Click row at index 1 — sets anchor
trellis.api.emit('selection:toggle', { rowId: '2' });

// Shift+click row at index 4 — selects rows 1 through 4
trellis.api.emit('selection:range', { toIndex: 4 });

// Shift+click row at index 2 — adjusts to rows 1 through 2
// (rows 3 and 4 are deselected)
trellis.api.emit('selection:range', { toIndex: 2 });

Range selection replaces the current selection with exactly the anchor-to-target range, matching standard desktop application behavior.

React Integration

The plugin only provides the selection logic. The UI is up to you:

function MyTable({ data }) {
  const { api } = useTrellis({
    data,
    columns,
    rowId: 'id',
    plugins: [createSelectionPlugin()],
  });

  const state = api.getState();
  const allSelected = state.data.length > 0 && state.selection.size === state.data.length;

  const handleToggleAll = () => {
    api.emit('selection:all', { select: !allSelected });
  };

  const handleToggleRow = (rowId: string, shiftKey: boolean, rowIndex: number) => {
    if (shiftKey) {
      api.emit('selection:range', { toIndex: rowIndex });
    } else {
      api.emit('selection:toggle', { rowId });
    }
  };

  return (
    <table>
      <thead>
        <tr>
          <th>
            <input
              type="checkbox"
              checked={allSelected}
              onChange={handleToggleAll}
            />
          </th>
          {/* column headers */}
        </tr>
      </thead>
      <tbody>
        {state.data.map((row, rowIndex) => (
          <tr key={row.id}>
            <td>
              <input
                type="checkbox"
                checked={state.selection.has(row.id)}
                onChange={() => {}}
                onClick={(e) => {
                  e.stopPropagation();
                  handleToggleRow(row.id, e.shiftKey, rowIndex);
                }}
              />
            </td>
            {/* cells */}
          </tr>
        ))}
      </tbody>
    </table>
  );
}

Combination with Other Plugins

Selection works alongside filter, sort, and pagination. When data changes due to filtering or sorting, selected IDs no longer in the data are automatically removed.

plugins: [
  createFilterPlugin(),
  createSortPlugin(),
  createPaginationPlugin(),
  createSelectionPlugin(),
]

License

MIT