Skip to content

hannasage/projection-ui

Repository files navigation

@hannasage/projection-ui

Dark-first React component library with consumer-configurable theming. No hardcoded themes — you define your palette, the library renders it.

Installation

npm install @hannasage/projection-ui

Peer dependencies

npm install react react-dom recharts zustand @dnd-kit/core @dnd-kit/sortable @dnd-kit/utilities

Quick start

1. Import the fallback tokens (optional but recommended)

In your entry file (main.tsx or index.tsx):

import '@hannasage/projection-ui/tokens'

This loads a set of CSS custom property defaults. If you wrap your app with ThemeProvider, these are overridden by your theme — but they act as a safe fallback.

2. Define your theme

import type { UITheme } from '@hannasage/projection-ui'

const myTheme: UITheme = {
  bg:        '#07090C',   // page background
  surface:   '#0D1117',   // card / panel
  border:    '#1B2535',   // borders
  text:      '#DDE3EE',   // primary text
  muted:     '#8396AB',   // secondary text / labels
  primary:   '#C9F53A',   // accent — buttons, focus rings
  primaryFg: '#07090C',   // text on top of primary (e.g. button label)
  danger:    '#FF5252',   // destructive actions
  font:      "'IBM Plex Mono', monospace",
  radius:    'soft',      // 'sharp' | 'soft' | 'rounded'
}

Radius presets:

preset buttons/inputs cards pills/toggles
sharp 2px 4px 4px (no pill)
soft 6px 10px 9999px
rounded 16px 24px 9999px

3. Wrap your app

import { ThemeProvider, ToastContainer } from '@hannasage/projection-ui'

export default function App() {
  return (
    <ThemeProvider theme={myTheme}>
      <YourApp />
      <ToastContainer />
    </ThemeProvider>
  )
}

Switching themes is instant — pass a new theme object and all --ui-* CSS variables update automatically.


Component reference

Layout

Component Description
ThemeProvider Writes CSS vars from your theme. Wrap your app root.
Card Surface container. Props: padding, border, as, className

Actions

Component Description
Button Variants: primary secondary ghost danger. Sizes: sm md lg.
ButtonGroup Segmented control / tab bar. Mutually exclusive options with optional deselect.

Forms

Component Description
Input Text input with label, error, hint, prefix/suffix slots
Select Styled native select with chevron
Textarea Resizable textarea with label, error, hint
Toggle On/off switch. Sizes: sm md
Slider Range input with fill track, value display, and min/max labels

Feedback

Component Description
Modal Accessible dialog. Closes on Escape + backdrop click.
ToastContainer Notification portal. Use useToastStore().push(message, variant) to trigger.
Skeleton Shimmer placeholder. Configurable width, height, borderRadius.

Data

Component Description
DataTable Sortable columns, loading skeletons, empty state slot, row click handler

Drag and drop

Component Description
SortableList Wraps @dnd-kit DndContext + SortableContext
SortableItem Render-prop item exposing dragHandleProps and isDragging

Charts (Recharts wrappers)

Component Description
AreaChart Gradient fill area chart
BarChart Grouped or stacked bar chart
LineChart Multi-series line chart
DonutChart Pie/donut with optional center label slot

All charts accept data, series (array of { key, color, label }), xKey, height, title, xFormatter, yFormatter.


Toast usage

import { useToastStore } from '@hannasage/projection-ui'

function MyComponent() {
  const toast = useToastStore(s => s.push)

  return (
    <button onClick={() => toast('Saved!', 'success')}>
      Save
    </button>
  )
}

Variants: info | success | warning | danger


Dynamic theming

ThemeProvider is just a div that writes CSS vars — swapping themes is a single state update:

const [theme, setTheme] = useState<UITheme>(darkTheme)

<ThemeProvider theme={theme}>
  <button onClick={() => setTheme(lightTheme)}>Toggle theme</button>
</ThemeProvider>

Used in


License

MIT

About

React-based UI library with customizable themeing built-in for use across my own projects (and yours, if you want).

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors