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

@micahcraig/ebbets

v0.1.1

Published

Softball lineup manager — drag-and-drop lineup and field position assignment

Downloads

22

Readme

Ebbets

Publish to NPM Storybook Deployment

A softball lineup manager React component.

Desktop — lineup list and field diagram side by side:

Desktop view

Mobile — single panel with List / Field tab toggle:

Mobile list view Mobile field view Drag-and-drop batting order and field position assignment in one view, with support for 3 or 4 outfielders and an optional Extra Hitter.

Features

  • List view — ordered batting lineup with drag-to-reorder handles
  • Field view — interactive diamond with draggable position chips
  • Cross-panel drag — drag a player from the lineup list directly onto a field position
  • 3 or 4 outfielders — toggle between LF/CF/RF and LF/CL/CR/RF configurations
  • Extra Hitter — manual or automatic; multiple EH slots when roster exceeds 10
  • Auto-config — switches to 4OF automatically at 10 players; adds EH slots beyond 10
  • Responsive — stacked tab layout on mobile, side-by-side panels on desktop (≥820px)
  • Self-contained CSS — styles are injected by the JS bundle; no separate stylesheet needed

Installation

npm install ebbets

React 17 or later is required as a peer dependency.

Usage

LineupManager is a controlled component. Your application owns the state and passes it down.

import { useState } from 'react'
import { LineupManager } from 'ebbets'

const COLORS = [
  '#dc2626', '#ea580c', '#d97706', '#16a34a',
  '#0891b2', '#2563eb', '#7c3aed', '#db2777',
]

const defaultRoster = () =>
  Array.from({ length: 9 }, (_, i) => ({
    id: i + 1,
    name: '',
    position: '',
    color: COLORS[i % COLORS.length],
  }))

export default function App() {
  const [players, setPlayers] = useState(defaultRoster)
  const [lineup, setLineup]   = useState({ outfield: '3', manualEH: false })

  const handleChange = ({ players: p, lineup: l }) => {
    setPlayers(p)
    setLineup(l)
  }

  return (
    <LineupManager
      players={players}
      lineup={lineup}
      onLineupChange={handleChange}
    />
  )
}

Props

players (required)

Array of player objects in batting order:

| Field | Type | Description | |---|---|---| | id | number \| string | Unique identifier | | name | string | Player name (empty string if unset) | | position | string | Assigned field position, e.g. 'SS', 'LF', 'EH', or '' | | color | string | CSS color used for the player's avatar chip |

lineup (required)

Configuration object:

| Field | Type | Default | Description | |---|---|---|---| | outfield | '3' \| '4' | '3' | Outfield configuration. Overridden automatically when roster ≥ 10 | | manualEH | boolean | false | Manually enable the Extra Hitter slot. Overridden automatically when roster > 10 |

onLineupChange (required)

(state: { players: Player[], lineup: Lineup }) => void

Called on every change — reorder, name edit, position assignment, add/remove player, or toggle. Receives the full next state; replace both players and lineup in your state handler.

initialView (optional)

'lineup' | 'field' — which panel is shown first on mobile. Defaults to 'lineup'. Has no effect on desktop where both panels are always visible.

showTitle (optional)

boolean — whether to render the "Lineup" <h1> heading. Defaults to true. Set to false when embedding the component inside a page that already provides its own heading. If showTitle is false and no toggle props are enabled, the header element is omitted entirely.

Toggle props (optional)

The header toggles are hidden by default. Enable them individually as needed for testing or accessibility:

| Prop | Controls | |---|---| | showViewToggle | List / Field tab toggle (mobile only) | | showOutfieldToggle | 4 Outfielders toggle | | showEHToggle | Extra Hitter toggle |

All three default to false. When none are shown the controls bar is removed from the header entirely.

Position reference

| Position | Notes | |---|---| | P, C, 1B, 2B, 3B, SS | Always present | | LF, RF | Always present | | CF | 3-outfielder mode only | | CL, CR | 4-outfielder mode only | | EH, EH2, EH3, … | One per player beyond 10; or one if manualEH is true |

Development

npm run dev          # Vite dev server (http://localhost:5173)
npm run storybook    # Storybook component explorer (http://localhost:6006)

Testing

npm test             # Unit + component tests (Vitest + React Testing Library)
npm run test:watch   # Same, in watch mode
npm run test:e2e     # Browser tests (Playwright, requires dev server or starts one automatically)

The unit/component suite (src/lineup.test.js, src/LineupManager.test.jsx) runs in a headless DOM environment and covers all pure data functions and the rendered component. The Playwright suite (tests/e2e/lineup.spec.js) runs against a live dev server in both a desktop viewport (1024px) and a mobile viewport (390px).

Building

npm run build        # Library build → dist/
npm run build:app    # Full app build (for hosting the demo)

The library build produces dist/index.es.js and dist/index.cjs.js with CSS injected at runtime.

License

MIT