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

@classic-homes/data-panel-core

v0.0.4

Published

Core utilities and types for DataPanel components

Readme

@classic-homes/data-panel-core

Core utilities and types for DataPanel components. This package provides shared functionality for building flexible, draggable, resizable panels across React and Svelte implementations.

Installation

npm install @classic-homes/data-panel-core

Quick Start

import {
  // Types
  type PanelMode,
  type PanelEdge,
  type DataPanelState,

  // Default values
  DEFAULT_PANEL_STATE,
  DEFAULT_CONSTRAINTS,

  // Utilities
  constrainSize,
  constrainPosition,
  loadPanelState,
  savePanelState,
} from '@classic-homes/data-panel-core';

// Load persisted state
const persisted = loadPanelState('my-panel');
const state = mergeWithDefaults(persisted);

// Constrain panel size
const size = constrainSize({ width: 500, height: 600 }, { minWidth: 300, maxWidth: 800 });

API Reference

Types

Panel Configuration Types

type PanelMode = 'pinned' | 'detached';
type PanelEdge = 'left' | 'right' | 'top' | 'bottom';
type PanelVariant = 'full' | 'card';
type ResizeHandle =
  | 'top'
  | 'right'
  | 'bottom'
  | 'left'
  | 'top-left'
  | 'top-right'
  | 'bottom-left'
  | 'bottom-right';

State Types

interface Position {
  x: number;
  y: number;
}

interface Size {
  width: number;
  height: number;
}

interface PanelConstraints {
  minWidth?: number;
  maxWidth?: number;
  minHeight?: number;
  maxHeight?: number;
}

interface DataPanelState {
  mode: PanelMode;
  variant: PanelVariant;
  edge: PanelEdge;
  isExpanded: boolean;
  detachedPosition: Position;
  detachedSize: Size;
  pinnedSize: number;
  cardSnapIndex: number;
}

Interaction State Types

interface DragState {
  isDragging: boolean;
  startPosition: Position;
  startPanelPosition: Position;
  currentPosition: Position;
}

interface ResizeState {
  isResizing: boolean;
  handle: ResizeHandle | null;
  startPosition: Position;
  startSize: Size;
  startPanelPosition: Position;
}

interface PinnedDragState {
  isDragging: boolean;
  hasDetached: boolean;
  startPosition: Position;
  currentPosition: Position;
  edge: PanelEdge;
  pinnedSize: number;
}

Constants

Default Values

import {
  DEFAULT_PANEL_STATE, // Default DataPanelState
  DEFAULT_CONSTRAINTS, // Default PanelConstraints
  DEFAULT_CARD_CONFIG, // Default CardConfig
  DEFAULT_SNAP_POINTS, // Default snap points { peek: 0.25, half: 0.5, full: 1.0 }
} from '@classic-homes/data-panel-core';

Card Mode Constants

import {
  CARD_HEADER_HEIGHT, // 72 - Height of collapsed card header
  CARD_EXPANDED_RATIO, // 0.85 - Max height as ratio of viewport
  CARD_MIN_WIDTH, // 280 - Minimum card width
} from '@classic-homes/data-panel-core';

Drag Utilities

State Initialization

// Create initial drag state
const dragState = createDragState();

// Create initial resize state
const resizeState = createResizeState();

// Create pinned drag-to-detach state
const pinnedDragState = createPinnedDragState();

Pointer Handling

// Get position from any pointer event type
const position = getPointerPosition(event); // MouseEvent | PointerEvent | TouchEvent

// Calculate new panel position during drag
const newPosition = calculateDragPosition(dragState, currentPointer);

// Calculate new size and position during resize
const { position, size } = calculateResize(resizeState, currentPointer);

Resize Handles

// Get cursor style for a resize handle
const cursor = getResizeCursor('top-left'); // 'nwse-resize'

// Get the resize handle for a pinned panel edge
const handle = getPinnedResizeHandle('right'); // 'left'

// Get all handles for detached mode
const handles = getDetachedResizeHandles(); // ['top', 'right', 'bottom', 'left', ...]

// Check if pointer is near a resize handle
const nearHandle = isNearResizeHandle(mousePos, panelRect, threshold);

Pinned Drag-to-Detach

// Calculate distance dragged away from edge
const distance = calculateDetachDistance(startPos, currentPos, 'right');

// Calculate rubber-band pull offset
const offset = calculatePullOffset(distance, threshold, maxPull);

// Get new position when detaching
const newPos = calculateDetachedPositionFromPinned(
  pointerPos,
  pinnedSize,
  detachedSize,
  edge,
  viewportWidth,
  viewportHeight
);

// Get CSS transform for pull effect
const transform = getPinnedPullTransform(pullOffset, 'right'); // 'translateX(-10px)'

Constraint Utilities

Value Clamping

// Clamp a value between min and max
const clamped = clamp(value, min, max);

// Constrain size to min/max bounds
const size = constrainSize({ width: 1000, height: 1000 }, constraints);

// Constrain position within viewport
const pos = constrainPosition(position, size, viewportWidth, viewportHeight, padding);

// Combined size and position constraint during resize
const { position, size } = constrainResize(newPos, newSize, constraints, vw, vh);

Pinned Panel Constraints

// Constrain width for horizontal edges (left/right)
const width = constrainPinnedWidth(width, constraints, viewportWidth, maxRatio);

// Constrain height for vertical edges (top/bottom)
const height = constrainPinnedHeight(height, constraints, viewportHeight, maxRatio);

Edge Detection

// Check if position should snap to an edge
const { shouldSnap, edge, distance } = detectEdgeSnap(
  position,
  size,
  viewportWidth,
  viewportHeight,
  threshold
);

// Edge type helpers
const isHoriz = isHorizontalEdge('left'); // true
const isVert = isVerticalEdge('top'); // true

Position Styles

// Get CSS styles for pinned panel
const styles = getPinnedPositionStyles('right', 400);
// { top: '0', right: '0', bottom: '0', width: '400px', height: '100%' }

// Get CSS styles for detached panel
const styles = getDetachedPositionStyles({ x: 100, y: 200 }, { width: 400, height: 500 });
// { top: '200px', left: '100px', width: '400px', height: '500px' }

// Get centered initial position
const pos = getInitialDetachedPosition(size, viewportWidth, viewportHeight);

Card Mode Utilities

// Calculate snap point height in pixels
const height = getSnapPointHeight(0.5, viewportHeight, headerHeight);

// Get CSS styles for card mode
const styles = getCardPositionStyles(0.5, viewportWidth, viewportHeight, cardConfig);

// Find nearest snap point to current height
const index = findNearestSnapIndex(currentHeight, viewportHeight, snapPoints);

// Determine snap based on swipe velocity
const index = getSnapIndexFromVelocity(currentIndex, velocity, snapPoints, threshold);

// Calculate drag velocity
const velocity = calculateDragVelocity(startY, endY, startTime, endTime);

// Check if card should be dismissed
const dismiss = shouldDismissCard(currentHeight, viewportHeight, threshold);

// Get labels for snap points
const labels = getSnapPointLabels([0.25, 0.5, 1.0]); // ['Peek', 'Half', 'Full']

Persistence Utilities

// Load state from localStorage
const state = loadPanelState('my-panel-key');

// Save state to localStorage
savePanelState('my-panel-key', panelState);

// Clear persisted state
clearPanelState('my-panel-key');

// Merge persisted state with defaults
const fullState = mergeWithDefaults(persisted, customDefaults);

// Create debounced save function
const debouncedSave = createDebouncedSave('my-panel-key', 300);
debouncedSave(state); // Saves after 300ms of inactivity

Usage with React/Svelte

This package is framework-agnostic and provides the core logic for DataPanel components. Use with:

  • @classic-homes/react - React DataPanel component
  • @classic-homes/svelte - Svelte DataPanel component

Both implementations use this package internally for consistent behavior.

License

MIT