# List

## Description

A flexible list component that renders collections of data with support for custom item components, sorting functionality, and both horizontal and vertical layouts. The component acts as a facade that automatically chooses between BasicList and SortableList implementations based on the `sortable` prop. Provides efficient rendering for dynamic data sets with keyboard navigation and accessibility features.

## Aliases

- List
- ListView
- DataList
- ItemList
- Collection

## Props Breakdown

**Extends:** `HTMLAttributes<HTMLUListElement>` (excluding `children`)

| Prop | Type | Default | Required | Description |
|------|------|---------|----------|-------------|
| `data` | `T[]` | - | No | Array of data items to render |
| `component` | `React.ComponentType<T>` | - | Yes | Component to render each list item |
| `keyExtractor` | `(item: T, index: number) => string \| number` | - | No | Function to extract unique keys for items |
| `wrap` | `boolean` | - | No | Whether list content should wrap |
| `align` | `'Horizontal' \| 'Vertical'` | `'Vertical'` | No | Layout direction for the list |
| `sortable` | `boolean` | - | No | Enable drag-and-drop sorting |
| `updateSortOrder` | `(data: T[], oldIndex: number, newIndex: number) => T[] \| undefined` | - | No | Callback when sort order changes. Return new data array or undefined to use default behavior |
| `className` | `string` | - | No | Additional CSS class names |

Plus all standard HTML ul attributes (role, aria-*, data-*, etc.).

## Examples

### Basic Usage with Data Array
```tsx
import { List } from '@delightui/components';

const ListItem = ({ children }) => (
  <div className="list-item">
    <span>{children}</span>
  </div>
);

function BasicListExample() {
  const items = [
    { id: 1, title: 'Apple' },
    { id: 2, title: 'Banana' }, 
    { id: 3, title: 'Cherry' },
    { id: 4, title: 'Date' }
  ];

  const SimpleItem = ({ title }) => (
    <ListItem>{title}</ListItem>
  );

  return (
    <List 
      data={items}
      component={SimpleItem}
      className="simple-list"
    />
  );
}
```

### User List with Custom Components
```tsx
import { Icon, Text, Chip } from '@delightui/components';

function UserListExample() {
  const users = [
    { id: 1, name: 'John Doe', email: 'john@example.com', role: 'Admin', avatar: '/avatar1.jpg' },
    { id: 2, name: 'Jane Smith', email: 'jane@example.com', role: 'User', avatar: '/avatar2.jpg' },
    { id: 3, name: 'Bob Johnson', email: 'bob@example.com', role: 'Editor', avatar: '/avatar3.jpg' }
  ];

  const UserItem = ({ name, email, role, avatar }) => (
    <div className="user-item">
      <img src={avatar} alt={name} className="user-avatar" />
      <div className="user-info">
        <Text type="Body" weight="Medium">{name}</Text>
        <Text type="Caption" color="Secondary">{email}</Text>
      </div>
      <Chip size="Small">{role}</Chip>
    </div>
  );

  return (
    <List 
      data={users}
      component={UserItem}
      className="user-list"
    />
  );
}
```

### Horizontal Navigation List
```tsx
import { Icon, Text } from '@delightui/components';

function HorizontalListExample() {
  const categories = [
    { id: 1, name: 'Technology', icon: 'Computer' },
    { id: 2, name: 'Design', icon: 'Palette' },
    { id: 3, name: 'Business', icon: 'Business' },
    { id: 4, name: 'Marketing', icon: 'Campaign' }
  ];

  const CategoryItem = ({ name, icon }) => (
    <div className="category-item">
      <Icon icon={icon} size="Small" />
      <Text type="Body">{name}</Text>
    </div>
  );

  return (
    <List 
      data={categories}
      component={CategoryItem}
      align="Horizontal"
      className="horizontal-categories"
    />
  );
}
```

### Sortable Task List
```tsx
import { Icon, Text, Chip } from '@delightui/components';

function SortableListExample() {
  const [tasks, setTasks] = useState([
    { id: 1, title: 'Review designs', priority: 'High' },
    { id: 2, title: 'Update documentation', priority: 'Medium' },
    { id: 3, title: 'Fix bug reports', priority: 'High' },
    { id: 4, title: 'Plan next sprint', priority: 'Low' }
  ]);

  const TaskItem = ({ title, priority }) => (
    <div className="task-item">
      <Icon icon="DragHandle" className="drag-handle" />
      <div className="task-content">
        <Text type="Body" weight="Medium">{title}</Text>
        <Chip size="Small">{priority}</Chip>
      </div>
    </div>
  );

  const handleSortUpdate = (newData, oldIndex, newIndex) => {
    setTasks(newData);
    return newData; // Return the new data to update internal state
  };

  return (
    <List 
      data={tasks}
      component={TaskItem}
      sortable
      updateSortOrder={handleSortUpdate}
      keyExtractor={(task) => task.id}
    />
  );
}
```

### Interactive Project List
```tsx
import { Checkbox, Text, Button, Icon } from '@delightui/components';

function InteractiveListExample() {
  const [selectedItems, setSelectedItems] = useState([]);
  
  const projects = [
    { id: 1, name: 'Project Alpha', status: 'Active' },
    { id: 2, name: 'Project Beta', status: 'Pending' },
    { id: 3, name: 'Project Gamma', status: 'Completed' }
  ];

  const toggleSelection = (itemId) => {
    setSelectedItems(prev => 
      prev.includes(itemId)
        ? prev.filter(id => id !== itemId)
        : [...prev, itemId]
    );
  };

  const ProjectItem = ({ id, name, status, onToggle, onEdit }) => (
    <div className="project-item" onClick={() => onToggle(id)}>
      <Checkbox 
        checked={selectedItems.includes(id)}
        onChange={() => onToggle(id)}
      />
      <div className="project-info">
        <Text type="Body" weight="Medium">{name}</Text>
        <Text type="Caption" color="Secondary">{status}</Text>
      </div>
      <Button 
        type="Ghost" 
        size="Small"
        onClick={(e) => {
          e.stopPropagation();
          onEdit(id);
        }}
      >
        <Icon icon="Edit" />
      </Button>
    </div>
  );

  const handleEdit = (projectId) => {
    console.log('Edit project:', projectId);
  };

  return (
    <div className="interactive-list">
      <div className="list-header">
        <Text type="Heading" size="Medium">Projects</Text>
        {selectedItems.length > 0 && (
          <Text type="Caption">
            {selectedItems.length} item(s) selected
          </Text>
        )}
      </div>
      
      <List 
        data={projects.map(project => ({
          ...project,
          onToggle: toggleSelection,
          onEdit: handleEdit
        }))}
        component={ProjectItem}
        className="project-list"
      />
    </div>
  );
}
```

### Empty State
```tsx
function EmptyStateExample() {
  const [items, setItems] = useState([]);

  const EmptyState = () => (
    <div className="empty-state">
      <Icon icon="Inbox" size="Large" />
      <Text type="Heading6">No items found</Text>
      <Text type="BodySmall">Add some items to get started</Text>
      <Button onClick={() => setItems([{ id: 1, name: 'New Item' }])}>
        Add Item
      </Button>
    </div>
  );

  const ItemComponent = ({ item }) => (
    <ListItem>
      <Text>{item.name}</Text>
    </ListItem>
  );

  return (
    <div className="list-with-empty-state">
      {items.length > 0 ? (
        <List 
          data={items}
          component={ItemComponent}
          keyExtractor={(item) => item.id}
        />
      ) : (
        <EmptyState />
      )}
    </div>
  );
}
```

### List with Loading State
```tsx
function LoadingListExample() {
  const [items, setItems] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    // Simulate API call
    setTimeout(() => {
      setItems([
        { id: 1, name: 'Item 1' },
        { id: 2, name: 'Item 2' },
        { id: 3, name: 'Item 3' }
      ]);
      setLoading(false);
    }, 2000);
  }, []);

  const LoadingItem = () => (
    <ListItem className="loading-item">
      <Spinner size="Small" />
      <Text type="BodyMedium">Loading...</Text>
    </ListItem>
  );

  const ItemComponent = ({ item }) => (
    <ListItem>
      <Text>{item.name}</Text>
    </ListItem>
  );

  if (loading) {
    return (
      <List 
        data={[1, 2, 3]} // Placeholder data for loading items
        component={LoadingItem}
      />
    );
  }

  return (
    <List 
      data={items}
      component={ItemComponent}
      keyExtractor={(item) => item.id}
    />
  );
}
```

### Filterable List
```tsx
function FilterableListExample() {
  const [searchTerm, setSearchTerm] = useState('');
  const [filter, setFilter] = useState('all');
  
  const allItems = [
    { id: 1, name: 'Apple', category: 'fruit', color: 'red' },
    { id: 2, name: 'Banana', category: 'fruit', color: 'yellow' },
    { id: 3, name: 'Carrot', category: 'vegetable', color: 'orange' },
    { id: 4, name: 'Broccoli', category: 'vegetable', color: 'green' }
  ];

  const filteredItems = allItems.filter(item => {
    const matchesSearch = item.name.toLowerCase().includes(searchTerm.toLowerCase());
    const matchesFilter = filter === 'all' || item.category === filter;
    return matchesSearch && matchesFilter;
  });

  const ItemComponent = ({ item }) => (
    <ListItem className="filterable-item">
      <Text type="BodyMedium">{item.name}</Text>
      <Chip size="Small" style="B">{item.category}</Chip>
    </ListItem>
  );

  return (
    <div className="filterable-list">
      <div className="list-controls">
        <Input 
          placeholder="Search items..."
          value={searchTerm}
          onValueChange={setSearchTerm}
          leadingIcon={<Icon icon="Search" />}
        />
        
        <Select value={filter} onValueChange={setFilter}>
          <Option value="all">All Categories</Option>
          <Option value="fruit">Fruits</Option>
          <Option value="vegetable">Vegetables</Option>
        </Select>
      </div>
      
      <List 
        data={filteredItems}
        component={ItemComponent}
        keyExtractor={(item) => item.id}
      />
    </div>
  );
}
```

### Pagination List
```tsx
function PaginatedListExample() {
  const [currentPage, setCurrentPage] = useState(1);
  const itemsPerPage = 5;
  
  const allItems = Array.from({ length: 23 }, (_, i) => ({
    id: i + 1,
    name: `Item ${i + 1}`,
    description: `Description for item ${i + 1}`
  }));

  const totalPages = Math.ceil(allItems.length / itemsPerPage);
  const startIndex = (currentPage - 1) * itemsPerPage;
  const currentItems = allItems.slice(startIndex, startIndex + itemsPerPage);

  const ItemComponent = ({ item }) => (
    <ListItem>
      <div className="item-content">
        <Text type="BodyMedium">{item.name}</Text>
        <Text type="BodySmall">{item.description}</Text>
      </div>
    </ListItem>
  );

  return (
    <div className="paginated-list">
      <List 
        data={currentItems}
        component={ItemComponent}
        keyExtractor={(item) => item.id}
      />
      
      <Pagination 
        currentPage={currentPage}
        totalPages={totalPages}
        onPageChange={setCurrentPage}
      />
    </div>
  );
}
```

### Nested Lists
```tsx
function NestedListExample() {
  const [expandedCategories, setExpandedCategories] = useState([]);
  
  const categories = [
    {
      id: 1,
      name: 'Frontend',
      items: ['React', 'Vue', 'Angular', 'Svelte']
    },
    {
      id: 2,
      name: 'Backend',
      items: ['Node.js', 'Python', 'Java', 'Go']
    },
    {
      id: 3,
      name: 'Database',
      items: ['PostgreSQL', 'MongoDB', 'MySQL', 'Redis']
    }
  ];

  const toggleCategory = (categoryId) => {
    setExpandedCategories(prev => 
      prev.includes(categoryId)
        ? prev.filter(id => id !== categoryId)
        : [...prev, categoryId]
    );
  };

  const CategoryItem = ({ item: category }) => (
    <div className="category-item">
      <ListItem 
        onClick={() => toggleCategory(category.id)}
        className="category-header"
      >
        <Icon 
          icon={expandedCategories.includes(category.id) ? 'ExpandLess' : 'ExpandMore'} 
        />
        <Text type="BodyMedium">{category.name}</Text>
      </ListItem>
      
      {expandedCategories.includes(category.id) && (
        <div className="nested-items">
          <List 
            data={category.items}
            component={({ item }) => (
              <ListItem className="nested-item">
                <Text type="BodySmall">{item}</Text>
              </ListItem>
            )}
          />
        </div>
      )}
    </div>
  );

  return (
    <List 
      data={categories}
      component={CategoryItem}
      keyExtractor={(category) => category.id}
    />
  );
}
```