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/core

v1.7.0

Published

無頭式資料表格引擎 — 狀態、插件、插槽、事件

Downloads

1,628

Readme

@trellisjs/core

Headless datatable engine -- state management, plugin system, slot registry, and event bus. Framework-agnostic; rendering is handled by adapters.

Installation

npm install @trellisjs/core

Quick Start

import { Trellis } from '@trellisjs/core'
import type { ColumnDef, TrellisPlugin } from '@trellisjs/core'

interface User {
  id: number
  name: string
  email: string
}

const columns: ColumnDef<User>[] = [
  { id: 'name', accessor: 'name', header: 'Name', sortable: true },
  { id: 'email', accessor: 'email', header: 'Email' },
]

const data: User[] = [
  { id: 1, name: 'Alice', email: '[email protected]' },
  { id: 2, name: 'Bob', email: '[email protected]' },
]

const table = new Trellis({ data, columns, rowId: 'id' })

// Read state
const state = table.api.getState()

// Subscribe to changes
const unsubscribe = table.api.subscribe((state) => {
  console.log('State changed:', state.pagination.page)
})

// Listen for events
table.api.on('row:click', (payload) => {
  console.log('Row clicked:', payload)
})

// Clean up
table.destroy()

Dynamic Data Operations

Add, remove, or update individual rows. Each operation modifies sourceData and re-runs the Transform Pipeline so sort/filter/pagination stay in sync.

// Add a new row — appended to sourceData, pipeline re-runs
table.api.addRow({ id: 3, name: 'Charlie', email: '[email protected]' })

// Remove a row by ID — no-op if ID not found
table.api.removeRow('2')

// Update a row (shallow merge) — no-op if ID not found
table.api.updateRow('1', { name: 'Alice Updated' })

// Listen for data change events
table.api.on('data:added', (id) => console.log('Added:', id))
table.api.on('data:removed', (id) => console.log('Removed:', id))
table.api.on('data:updated', (id) => console.log('Updated:', id))

API Reference

Trellis<T>

Main class. Generic T is the shape of a data row.

const table = new Trellis(options)
  • table.api -- the public TrellisAPI<T> interface.
  • table.destroy() -- unregisters all plugins and clears event listeners.

TrellisAPI<T>

| Method | Signature | Returns | Description | |--------|-----------|---------|-------------| | getState | () => TableState<T> | Immutable snapshot | Current table state | | setState | (updater: (prev) => Partial<TableState<T>>) => void | void | Produce next state immutably | | subscribe | (listener: (state) => void) => () => void | Unsubscribe fn | React to state changes | | on | (event: string, handler: EventHandler) => () => void | Unsubscribe fn | Listen for events | | emit | (event: string, payload: unknown) => void | void | Dispatch an event | | registerSlot | (name: string, renderer: SlotRenderer) => () => void | Unregister fn | Register a named render slot | | getSlot | (name: string) => SlotRenderer \| undefined | Renderer or undefined | Retrieve a registered slot | | registerTransform | (name: string, priority: number, fn: TransformFn<T>) => void | void | Register a pipeline transform | | recompute | (withState?: Partial<TableState<T>>) => void | void | Re-run pipeline, optionally merging state | | updateSourceData | (data: T[]) => void | void | Replace all source data and re-run pipeline | | addRow | (item: T) => void | void | Append a row to sourceData and re-run pipeline. Emits data:added | | removeRow | (id: DataId) => void | void | Remove a row by ID and re-run pipeline. Emits data:removed | | updateRow | (id: DataId, partial: Partial<T>) => void | void | Merge-update a row by ID and re-run pipeline. Emits data:updated | | getFilteredData | () => DataRow<T>[] | Immutable copy | Filtered + sorted data before pagination |

Types

TrellisOptions<T>

interface TrellisOptions<T> {
  data: T[]
  columns: ColumnDef<T>[]
  plugins?: TrellisPlugin<T>[]
  pageSize?: number        // default: 10
  rowId?: keyof T | ((row: T, index: number) => DataId)
}

TrellisPlugin<T>

interface TrellisPlugin<T> {
  name: string
  install: (api: TrellisAPI<T>) => void
  destroy?: () => void
}

ColumnDef<T>

interface ColumnDef<T> {
  id: string
  accessor: keyof T | ((row: T) => unknown)
  header: string
  sortFn?: ColumnSortFn
  sortable?: boolean
  filterable?: boolean
  width?: number | string
  minWidth?: number | string
  maxWidth?: number | string
  align?: 'left' | 'center' | 'right'
  visible?: boolean
  resizable?: boolean
  // ...see source for full definition
}

DataRow<T>

interface DataRow<T> {
  id: DataId            // string | number
  original: T           // user-provided row data
  index: number          // position in original array
}

TableState<T>

interface TableState<T> {
  data: DataRow<T>[]
  columns: ColumnDef<T>[]
  sorting: { columnId: string; direction: 'asc' | 'desc' | null }
  filtering: { query: string; columnFilters: Record<string, unknown> }
  pagination: { page: number; pageSize: number; totalItems: number }
  selection: Set<DataId>
  columnVisibility: Record<string, boolean>
  columnPinning: { left: string[]; right: string[] }
  virtualScroll?: { startIndex: number; endIndex: number; totalHeight: number; rowHeight: number }
}

License

MIT