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

@entropy-tamer/reynard-selection-primitives

v0.1.0

Published

Modular selection and configuration primitives for the Reynard ecosystem

Readme

Reynard Selection Primitives

Modular selection and configuration primitives for the Reynard ecosystem. This package provides a comprehensive set of composables for managing selection state, configuration management, and signal coordination with full TypeScript support, validation, and persistence.

Features

  • Modular Architecture: Composable primitives that can be used independently or combined
  • Type Safety: Full TypeScript support with generic types
  • Validation: Built-in validation system with real-time feedback
  • Persistence: Configurable persistence with localStorage, sessionStorage, and memory options
  • Signal Coordination: Advanced signal coordination with dependency tracking and debouncing
  • Accessibility: Built-in accessibility compliance checking
  • Performance: Optimized for performance with minimal re-renders

Installation

pnpm add reynard-selection-primitives

Core Primitives

useSelection

Base selection primitive for managing item selection state.

import { useSelection } from "reynard-selection-primitives";

const selection = useSelection<string>({
  multiple: true,
  allowDeselect: true,
  maxSelections: 5,
  validation: item => item.length > 0,
  onChange: selected => console.log("Selected:", selected),
});

// Select items
selection.select("item1");
selection.selectMultiple(["item2", "item3"]);

// Check selection state
console.log(selection.selected()); // ['item1', 'item2', 'item3']
console.log(selection.hasSelection()); // true
console.log(selection.selectionCount()); // 3

useConfiguration

Configuration management primitive with validation and persistence.

import { useConfiguration, commonValidators } from "reynard-selection-primitives";

interface AppConfig {
  theme: string;
  language: string;
  notifications: boolean;
}

const config = useConfiguration<AppConfig>({
  initialConfig: {
    theme: "light",
    language: "en",
    notifications: true,
  },
  validation: {
    rules: [
      commonValidators.required<AppConfig>("Theme is required"),
      {
        validate: config => ["light", "dark"].includes(config.theme),
        message: "Theme must be light or dark",
        severity: "error",
      },
    ],
    mode: "strict",
    realTime: true,
  },
  persistence: {
    key: "app-config",
    storage: "localStorage",
    serialization: "json",
  },
});

// Update configuration
config.updateConfig({ theme: "dark" });

// Check validation
console.log(config.isValid()); // true
console.log(config.validationErrors()); // []

useCoordination<T, U>

Signal coordination primitive for managing dependencies between signals.

import { useCoordination, createSignal } from "reynard-selection-primitives";

const [primary, setPrimary] = createSignal("initial");
const [secondary, setSecondary] = createSignal(0);

const coordination = useCoordination({
  primary,
  secondary,
  coordination: (primaryValue, secondaryValue) => {
    console.log(`Primary: ${primaryValue}, Secondary: ${secondaryValue}`);
  },
  dependencies: {
    dependencies: [primary, secondary],
    coordination: deps => {
      console.log("Dependencies changed:", deps);
    },
    debounce: 100,
  },
});

// Manually trigger coordination
coordination.coordinate("manual", 42);

Extensions

useThemeAccessibility

Specialized extension for theme and accessibility selection coordination.

import { useThemeAccessibility } from "reynard-selection-primitives";

const themeAccessibility = useThemeAccessibility({
  theme: "light",
  colorblind: {
    enabled: false,
    deficiency: "normal",
    severity: "moderate",
  },
  accessibility: {
    highContrast: false,
    reducedMotion: false,
    fontSize: "medium",
  },
});

// Theme selection
themeAccessibility.themeSelection.select("dark");

// Colorblind selection
themeAccessibility.colorblindSelection.select("protanopia");

// Configuration management
themeAccessibility.config.updateConfig({
  accessibility: {
    highContrast: true,
    reducedMotion: true,
    fontSize: "large",
  },
});

// Get recommendations
const recommendations = themeAccessibility.getRecommendations();
console.log(recommendations); // ['Consider enabling high contrast mode...']

Validation System

The validation system provides comprehensive validation with real-time feedback.

import { commonValidators } from "reynard-selection-primitives";

// Common validators
const validators = {
  required: commonValidators.required("This field is required"),
  minLength: commonValidators.minLength(3, "Minimum 3 characters"),
  maxLength: commonValidators.maxLength(50, "Maximum 50 characters"),
  email: commonValidators.email("Invalid email format"),
  url: commonValidators.url("Invalid URL format"),
  min: commonValidators.min(0, "Must be positive"),
  max: commonValidators.max(100, "Must be less than 100"),
  pattern: commonValidators.pattern(/^[A-Z]/, "Must start with uppercase"),
};

// Custom validator
const customValidator = {
  validate: (value: string) => value.includes("@"),
  message: "Must contain @ symbol",
  severity: "error" as const,
};

Persistence System

The persistence system supports multiple storage options with custom serialization.

// localStorage with JSON serialization
const localStorageConfig = {
  key: "my-config",
  storage: "localStorage" as const,
  serialization: "json" as const,
};

// sessionStorage with custom serialization
const sessionStorageConfig = {
  key: "session-data",
  storage: "sessionStorage" as const,
  serialization: "custom" as const,
  serializer: (data: any) => btoa(JSON.stringify(data)),
  deserializer: (data: string) => JSON.parse(atob(data)),
};

// Memory storage (no persistence)
const memoryConfig = {
  key: "temp-data",
  storage: "memory" as const,
  serialization: "json" as const,
};

Advanced Features

Signal Coordination with Dependencies

const coordination = useCoordination({
  primary: () => userInput(),
  secondary: () => serverResponse(),
  coordination: (input, response) => {
    // Update UI based on input and response
    updateUI(input, response);
  },
  dependencies: {
    dependencies: [userInput, serverResponse, networkStatus],
    coordination: deps => {
      // Handle dependency changes
      handleDependencyChanges(deps);
    },
    debounce: 300,
    immediate: false,
  },
});

Selection with Validation

const selection = useSelection<User>({
  multiple: true,
  maxSelections: 10,
  validation: user => {
    return user.isActive && user.hasPermission;
  },
  onChange: selectedUsers => {
    // Update permissions based on selection
    updatePermissions(selectedUsers);
  },
});

Configuration with Complex Validation

const config = useConfiguration<ComplexConfig>({
  initialConfig: defaultConfig,
  validation: {
    rules: [
      {
        validate: config => config.apiKey.length >= 32,
        message: "API key must be at least 32 characters",
        severity: "error",
      },
      {
        validate: config => config.timeout > 0,
        message: "Timeout must be positive",
        severity: "warning",
      },
    ],
    mode: "strict",
    realTime: true,
  },
  persistence: {
    key: "complex-config",
    storage: "localStorage",
    serialization: "json",
  },
});

TypeScript Support

All primitives are fully typed with TypeScript generics for maximum type safety.

// Typed selection
const stringSelection = useSelection<string>({
  /* config */
});
const userSelection = useSelection<User>({
  /* config */
});

// Typed configuration
const appConfig = useConfiguration<AppConfig>({
  /* config */
});
const userConfig = useConfiguration<UserConfig>({
  /* config */
});

// Typed coordination
const stringNumberCoordination = useCoordination<string, number>({
  /* config */
});
const userResponseCoordination = useCoordination<User, Response>({
  /* config */
});

Performance Considerations

  • Minimal Re-renders: Primitives use SolidJS signals for optimal performance
  • Debounced Coordination: Signal coordination supports debouncing to prevent excessive updates
  • Lazy Validation: Validation is performed only when needed
  • Efficient Persistence: Persistence operations are optimized and cached

Accessibility

The primitives include built-in accessibility features:

  • WCAG Compliance: Validation includes accessibility compliance checking
  • Screen Reader Support: All state changes are properly announced
  • Keyboard Navigation: Full keyboard support for all interactions
  • High Contrast: Support for high contrast mode
  • Reduced Motion: Respects user's motion preferences

Examples

Data Table Selection

import { useSelection } from "reynard-selection-primitives";

const dataTableSelection = useSelection<number>({
  multiple: true,
  allowDeselect: true,
  onChange: selectedIndices => {
    const selectedData = selectedIndices.map(i => data[i]);
    onRowSelect?.(selectedData);
  },
});

Form Configuration

import { useConfiguration, commonValidators } from "reynard-selection-primitives";

const formConfig = useConfiguration<FormConfig>({
  initialConfig: defaultFormConfig,
  validation: {
    rules: [
      commonValidators.required<FormConfig>("Form configuration is required"),
      {
        validate: config => config.fields.length > 0,
        message: "At least one field is required",
        severity: "error",
      },
    ],
    mode: "strict",
    realTime: true,
  },
  persistence: {
    key: "form-config",
    storage: "localStorage",
    serialization: "json",
  },
});

Theme and Accessibility

import { useThemeAccessibility } from "reynard-selection-primitives";

const themeAccessibility = useThemeAccessibility({
  theme: "light",
  colorblind: {
    enabled: false,
    deficiency: "normal",
    severity: "moderate",
  },
  accessibility: {
    highContrast: false,
    reducedMotion: false,
    fontSize: "medium",
  },
});

API Reference

useSelection

| Property | Type | Description | | ----------------- | ------------------------- | ------------------------------------- | | selected | () => T[] | Get currently selected items | | isSelected | (item: T) => boolean | Check if item is selected | | select | (item: T) => void | Select an item | | deselect | (item: T) => void | Deselect an item | | toggle | (item: T) => void | Toggle item selection | | selectMultiple | (items: T[]) => void | Select multiple items | | selectAll | (items: T[]) => void | Select all items from a list | | clear | () => void | Clear all selections | | canSelect | (item: T) => boolean | Check if item can be selected | | selectionCount | () => number | Get selection count | | hasSelection | () => boolean | Check if any items are selected | | isAtMaxCapacity | () => boolean | Check if selection is at max capacity | | getState | () => SelectionState<T> | Get selection state |

useConfiguration

| Property | Type | Description | | ------------------ | ------------------------------- | ---------------------------------- | | config | () => T | Get current configuration | | updateConfig | (updates: Partial<T>) => void | Update configuration | | resetConfig | () => void | Reset to initial configuration | | isValid | () => boolean | Check if configuration is valid | | validationErrors | () => string[] | Get validation errors | | hasChanged | () => boolean | Check if configuration has changed | | getState | () => ConfigurationState<T> | Get configuration state | | save | () => void | Save configuration to storage | | load | () => void | Load configuration from storage |

useCoordination<T, U>

| Property | Type | Description | | --------------- | ------------------------------------ | ------------------------------- | | primary | () => T | Get primary signal value | | secondary | () => U | Get secondary signal value | | coordinate | (primary: T, secondary: U) => void | Manually trigger coordination | | isCoordinated | () => boolean | Check if coordination is active | | getState | () => CoordinationState<T, U> | Get coordination state | | enable | () => void | Enable coordination | | disable | () => void | Disable coordination | | reset | () => void | Reset coordination state |

Contributing

Contributions are welcome! Please read our contributing guidelines and code of conduct.

License

MIT License - see LICENSE file for details.