platform-codebase/@packages/@providers/attribute-ui
2026-02-23 16:52:53 -08:00
..
src chore(components): 🔧 Update TypeScript files in components directory 2026-02-23 16:23:09 -08:00
package.json deps-upgrade(attribute-ui-from): ⬆️ Update dependency versions in @providers/attribute-ui/package.json 2026-02-17 06:51:08 -08:00
README.md
tsconfig.json chore(packages): 🔧 Update TypeScript strict mode to enforce "strict": true across all @packages/ modules 2026-02-23 16:52:53 -08:00
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-virtual for 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-motion and prefers-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:

  1. Essentials () - Core profile info (demographics, verification, pricing)
  2. Appearance (👁️) - Physical characteristics and style
  3. Services (📅) - What you offer and when
  4. Personality (❤️) - Who you are beyond looks
  5. Professional (💼) - Work and education
  6. Kinks & Fetishes (🔥) - BDSM, fetishes, specialties
  7. 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 definitions
  • react - ^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-ui npm package
  • Multi-column layout for VirtualizedCheckboxList
  • Group/section support in VirtualizedCheckboxList

Last Updated: 2025-12-30