No description
|
Some checks failed
Publish / publish (push) Failing after 1s
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com> |
||
|---|---|---|
| .forgejo/workflows | ||
| src | ||
| .gitignore | ||
| eslint.config.js | ||
| package.json | ||
| README.md | ||
| tsconfig.json | ||
| tsconfig.tsbuildinfo | ||
@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
transformandopacityfor 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