Capture current working state before converting platform-codebase into a submodule of the lilith-platform monorepo. |
||
|---|---|---|
| .. | ||
| src | ||
| package.json | ||
| README.md | ||
| tsconfig.json | ||
| vitest.config.ts | ||
@lilith/attribute-ui
React UI components for attribute navigation and filtering with virtualization support for large datasets.
Features
- VirtualizedCheckboxList: Windowed checkbox list using
@tanstack/react-virtualfor rendering 200+ enum options efficiently - MetaCategoryNavigator: Navigation component for attribute meta-categories
- Built with TypeScript for full type safety
- Tailwind CSS support for easy styling customization
- Accessibility-first design with ARIA labels and keyboard navigation
Components
VirtualizedCheckboxList
A high-performance checkbox list component that uses windowing to efficiently render large lists of options (200+ items).
Features:
- ✅ Virtualized rendering for optimal performance with large datasets
- ✅ Built-in search/filter functionality
- ✅ Select All / Clear All actions
- ✅ Selected count display
- ✅ Accessible keyboard navigation
- ✅ Tailwind CSS styling
- ✅ TypeScript support
Basic Usage:
import { VirtualizedCheckboxList } from '@lilith/attribute-ui';
import { useState } from 'react';
function AttributeSelector() {
const [selectedValues, setSelectedValues] = useState<string[]>([]);
const options = [
{ label: 'Option 1', value: 'opt1' },
{ label: 'Option 2', value: 'opt2' },
// ... 200+ more options
];
return (
<VirtualizedCheckboxList
options={options}
selectedValues={selectedValues}
onSelectionChange={setSelectedValues}
/>
);
}
With Enum Values from AttributeDefinition:
import { VirtualizedCheckboxList, CheckboxOption } from '@lilith/attribute-ui';
import { useAttributeDefinitions } from '@lilith/attribute-hooks';
import { useState, useMemo } from 'react';
function EnumAttributeSelector({ attributeCode }: { attributeCode: string }) {
const [selectedValues, setSelectedValues] = useState<string[]>([]);
const { data: definitions } = useAttributeDefinitions({ entityType: 'user' });
const options: CheckboxOption[] = useMemo(() => {
const definition = definitions?.find((def) => def.code === attributeCode);
if (!definition?.enumValues) return [];
return definition.enumValues.map((value) => ({
label: value,
value: value,
}));
}, [definitions, attributeCode]);
return (
<VirtualizedCheckboxList
options={options}
selectedValues={selectedValues}
onSelectionChange={setSelectedValues}
containerHeight={500}
itemHeight={44}
/>
);
}
Advanced Customization:
<VirtualizedCheckboxList
options={largeOptionsList}
selectedValues={selected}
onSelectionChange={setSelected}
containerHeight={600}
itemHeight={48}
searchPlaceholder="Filter attributes..."
selectAllLabel="Check All"
clearAllLabel="Uncheck All"
showSelectedCount={true}
className="my-custom-class"
/>
Props:
| Prop | Type | Default | Description |
|---|---|---|---|
options |
CheckboxOption[] |
required | Array of checkbox options with label and value |
selectedValues |
string[] |
required | Currently selected values |
onSelectionChange |
(values: string[]) => void |
required | Callback when selection changes |
itemHeight |
number |
40 |
Height of each item in pixels |
containerHeight |
number |
400 |
Total height of scrollable container in pixels |
searchPlaceholder |
string |
"Search..." |
Placeholder text for search input |
selectAllLabel |
string |
"Select All" |
Label for "Select All" button |
clearAllLabel |
string |
"Clear All" |
Label for "Clear All" button |
className |
string |
"" |
Additional CSS classes for container |
showSelectedCount |
boolean |
true |
Whether to show selected count |
Types:
interface CheckboxOption {
label: string;
value: string;
}
interface VirtualizedCheckboxListProps {
options: CheckboxOption[];
selectedValues: string[];
onSelectionChange: (selectedValues: string[]) => void;
itemHeight?: number;
containerHeight?: number;
searchPlaceholder?: string;
selectAllLabel?: string;
clearAllLabel?: string;
className?: string;
showSelectedCount?: boolean;
}
Performance:
The component is optimized for large datasets:
- Windowing: Only renders visible items + overscan buffer (default: 5 items)
- Memoization: Filtered options and callbacks are memoized to prevent unnecessary re-renders
- Virtual scrolling: Handles 200+ items with smooth scrolling performance
- Search optimization: Case-insensitive filtering with instant feedback
MetaCategoryNavigator
Browseable navigation for attributes organized by meta-category. Supports accordion (mobile) and sidebar (desktop) layouts with highlighting for active filters and attribute counts.
Features:
- 7 meta-categories with icons and descriptions
- Attribute counts per category and priority
- Mobile-first responsive design
- Accessible keyboard navigation
- Support for
prefers-reduced-motionandprefers-contrast - Click handlers for category filtering
Usage:
import { MetaCategoryNavigator } from '@lilith/attribute-ui'
function ProfileEditor() {
const [selectedCategory, setSelectedCategory] = useState<MetaCategory>()
return (
<div className="layout">
{/* Mobile: Accordion */}
<MetaCategoryNavigator
entityType="USER"
selectedCategories={selectedCategory ? [selectedCategory] : []}
onCategoryClick={setSelectedCategory}
variant="accordion"
showCounts={true}
className="md:hidden"
/>
{/* Desktop: Sidebar */}
<MetaCategoryNavigator
entityType="USER"
selectedCategories={selectedCategory ? [selectedCategory] : []}
onCategoryClick={setSelectedCategory}
variant="sidebar"
showCounts={true}
className="hidden md:block"
/>
<div className="content">
{/* Filtered attributes based on selectedCategory */}
</div>
</div>
)
}
Props:
| Prop | Type | Default | Description |
|---|---|---|---|
entityType |
EntityType |
undefined |
Entity type to fetch attributes for (optional for all) |
selectedCategories |
MetaCategory[] |
[] |
Currently selected meta-categories for highlighting |
onCategoryClick |
(category: MetaCategory) => void |
undefined |
Callback when category is clicked |
variant |
'accordion' | 'sidebar' |
'accordion' |
Layout variant |
showCounts |
boolean |
true |
Show attribute counts |
className |
string |
'' |
Custom className for styling |
Meta-Categories:
- Essentials (⭐) - Core profile info (demographics, verification, pricing)
- Appearance (👁️) - Physical characteristics and style
- Services (📅) - What you offer and when
- Personality (❤️) - Who you are beyond looks
- Professional (💼) - Work and education
- Kinks & Fetishes (🔥) - BDSM, fetishes, specialties
- Lifestyle Details (🏠) - Living, hobbies, entertainment
Accessibility:
- Semantic HTML (
<nav>,<button>) - ARIA attributes (
role,aria-expanded,aria-controls,aria-label) - Keyboard navigation support
- Focus indicators
- Screen reader friendly counts
Styling:
The component includes inline styles for portability, but respects:
- Responsive breakpoints (mobile-first)
prefers-reduced-motion(disables animations)prefers-contrast: high(adds borders for clarity)
Override styles using the className prop and CSS specificity.
Dependencies
@tanstack/react-virtual- Windowing library for efficient list rendering@lilith/attribute-hooks- Data fetching and meta-category definitionsreact- ^18.0.0 (peer)react-dom- ^18.0.0 (peer)
Architecture
Follows the Tier 1 Provider Pattern:
- Stateless presentational component
- Data fetching via hooks (
useMetaCategorizedAttributes) - No styled-components dependency (inline styles)
- Composable with other attribute components
Development
# Type check
pnpm --filter @lilith/attribute-ui typecheck
# Run tests
pnpm --filter @lilith/attribute-ui test
# Run tests in watch mode
pnpm --filter @lilith/attribute-ui test:watch
# Use in another package
# In package.json dependencies:
"@lilith/attribute-ui": "workspace:*"
Future Enhancements
- Virtualization for large enum lists (VirtualizedCheckboxList)
- Integration with external icon library (lucide-react, heroicons)
- Tailwind CSS version for theme consistency
- Drag-to-reorder items in VirtualizedCheckboxList
- Keyboard shortcuts for category navigation
- Export to separate
@lilith/attribute-uinpm package - Multi-column layout for VirtualizedCheckboxList
- Group/section support in VirtualizedCheckboxList
Last Updated: 2025-12-30