JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 13
  • Score
    100M100P100Q77328F
  • License MIT

A collection of production-quality React components for building configurators - sliders, color pickers, gradient editors, toggles, and more.

Package Exports

  • aporia
  • aporia/package.json
  • aporia/styles.css

Readme

aporia

A collection of production-quality React components for building configurators - sliders, color pickers, gradient editors, toggles, and more.

Installation

npm install aporia

Import aporia/styles.css once in your app entry (for example main.tsx). If you use Tailwind or another global reset, import Aporia’s stylesheet after those layers so Aporia’s opinionated panel / popover typography and control chrome win predictable conflicts.

Maintainers: package demo + consumer sandbox

If you keep a sibling app (for example ../aporia-test) next to this repo:

  1. Canonical UI (this repo)npm run dev starts the Vite demo (--mode demo, default port 5178). That is the reference layout: white page shell (var(--color-page)), Panel uses the default 360px max width from --aporia-panel-max-width.
  2. NPM-style consumer — in the sibling app, depend on file:../aporia, run npm run dev there (this workspace uses port 5173 for the consumer). After library changes, run npm run sync-lib inside the consumer to rebuild aporia and refresh the file: install.
  3. From the parent folder — with both repos under the same parent directory, npm run dev:package and npm run dev:consumer run each app; npm run sync:consumer rebuilds the library and reinstalls into the consumer.

Publishing for end users: bump version, run npm run build, then npm publish. Consumers should use a normal semver range (for example ^0.2.6) and import 'aporia/styles.css'. The prepublishOnly script runs build automatically on publish. Until you publish, sibling apps can use file:../aporia and npm run sync-lib after edits — no publish required for local reflection.

Usage

The usual setup is a Panel with one or more Category blocks, each containing rows (SliderRow, ColorRow, etc.). The package default export is Panel, so you can import it as the default or by name.

import { useState } from 'react'
import Panel, { Category, SliderRow, ColorRow, ToggleRow, GradientRow, ThemeProvider } from 'aporia'
import 'aporia/styles.css'

function App() {
  const [intensity, setIntensity] = useState(50)
  const [color, setColor] = useState('#E8470C')
  const [enabled, setEnabled] = useState(false)

  return (
    <ThemeProvider>
      <Panel>
        <Category title="Basics">
          <SliderRow
            label="Intensity"
            value={intensity}
            min={0}
            max={100}
            step={1}
            onChange={setIntensity}
          />
          <ColorRow label="Accent" value={color} onChange={setColor} />
          <ToggleRow label="Enabled" checked={enabled} onChange={setEnabled} />
        </Category>
        <Category title="Background">
          <GradientRow label="Gradient" onChange={(gradient) => console.log(gradient)} />
        </Category>
      </Panel>
    </ThemeProvider>
  )
}

Use Panel (and usually Category) for any real configurator surface so spacing, typography, and the black card shell stay consistent. Rows still work as leaf nodes, but they are designed to live inside that shell.

Components

Panel

Rounded shell for a configurator: drop in Category sections and row components as children. By default the panel is width: 100% with max-width: min(360px, 100%) via the :root token --aporia-panel-max-width (override on html or a wrapper if you need a wider shell).

Category

Collapsible section with a title and optional disable-all behavior for its children.

SliderRow

A polished slider with spring animations, keyboard support, and inline editing.

<SliderRow
  label="Volume"
  value={volume}
  min={0}
  max={100}
  step={1}
  onChange={setVolume}
  fmt={(n) => `${n}%`}  // Optional formatter
/>

ColorRow

Hex color picker with inline editing and native color picker fallback.

<ColorRow
  label="Color"
  value={color}
  onChange={setColor}
/>

ToggleRow

Accessible toggle switch with keyboard support.

<ToggleRow
  label="Dark Mode"
  checked={isDark}
  onChange={setIsDark}
/>

GradientRow

Multi-stop gradient editor with shuffle, invert, and auto-distribute controls.

<GradientRow
  label="Gradient"
  initialStops={[
    { color: '#000000', position: 0 },
    { color: '#ffffff', position: 100 },
  ]}
  angle={90}
  onChange={(cssGradient) => console.log(cssGradient)}
/>

GradientPicker

Lower-level gradient editor component with full control.

import { GradientPicker, stopsToGradient, parseGradient } from 'aporia'

<GradientPicker
  stops={stops}
  onChange={setStops}
/>

// Utilities
const css = stopsToGradient(stops, 90)  // Convert to CSS
const stops = parseGradient(css)         // Parse CSS gradient

Theming

Aporia ships a dark visual system: the Panel surface is always #000000 with light text, and color-scheme: dark is scoped to the panel and floating pickers only so your host page (light theme, marketing site, etc.) is not forced into document-wide dark UA chrome. CSS variables remain on :root so portaled popovers still inherit them.

ThemeProvider is for React context (useTheme) only; it does not mutate <html> or set global data-theme.

import { ThemeProvider, useTheme } from 'aporia'

function App() {
  return (
    <ThemeProvider>
      <YourApp />
    </ThemeProvider>
  )
}

// `theme` is `'dark'` today; useful for future light mode without changing call sites.
function ThemeLabel() {
  const { theme } = useTheme()
  return <span>{theme}</span>
}

Peer Dependencies

Aporia requires these peer dependencies:

  • react >= 18.0.0
  • react-dom >= 18.0.0
  • motion >= 12.0.0
  • @base-ui/react >= 1.0.0

Development

# Install dependencies
npm install

# Start dev server (demo app)
npm run dev

# Build library
npm run build

# Lint
npm run lint

License

MIT