cascade_chips 0.0.2 copy "cascade_chips: ^0.0.2" to clipboard
cascade_chips: ^0.0.2 copied to clipboard

A stylish and animated chip component for filtering and navigating through hierarchical data.

example/lib/main.dart

import 'package:cascade_chips/cascade_chips.dart';
import 'package:cascade_chips/cascade_node.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Cascade Chips Demo',
      theme: ThemeData(
        useMaterial3: true,
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
      ),
      home: const MyHomePage(),
    );
  }
}

// In a real app, this would likely be in its own file (e.g., 'models/product.dart').
class Product {
  final String name;
  final String brand;
  final String categoryId;

  const Product({
    required this.name,
    required this.brand,
    required this.categoryId,
  });
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  // State for the example app
  List<Product> _products = [];
  bool _isLoading = true;

  // Data sources for the example
  late final List<CascadeNode> _rootCategories;
  late final List<Product> _allTransactions;

  @override
  void initState() {
    super.initState();

    _rootCategories = _sampleTree();
    _allTransactions = _generateSampleProducts();
    // Fetch initial data with no filters
    _fetchTransactions(List.empty());
  }

  /// Simulates fetching data from a source based on the selected filters.
  Future<void> _fetchTransactions(List<CascadeNode> activeFilters) async {
    setState(() => _isLoading = true);
    await Future.delayed(const Duration(milliseconds: 500));
    List<Product> results;
    if (activeFilters.isEmpty) {
      results = List.from(_allTransactions);
    } else {
      final lastSelectedCategoryId = activeFilters.last.id;
      results = _allTransactions.where((t) => t.categoryId.startsWith(lastSelectedCategoryId)).toList();
    }
    setState(() {
      _products = results;
      _isLoading = false;
    });
  }

  /// Builds the content area that displays loading, empty, or data states.
  Widget _buildContentArea() {
    if (_isLoading) {
      return const Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            CircularProgressIndicator(),
            SizedBox(height: 16),
            Text('Loading...'),
          ],
        ),
      );
    }
    if (_products.isEmpty) {
      return const Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Icon(Icons.search_off, size: 64, color: Colors.grey),
            SizedBox(height: 16),
            Text(
              'No Results Found',
              style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
            ),
            SizedBox(height: 8),
            Text(
              'No transactions were found for the selected filter.',
              textAlign: TextAlign.center,
              style: TextStyle(color: Colors.grey),
            ),
          ],
        ),
      );
    }
    return ListView.builder(
      itemCount: _products.length,
      itemBuilder: (context, index) {
        final product = _products[index];
        return ListTile(
          title: Text(product.name),
          subtitle: Text(product.brand),
          trailing: const Icon(Icons.arrow_forward_ios, size: 14),
        );
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    final myInitialFilterIds = ['apparel', 'apparel_womens', 'apparel_womens_dresses'];

    return Scaffold(
        appBar: AppBar(
          title: const Text('Cascade Chips Example'),
          backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        ),
        body: Column(
          children: [
            Padding(
              padding: const EdgeInsets.all(16.0),
              child: CascadeChips(
                nodes: _rootCategories,
                initialPathIds: myInitialFilterIds,
                onFilterChanged: (activeFilters) {
                  _fetchTransactions(activeFilters);
                },
                // --- OPTIONAL THEME CUSTOMIZATION EXAMPLE ---
                // Uncomment the theme below to see a custom style.
                /*
                theme: CascadeChipTheme(
                  primaryPathBackgroundColor: Colors.teal.shade800,
                  primaryPathForegroundColor: Colors.white,
                  secondaryPathBackgroundColor: Colors.teal.shade100,
                  secondaryPathForegroundColor: Colors.teal.shade900,
                  optionChipBackgroundColor: Colors.teal.shade50,
                  optionChipBorderColor: Colors.teal.shade200,
                  clearChipBackgroundColor: Colors.grey.shade200,
                  clearChipForegroundColor: Colors.grey.shade700,
                  clearChipBorderColor: Colors.grey.shade300,
                  fontSize: 14.0,
                  chipBorderRadius: BorderRadius.circular(20.0), // Pill-shape
                  chipPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
                  chipSpacing: 10.0,
                ),
                */
              ),
            ),
            const Divider(height: 1),
            Expanded(child: _buildContentArea()),
          ],
        ));
  }
}

// SAMPLE DATA (E-commerce Catalog)
List<CascadeNode<Object>> _sampleTree() => [
      const CascadeNode(
        id: 'electronics',
        label: 'Electronics',
        children: [
          CascadeNode(
            id: 'electronics_computers',
            label: 'Computers',
            children: [
              CascadeNode(id: 'electronics_computers_laptops', label: 'Laptops'),
              CascadeNode(id: 'electronics_computers_desktops', label: 'Desktops'),
            ],
          ),
          CascadeNode(
            id: 'electronics_mobiles',
            label: 'Mobile Phones',
            children: [
              CascadeNode(id: 'electronics_mobiles_smartphones', label: 'Smartphones'),
              CascadeNode(id: 'electronics_mobiles_accessories', label: 'Accessories'),
            ],
          ),
        ],
      ),
      const CascadeNode(
        id: 'apparel',
        label: 'Apparel',
        children: [
          CascadeNode(
            id: 'apparel_mens',
            label: 'Men\'s Fashion',
            children: [
              CascadeNode(id: 'apparel_mens_tops', label: 'Tops'),
              CascadeNode(id: 'apparel_mens_bottoms', label: 'Bottoms'),
            ],
          ),
          CascadeNode(
            id: 'apparel_womens',
            label: 'Women\'s Fashion',
            children: [
              CascadeNode(id: 'apparel_womens_dresses', label: 'Dresses'),
              CascadeNode(id: 'apparel_womens_shoes', label: 'Shoes'),
            ],
          ),
        ],
      ),
      const CascadeNode(id: 'books', label: 'Books'), // A category with no children
      const CascadeNode(id: 'home_garden', label: 'Home & Garden'),
    ];

List<Product> _generateSampleProducts() => [
      // Electronics
      const Product(name: 'MacBook Pro 16"', brand: 'Apple', categoryId: 'electronics_computers_laptops'),
      const Product(name: 'XPS 15 Laptop', brand: 'Dell', categoryId: 'electronics_computers_laptops'),
      const Product(name: 'iPhone 17 Pro', brand: 'Apple', categoryId: 'electronics_mobiles_smartphones'),
      const Product(name: 'Pixel 10', brand: 'Google', categoryId: 'electronics_mobiles_smartphones'),
      const Product(
          name: 'QuietComfort Ultra Headphones', brand: 'Bose', categoryId: 'electronics_mobiles_accessories'),

      // Apparel
      const Product(name: 'Classic Crewneck T-Shirt', brand: 'Gap', categoryId: 'apparel_mens_tops'),
      const Product(name: 'Tech Fleece Hoodie', brand: 'Nike', categoryId: 'apparel_mens_tops'),
      const Product(name: '501 Original Fit Jeans', brand: 'Levi\'s', categoryId: 'apparel_mens_bottoms'),
      const Product(name: 'Floral Midi Dress', brand: 'Zara', categoryId: 'apparel_womens_dresses'),

      // Books
      const Product(name: 'Atomic Habits', brand: 'James Clear', categoryId: 'books'),
      const Product(name: 'The Pragmatic Programmer', brand: 'Hunt & Thomas', categoryId: 'books'),
    ];
4
likes
160
points
29
downloads

Publisher

verified publisherserifsadi.dev

Weekly Downloads

A stylish and animated chip component for filtering and navigating through hierarchical data.

Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (license)

Dependencies

flutter

More

Packages that depend on cascade_chips