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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@ybaillet/elysium

v1.0.7

Published

Logitech Software Design System

Readme

Elysium Component Library

A production-ready React + TypeScript component library with a Figma tokens-based design system, built for Electron desktop applications.

Features

  • Dual-theme support: G-Hub theme (Cyan primary #00B6FA) and Options+ theme (Teal primary #00FDCF)
  • Light/Dark mode: Automatic mode switching with localStorage persistence
  • Figma tokens: Single source of truth from Figma design tokens
  • Accessible: Built with Radix UI primitives for full accessibility
  • TypeScript: Full type safety with exported types
  • Custom Font: BrownLogitechPan font family included (12 weights)
  • 330+ Icons: Custom SVG icon library

Installation

npm install @ybaillet/elysium

Note: Peer dependencies (React, Radix UI primitives, etc.) are automatically installed with npm 7+. If you're using an older npm version, you may need to install them manually.

Quick Start

All 4 steps below are required for the components to display correctly.

Step 1: Import Styles (Required)

Import the component styles in your main entry file. This includes the compiled Tailwind CSS classes used by all components:

// In your main.tsx or index.tsx (your app's entry point)
import '@ybaillet/elysium/styles';

Step 2: Import Fonts (Optional but Recommended)

Import the BrownLogitechPan font family for the authentic Logitech look:

import '@ybaillet/elysium/fonts';

Step 3: Wrap with ThemeProvider (Required)

The ThemeProvider is essential - it generates all CSS variables that components depend on. Without it, colors will not display correctly.

// App.tsx
import { ThemeProvider } from '@ybaillet/elysium';

function App() {
  return (
    <ThemeProvider defaultTheme="ghub" defaultMode="dark">
      {/* Your entire app goes here */}
      <YourApp />
    </ThemeProvider>
  );
}

export default App;

Important: The ThemeProvider must wrap your entire application. It dynamically injects CSS variables (like --color-surface-primary-default, --color-text-neutral-default, etc.) that all components use for theming.

Step 4: Configure Tailwind CSS (Required if using Tailwind)

If your project uses Tailwind CSS, you must add the Elysium dist folder to your content paths. This ensures Tailwind doesn't purge the CSS classes used by Elysium components:

// tailwind.config.js
module.exports = {
  content: [
    './src/**/*.{js,ts,jsx,tsx}',
    // Add this line - required for Elysium components to work
    './node_modules/@ybaillet/elysium/dist/**/*.{js,cjs}',
  ],
  // ... rest of your config
};

Complete Setup Example

Here's a complete example of a properly configured app:

// main.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';

// Step 1: Import Elysium styles
import '@ybaillet/elysium/styles';

// Step 2: Import fonts (optional)
import '@ybaillet/elysium/fonts';

// Your own styles (if any) should come after
import './index.css';

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);
// App.tsx
import { ThemeProvider, Button, Card, Switch } from '@ybaillet/elysium';

function App() {
  return (
    // Step 3: Wrap with ThemeProvider
    <ThemeProvider defaultTheme="ghub" defaultMode="dark">
      <div className="min-h-screen p-8">
        <Card>
          <Button variant="primary">Click Me</Button>
          <Switch />
        </Card>
      </div>
    </ThemeProvider>
  );
}

export default App;

Troubleshooting

Colors not displaying correctly?

  • Ensure ThemeProvider wraps your entire app (not just individual components)
  • Verify @ybaillet/elysium/styles is imported in your entry file
  • If using Tailwind, check that the Elysium content path is in your tailwind.config.js

Components look unstyled?

  • Make sure styles are imported before your own CSS files
  • Check browser console for any import errors

Theme System

Elysium supports two branded themes, each with light and dark modes:

Available Themes

| Theme ID | Brand Name | Primary Color | Use Case | |----------|------------|---------------|----------| | ghub | G-Hub | Cyan (#00B6FA) | Gaming peripherals, high-energy interfaces | | options+ | Options+ | Teal (#00FDCF) | Professional peripherals, productivity tools |

Note: The theme IDs match the brand names for clarity. The theme definition files are themeGHub.ts and themeOptionsPlus.ts.

Each theme automatically adjusts all component colors, including surfaces, text, icons, and interactive states.

Setting Up a Theme

Wrap your app with ThemeProvider and specify your theme:

import { ThemeProvider, Button, Switch, Slider } from '@ybaillet/elysium';

// G-Hub theme (Cyan) - Dark mode
function GHubApp() {
  return (
    <ThemeProvider defaultTheme="ghub" defaultMode="dark">
      <Button variant="primary">Gaming Button</Button>
      <Switch /> {/* Cyan accent when on */}
      <Slider value={[50]} /> {/* Cyan track */}
    </ThemeProvider>
  );
}

// Options+ theme (Teal) - Light mode
function OptionsPlusApp() {
  return (
    <ThemeProvider defaultTheme="options+" defaultMode="light">
      <Button variant="primary">Professional Button</Button>
      <Switch /> {/* Teal accent when on */}
      <Slider value={[50]} /> {/* Teal track */}
    </ThemeProvider>
  );
}

Switching Themes Dynamically

Use the useTheme hook to change themes or modes at runtime:

import { useTheme, Button } from '@ybaillet/elysium';

function ThemeSwitcher() {
  const { theme, mode, themeBrand, setTheme, setMode, toggleMode } = useTheme();
  
  return (
    <div>
      {/* theme = 'ghub' or 'options+', themeBrand = 'G-Hub' or 'Options+' */}
      <p>Current: {themeBrand} ({mode})</p>
      
      {/* Switch between themes */}
      <Button onClick={() => setTheme('ghub')}>G-Hub Theme</Button>
      <Button onClick={() => setTheme('options+')}>Options+ Theme</Button>
      
      {/* Toggle light/dark mode */}
      <Button onClick={toggleMode}>Toggle Dark/Light</Button>
      <Button onClick={() => setMode('dark')}>Force Dark</Button>
    </div>
  );
}

Theme-Aware Components

All components automatically adapt to the current theme. The primary color changes based on the active theme:

import { ThemeProvider, Button, ProgressIndicator, Checkbox } from '@ybaillet/elysium';

function MyApp() {
  return (
    <ThemeProvider defaultTheme="ghub" defaultMode="dark">
      {/* All these components use Cyan (G-Hub) accents */}
      <Button variant="primary">Primary Action</Button>
      <ProgressIndicator value={75} />
      <Checkbox defaultChecked />
      
      {/* Switching to options+ would make them all Teal instead */}
    </ThemeProvider>
  );
}

Components

Core Components

| Component | Description | |-----------|-------------| | Accordion | Expandable content sections | | Button | Primary interactive element with multiple variants | | Card | Container with header, content, and footer | | Checkbox | Toggle selection control | | Dialog | Modal overlay for focused interactions | | DropdownMenu | Context menu with nested options | | IconButton | Icon-only button with aria-label | | Input | Text input with validation states | | ListItem | Interactive list row with various controls | | Pagination | Page navigation control | | ProgressIndicator | Visual progress display | | RadioGroup | Single-select option group | | Search | Search input with clear functionality | | Select | Dropdown selection control | | Slider | Range value selector | | Snackbar | Toast notifications | | Switch | Toggle control | | Tabs | Horizontal tab navigation | | TabsVertical | Vertical tab navigation | | TabViewer | Tab content manager | | Textarea | Multi-line text input | | Tooltip | Contextual information popup |

Specialized Components

| Component | Description | |-----------|-------------| | ActuationPoint | Vertical slider for actuation settings | | AssignmentLabel | Key assignment display | | Connectivity | Device connection status indicator | | RapidTrigger | Horizontal slider for rapid trigger settings |

Component Usage Examples

Many components require state management. Here are complete examples showing how to properly use them:

Controlled Components with useState

import { useState } from 'react';
import { 
  ActuationPoint, 
  RapidTrigger, 
  Slider, 
  Switch, 
  Checkbox,
  Input,
  Select,
  SelectTrigger,
  SelectValue,
  SelectContent,
  SelectItem
} from '@ybaillet/elysium';

function ControlledComponentsExample() {
  // Slider-based components
  const [actuationValue, setActuationValue] = useState(1);
  const [rapidTriggerValue, setRapidTriggerValue] = useState(0.5);
  const [sliderValue, setSliderValue] = useState([50]);
  
  // Toggle components
  const [switchOn, setSwitchOn] = useState(false);
  const [checked, setChecked] = useState(false);
  
  // Text input
  const [text, setText] = useState('');
  
  // Select
  const [selected, setSelected] = useState('option1');

  return (
    <div className="space-y-4">
      {/* ActuationPoint - vertical slider */}
      <ActuationPoint
        value={actuationValue}
        onChange={setActuationValue}
      />
      
      {/* RapidTrigger - horizontal slider */}
      <RapidTrigger
        value={rapidTriggerValue}
        onChange={setRapidTriggerValue}
      />
      
      {/* Standard Slider */}
      <Slider
        value={sliderValue}
        onValueChange={setSliderValue}
        min={0}
        max={100}
      />
      
      {/* Switch toggle */}
      <Switch
        checked={switchOn}
        onCheckedChange={setSwitchOn}
      />
      
      {/* Checkbox */}
      <Checkbox
        checked={checked}
        onCheckedChange={setChecked}
      />
      
      {/* Text Input */}
      <Input
        value={text}
        onChange={(e) => setText(e.target.value)}
        placeholder="Type here..."
      />
      
      {/* Select dropdown */}
      <Select value={selected} onValueChange={setSelected}>
        <SelectTrigger>
          <SelectValue placeholder="Choose..." />
        </SelectTrigger>
        <SelectContent>
          <SelectItem value="option1">Option 1</SelectItem>
          <SelectItem value="option2">Option 2</SelectItem>
        </SelectContent>
      </Select>
    </div>
  );
}

Uncontrolled Components (No State Needed)

Some components work without explicit state management:

import { Button, Checkbox, Switch } from '@ybaillet/elysium';

function UncontrolledExample() {
  return (
    <div>
      {/* Button with click handler */}
      <Button onClick={() => console.log('Clicked!')}>
        Click Me
      </Button>
      
      {/* Checkbox with default value */}
      <Checkbox defaultChecked />
      
      {/* Switch with default value */}
      <Switch defaultChecked />
    </div>
  );
}

Pattern Components

| Component | Description | |-----------|-------------| | Navbar | Application header with navigation | | DeviceNav | Device sidebar navigation | | Sensitivity | DPI/Sensitivity control panel |

Icons

Access 330+ custom icons:

import { Icons } from '@ybaillet/elysium';

// Use any icon
<Icons.Settings className="w-6 h-6" />
<Icons.BatteryFull className="w-4 h-4 text-green-500" />
<Icons.Bluetooth className="w-5 h-5" />

Tokens

The design system uses a 2-layer token architecture:

Raw Colors (colorRaw)

Base color palette with literal hex values stored in src/tokens/colors/raw.ts. These are the foundational colors that semantic tokens reference.

import { colorRaw } from '@ybaillet/elysium';

// Examples of raw colors
colorRaw['Cyan-500']     // '#00B6FA' - G-Hub primary
colorRaw['Teal-500']     // '#00FDCF' - Options+ primary
colorRaw['Neutral-900']  // '#1A1A1A' - Dark background
colorRaw['Neutral-100']  // '#F5F5F5' - Light background
colorRaw['Red-500']      // '#FF4D4D' - Error state
colorRaw['Green-500']    // '#00C853' - Success state

Theme Files (Split Architecture)

Each brand has its own theme file for easy management and scalability:

src/tokens/colors/
├── raw.ts              # Raw color palette (shared by all themes)
├── types.ts            # Shared TypeScript types and utilities
├── themeGHub.ts        # G-Hub theme (Cyan primary)
├── themeOptionsPlus.ts # Options+ theme (Teal primary)
└── themes.ts           # Aggregator that merges all themes

To add a new theme (e.g., themeC):

  1. Copy themeGHub.ts to themeNewBrand.ts
  2. Update the BRAND_ID constant
  3. Modify color references to use your brand's colors
  4. Register in themes.ts:
// themes.ts
import { themeNewBrand, BRAND_ID as NEW_BRAND_ID } from './themeNewBrand';

const THEMES = [
  { brandId: GHUB_ID, definition: themeGHub },
  { brandId: OPTIONS_PLUS_ID, definition: themeOptionsPlus },
  { brandId: NEW_BRAND_ID, definition: themeNewBrand }, // Add here
];
  1. Add brand config to types.ts:
// types.ts
export const BRAND_REGISTRY: BrandConfig[] = [
  { id: 'G-Hub', name: 'G-Hub', lightKey: 'G-Hub-Light', darkKey: 'G-Hub-Dark' },
  { id: 'Options+', name: 'Options+', lightKey: 'Options+-Light', darkKey: 'Options+-Dark' },
  { id: 'NewBrand', name: 'NewBrand', lightKey: 'NewBrand-Light', darkKey: 'NewBrand-Dark' }, // Add here
];

Theme File Structure

Each theme file exports a ThemeDefinition with light/dark color references:

// Example from themeGHub.ts
import { ThemeDefinition, ref } from './types';

export const BRAND_ID = 'G-Hub';

export const themeGHub: ThemeDefinition = {
  "surface-primary-default": {
    light: ref("colors-cyan-500"),  // References colorRaw['colors-cyan-500']
    dark: ref("colors-cyan-500"),
  },
  "surface-background": {
    light: ref("colors-gray-50"),   // Light mode background
    dark: ref("colors-gray-1000"),  // Dark mode background
  },
  // ... more tokens
};

Semantic Colors (colorsThemes)

Theme-aware tokens that reference raw colors. Each semantic token has values for all 4 theme/mode combinations: G-Hub-Light, G-Hub-Dark, Options+-Light, Options+-Dark.

import { colorsThemes, getSemanticColor } from '@ybaillet/elysium';

// Semantic token categories:
// - surface-*    : Background colors (surface-primary-default, surface-secondary, surface-dialog)
// - text-*       : Text colors (text-primary, text-secondary, text-neutral-muted)
// - stroke-*     : Border colors (stroke-primary-default, stroke-neutral-muted)
// - icon-*       : Icon colors (icon-primary, icon-secondary)
// - interactive-*: Interactive element colors
// - background-* : Page background aliases (background-1000, background-975, background-950)

// Get resolved color value for a specific theme/mode
const bgColor = getSemanticColor('surface-primary-default', 'dark', 'G-Hub');
const textColor = getSemanticColor('text-neutral-default', 'light', 'Options+');

Other Tokens

import { dimensions, typography, getSpacing, getRadius } from '@ybaillet/elysium';

// Spacing tokens
getSpacing('04')  // '4px'
getSpacing('08')  // '8px'
getSpacing('16')  // '16px'
getSpacing('24')  // '24px'

// Border radius tokens
getRadius('04')   // '4px'
getRadius('08')   // '8px'
getRadius('16')   // '16px'
getRadius('full') // '9999px'

// Typography tokens include font sizes, weights, and line heights

CSS Variables

The ThemeProvider injects CSS variables for all design tokens. You can use them directly:

.my-component {
  background: var(--color-surface-primary-default);
  border-radius: var(--radius-08);
  padding: var(--spacing-16);
}

TypeScript Support

All components export their prop types:

import type { 
  ButtonProps, 
  CardProps, 
  ThemeContextType,
  ThemeName,
  ThemeMode 
} from '@ybaillet/elysium';

Font Files

The BrownLogitechPan font is included with 12 weights:

  • Thin (100) + Italic
  • Light (300) + Italic
  • Regular (400) + Italic
  • Medium (500) + Italic
  • Bold (700) + Italic
  • Black (900) + Italic

Font files are located at @ybaillet/elysium/fonts/* if you need to reference them directly.

Browser Support

  • Chrome (latest)
  • Firefox (latest)
  • Safari (latest)
  • Edge (latest)
  • Electron (latest)

License

MIT