No description
Find a file
autocommit f583d5f244
Some checks failed
Publish / publish (push) Failing after 1s
deps-upgrade(deps): ⬆️ Update dependencies to latest stable versions for bug fixes and performance improvements
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-10 21:23:21 -07:00
.forgejo/workflows chore: initial package split from monorepo 2026-04-20 01:11:27 -07:00
src chore: initial package split from monorepo 2026-04-20 01:11:27 -07:00
.gitignore chore: add .gitignore, remove node_modules/dist/.turbo from tracking 2026-04-20 01:13:08 -07:00
eslint.config.js chore: initial package split from monorepo 2026-04-20 01:11:27 -07:00
package.json deps-upgrade(deps): ⬆️ Update dependencies to latest stable versions for bug fixes and performance improvements 2026-06-10 21:23:21 -07:00
README.md chore: initial package split from monorepo 2026-04-20 01:11:27 -07:00
tsconfig.json chore: initial package split from monorepo 2026-04-20 01:11:27 -07:00
tsconfig.tsbuildinfo chore: initial package split from monorepo 2026-04-20 01:11:27 -07:00

@ui/interactive-grid

Interactive grid components with stunning circular quadrant layouts for React applications.

Installation

pnpm add @ui/interactive-grid

Features

  • 🎯 Circular Quadrant Grid - 4-option selection interface with orbital animations
  • Pure CSS-in-JS - Styled-components with hardware-accelerated animations
  • Accessibility-first - Respects prefers-reduced-motion and high-contrast
  • 📱 Responsive - Mobile-optimized with touch support
  • 🎨 Customizable - Flexible gradients, colors, and center content
  • 🔧 TypeScript - Full type safety with generic support
  • 🎭 Framer Motion - Smooth entrance and hover animations

Quick Start

import { QuadrantGrid } from '@ui/interactive-grid'
import type { QuadrantConfig } from '@ui/interactive-grid'

const quadrants: [QuadrantConfig, QuadrantConfig, QuadrantConfig, QuadrantConfig] = [
  {
    id: 'option-1',
    label: 'Option 1',
    gradient: 'linear-gradient(135deg, #FFD700 0%, #FF8C00 100%)',
  },
  {
    id: 'option-2',
    label: 'Option 2',
    gradient: 'linear-gradient(225deg, #4169E1 0%, #00BFFF 100%)',
  },
  {
    id: 'option-3',
    label: 'Option 3',
    gradient: 'linear-gradient(45deg, #32CD32 0%, #7FFF00 100%)',
  },
  {
    id: 'option-4',
    label: 'Option 4',
    gradient: 'linear-gradient(315deg, #DC143C 0%, #FF6347 100%)',
  },
]

function SelectionInterface() {
  const [selected, setSelected] = useState(null)

  return (
    <QuadrantGrid
      quadrants={quadrants}
      onQuadrantClick={(id) => setSelected(id)}
      centerContent={<p>Choose an option</p>}
    />
  )
}

Component API

<QuadrantGrid />

Interactive circular grid with 4 quadrants arranged in a circle.

Props:

interface QuadrantGridProps<T = string> {
  /** Array of 4 quadrant configurations (required) */
  quadrants: [QuadrantConfig<T>, QuadrantConfig<T>, QuadrantConfig<T>, QuadrantConfig<T>]

  /** Callback when quadrant is clicked (required) */
  onQuadrantClick: (quadrantId: T, event: React.MouseEvent<HTMLDivElement>) => void

  /** Callback when quadrant is hovered (optional) */
  onQuadrantHover?: (quadrantId: T | null) => void

  /** Currently hovered quadrant ID (optional) */
  hoveredQuadrant?: T | null

  /** Disable animations for reduced motion (default: false) */
  disableAnimations?: boolean

  /** Center content to display (optional) */
  centerContent?: React.ReactNode

  /** Center click handler (optional) */
  onCenterClick?: () => void
}

QuadrantConfig Type:

interface QuadrantConfig<T = string> {
  /** Unique identifier for this quadrant */
  id: T
  /** Display label */
  label: string
  /** Background gradient CSS */
  gradient: string
  /** Optional hover text */
  hoverText?: string
}

Advanced Usage

With TypeScript Enums

import { QuadrantGrid } from '@ui/interactive-grid'
import type { QuadrantConfig } from '@ui/interactive-grid'

enum UserType {
  Client = 'client',
  Provider = 'provider',
  Creator = 'creator',
  Fan = 'fan',
}

const userTypeQuadrants: [
  QuadrantConfig<UserType>,
  QuadrantConfig<UserType>,
  QuadrantConfig<UserType>,
  QuadrantConfig<UserType>
] = [
  {
    id: UserType.Client,
    label: 'Client',
    gradient: 'linear-gradient(135deg, #FFD700 0%, #FF8C00 100%)',
    hoverText: 'Find services',
  },
  {
    id: UserType.Provider,
    label: 'Provider',
    gradient: 'linear-gradient(225deg, #4169E1 0%, #00BFFF 100%)',
    hoverText: 'Offer services',
  },
  {
    id: UserType.Creator,
    label: 'Creator',
    gradient: 'linear-gradient(45deg, #32CD32 0%, #7FFF00 100%)',
    hoverText: 'Create content',
  },
  {
    id: UserType.Fan,
    label: 'Fan',
    gradient: 'linear-gradient(315deg, #DC143C 0%, #FF6347 100%)',
    hoverText: 'Support creators',
  },
]

function UserTypeSelector() {
  const [selected, setSelected] = useState<UserType | null>(null)
  const [hovered, setHovered] = useState<UserType | null>(null)

  const centerText = hovered
    ? userTypeQuadrants.find((q) => q.id === hovered)?.hoverText
    : 'Choose your path'

  return (
    <QuadrantGrid
      quadrants={userTypeQuadrants}
      onQuadrantClick={(userType) => setSelected(userType)}
      onQuadrantHover={setHovered}
      hoveredQuadrant={hovered}
      centerContent={<p>{centerText}</p>}
    />
  )
}

With Accessibility

import { QuadrantGrid } from '@ui/interactive-grid'
import { useReducedMotion } from '@ui/accessibility'

function AccessibleGrid() {
  const prefersReducedMotion = useReducedMotion()

  return (
    <QuadrantGrid
      quadrants={quadrants}
      onQuadrantClick={handleClick}
      disableAnimations={prefersReducedMotion}
    />
  )
}

With Custom Center Content

import { QuadrantGrid } from '@ui/interactive-grid'
import { useState } from 'react'

function InteractiveGrid() {
  const [clicks, setClicks] = useState(0)

  return (
    <QuadrantGrid
      quadrants={quadrants}
      onQuadrantClick={handleClick}
      centerContent={
        <div>
          <p>Center Text</p>
          <small>{clicks} clicks</small>
        </div>
      }
      onCenterClick={() => setClicks((c) => c + 1)}
    />
  )
}

How It Works

Circular Layout

Quadrants are positioned using CSS absolute positioning in a circular arrangement:

  • Quadrant 1 (top-left): border-radius: 100% 0 0 0
  • Quadrant 2 (top-right): border-radius: 0 100% 0 0
  • Quadrant 3 (bottom-left): border-radius: 0 0 0 100%
  • Quadrant 4 (bottom-right): border-radius: 0 0 100% 0

Orbital Animations

Two rotating conic gradients create orbital light sweeps:

background: conic-gradient(
  from 0deg,
  transparent 0deg,
  transparent 330deg,
  rgba(255, 255, 255, 0.15) 345deg,
  rgba(255, 255, 255, 0.4) 355deg,
  rgba(255, 255, 255, 0.15) 360deg
);
animation: orbitalSweep 12s linear infinite;

Glass Effect

Each quadrant has a shimmer sweep overlay:

background: linear-gradient(
    135deg,
    rgba(255, 255, 255, 0.4) 0%,
    rgba(255, 255, 255, 0.1) 30%,
    transparent 60%
  ),
  linear-gradient(
    90deg,
    transparent 0%,
    transparent 40%,
    rgba(255, 255, 255, 0.3) 50%,
    transparent 60%,
    transparent 100%
  );

Idle Glow Animations

Each quadrant breathes with a subtle glow effect, staggered by 1.5s delays for a flowing visual rhythm.

Accessibility

Automatic accessibility features:

  • prefers-reduced-motion: Disables all animations when user prefers reduced motion
  • High contrast mode: Removes glass effects, uses solid text colors
  • Touch support: Optimized hover states for touch devices (no hover on mobile)
  • Keyboard navigation: Proper focus states for keyboard users
  • Semantic HTML: Uses motion.div from Framer Motion for accessible animations

Performance

  • Hardware accelerated: Uses transform and opacity for 60fps animations
  • RequestAnimationFrame: Smooth animations via Framer Motion
  • CSS-in-JS: Styled-components with no external CSS files
  • Lazy rendering: AnimatePresence for center content
  • Mobile optimized: Responsive sizing with clamp()

Browser Support

  • Chrome/Edge: Full support
  • Firefox: Full support
  • Safari: Full support
  • Mobile: Full support with touch optimizations

License

MIT © Lilith Platform