statecraft 0.1.2 copy "statecraft: ^0.1.2" to clipboard
statecraft: ^0.1.2 copied to clipboard

Elegant state handling for Flutter and flutter_bloc. Build smooth async, form, list, and paginated states with ease.

statecraft #

🎯 Elegant, lightweight state handling for Flutter and flutter_bloc.


statecraft provides simple yet powerful state models (AsyncState<T>, FormState<T>) that you can use in your Flutter apps, especially with flutter_bloc, Cubit, or any state management solution.

It removes boilerplate and helps you manage async operations (loading, success, failure) and form states cleanly.


πŸš€ Features #

  • Typed AsyncState<T> and FormState<T> sealed classes
  • Built-in when, maybeWhen, and whenOrNull APIs
  • Designed for Dart 3 (sealed, final classes)
  • Extremely lightweight (no code generation, no dependencies)
  • Perfect companion for flutter_bloc and Cubit
  • Fully extensible β€” Pagination state coming soon!

πŸ“¦ Installation #

dart pub add statecraft

or manually in your pubspec.yaml:

dependencies:
  statecraft: ^0.1.0

✨ Philosophy #

Handling asynchronous states in Flutter is a repetitive task.Typically you create:

  • Loading State
  • Success State
  • Error State

for every BLoC manually. This leads to boilerplate and messy switch-cases.

statecraft solves this by providing unified AsyncState you can reuse everywhere.


🧩 Usage with flutter_bloc #

Here’s a complete real-world example using AsyncState<T>:

1. Define your Cubit #

import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:statecraft/statecraft.dart';

class ExampleCubit extends Cubit<AsyncState<String>> {
  final ExampleRepository repository;

  ExampleCubit(this.repository) : super(const AsyncInitial());

  Future<void> fetchData() async {
    emit(const AsyncLoading());
    try {
      final result = await repository.loadExampleData();
      emit(AsyncSuccess(result));
    } catch (e) {
      emit(AsyncFailure(e.toString()));
    }
  }
}

2. Use it in your Flutter Widget #

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:statecraft/statecraft.dart';

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

  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      create: (_) => ExampleCubit(ExampleRepository()),
      child: Scaffold(
        appBar: AppBar(title: const Text('Async Example')),
        body: BlocBuilder<ExampleCubit, AsyncState<String>>(
          builder: (context, state) {
            return state.when(
              initial: () => const Center(child: Text('Press the button to load data')),
              loading: () => const Center(child: CircularProgressIndicator()),
              success: (data) => Center(child: Text('Result: $data')),
              failure: (error) => Center(child: Text('Failed: $error')),
            );
          },
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () => context.read<ExampleCubit>().fetchData(),
          child: const Icon(Icons.download),
        ),
      ),
    );
  }
}

✨ AsyncState Lifecycle #

State Meaning
AsyncInitial The initial idle state before anything starts
AsyncLoading Represents an ongoing async operation
AsyncSuccess<T> Represents a successful operation with [T] data
AsyncFailure Represents a failure with an error message

✨ FormState Lifecycle #

Use FormState<T> to handle user form submission flows β€” from untouched to submission, success, or error.

State Meaning
FormInitial Form has not been submitted yet
FormSubmitting Submission in progress
FormSuccess<T> Submitted successfully, with result data
FormFailure Submission failed with error message

πŸ”„ Example: Form Cubit #

class ProfileFormCubit extends Cubit<FormState<Profile>> {
  ProfileFormCubit() : super(const FormInitial());

  Future<void> submit(String name) async {
    emit(const FormSubmitting());
    try {
      await Future.delayed(const Duration(seconds: 2));
      emit(FormSuccess(Profile(name: name)));
    } catch (_) {
      emit(FormFailure('Submission failed.'));
    }
  }
}

🧱 In your Widget #

BlocBuilder<ProfileFormCubit, FormState<Profile>>(
  builder: (context, state) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        state.when(
          initial: () => const Text('Please submit the form'),
          submitting: () => const CircularProgressIndicator(),
          success: (profile) => Text('Welcome ${profile.name}'),
          failure: (error) => Text('Error: $error'),
        ),
        const SizedBox(height: 16),
        ElevatedButton(
          onPressed: () => context.read<ProfileFormCubit>().submit('Samfan'),
          child: const Text('Submit'),
        ),
      ],
    );
  },
);

πŸ“œ API Overview #

All states expose:

  • when β€” handle every case explicitly
  • maybeWhen β€” handle some cases, fallback with orElse
  • whenOrNull β€” handle only what you need, ignore others

Example: #

state.maybeWhen(
  success: (data) => Text('Loaded: $data'),
  orElse: () => const CircularProgressIndicator(),
);

🚧 Roadmap #

  • βœ… AsyncState<T> – async loading/success/failure
  • βœ… FormState<T> – form submission lifecycle βœ…
  • ❌ PaginationState<T> – for infinite scroll & pagination

πŸ“ƒ License #

MIT License β€” free to use for personal or commercial projects.


🌟 Why use statecraft? #

  • Stop writing Loading/Loaded/Error states manually.
  • Smaller, readable, and reusable BLoC/Cubit logic.
  • Type-safe state management with zero boilerplate.
  • Grows with your app: Async, Form, Pagination states.

Made with ❀️ for Flutter devs who love BLoC.

2
likes
160
points
258
downloads
screenshot

Publisher

verified publishersamfan.dev

Weekly Downloads

Elegant state handling for Flutter and flutter_bloc. Build smooth async, form, list, and paginated states with ease.

Repository (GitHub)
View/report issues

Topics

#state-management #flutter #bloc #cubit

Documentation

API reference

License

MIT (license)

More

Packages that depend on statecraft