KompKit Core — Flutter / Dart

Cross-platform utility functions for Flutter and Dart applications. Part of the KompKit ecosystem with identical APIs across Web (TypeScript), Android (Kotlin), and Flutter (Dart).

⚠️ Alpha: APIs may change before 1.0.0. Pin to an exact version in production.

Installation

Add to your pubspec.yaml:

dependencies:
  kompkit_core: ^0.4.1-alpha.0

Then run:

flutter pub get

Published on pub.dev/packages/kompkit_core

Quick Start

import 'package:kompkit_core/kompkit_core.dart';

// Debounce — delay until calls stop
final onSearch = debounce<String>(
  (query) => print('Searching: $query'),
  const Duration(milliseconds: 300),
);

// Email validation
print(isEmail('user@example.com')); // true
print(isEmail('invalid@'));         // false

// Currency formatting (en-US / USD default)
print(formatCurrency(1234.56));                        // "$1,234.56"
print(formatCurrency(1234.56, currency: 'EUR', locale: 'es-ES')); // "1.234,56 €"

// Clamp a value to a range
print(clamp(15.0, 0.0, 10.0)); // 10.0

// Throttle — at most once per interval
final onScroll = throttle<double>(
  (offset) => print('offset: $offset'),
  const Duration(milliseconds: 200),
);

API Reference

debounce

Delays execution until calls stop for the given wait duration. The last call within the wait period executes; all earlier ones are cancelled.

Debounced<T> debounce<T>(void Function(T) action, Duration wait)
final onSearch = debounce<String>(
  (query) => fetchResults(query),
  const Duration(milliseconds: 300),
);

onSearch('k');
onSearch('ko');
onSearch('kompkit'); // only this executes, after 300ms of inactivity

onSearch.cancel();   // discard pending call — call in dispose()

Flutter StatefulWidget example:

class SearchWidget extends StatefulWidget {
  @override
  State<SearchWidget> createState() => _SearchWidgetState();
}

class _SearchWidgetState extends State<SearchWidget> {
  late final Debounced<String> _onSearch;

  @override
  void initState() {
    super.initState();
    _onSearch = debounce<String>(
      (query) => setState(() { /* update results */ }),
      const Duration(milliseconds: 300),
    );
  }

  @override
  void dispose() {
    _onSearch.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return TextField(onChanged: _onSearch.call);
  }
}

throttle

Limits execution to at most once per wait duration. The first call executes immediately; subsequent calls within the cooldown are ignored.

Throttled<T> throttle<T>(void Function(T) action, Duration wait)
final onScroll = throttle<double>(
  (offset) => print('scroll: $offset'),
  const Duration(milliseconds: 200),
);

onScroll(0.0);   // executes immediately
onScroll(50.0);  // ignored — within 200ms cooldown
onScroll.cancel(); // reset state — call in dispose()

Flutter StatefulWidget with ScrollController:

class ScrollTracker extends StatefulWidget {
  @override
  State<ScrollTracker> createState() => _ScrollTrackerState();
}

class _ScrollTrackerState extends State<ScrollTracker> {
  final _controller = ScrollController();
  late final Throttled<double> _onScroll;
  double _offset = 0;

  @override
  void initState() {
    super.initState();
    _onScroll = throttle<double>(
      (offset) => setState(() => _offset = offset),
      const Duration(milliseconds: 200),
    );
    _controller.addListener(() => _onScroll(_controller.offset));
  }

  @override
  void dispose() {
    _onScroll.cancel();
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Text('Offset: ${_offset.toStringAsFixed(1)}'),
        Expanded(
          child: ListView.builder(
            controller: _controller,
            itemCount: 100,
            itemBuilder: (_, i) => ListTile(title: Text('Item $i')),
          ),
        ),
      ],
    );
  }
}

isEmail

Validates an email address.

bool isEmail(String value)
isEmail('user@example.com')   // true
isEmail('invalid@')           // false
isEmail('  user@domain.org ') // true (trimmed)

formatCurrency

Formats a number as a localized currency string.

String formatCurrency(double amount, {String currency = 'USD', String locale = 'en-US'})
formatCurrency(1234.56)                              // "$1,234.56"
formatCurrency(1234.56, currency: 'EUR', locale: 'es-ES') // "1.234,56 €"
formatCurrency(1234.56, currency: 'JPY', locale: 'ja-JP') // "¥1,235"
  • Accepts BCP 47 locale strings; normalizes en-USen_US for the intl package internally
  • Throws on invalid currency codes

clamp

Constrains a value within an inclusive [min, max] range.

double clamp(double value, double min, double max)
clamp(5.0, 0.0, 10.0)   // 5.0
clamp(-3.0, 0.0, 10.0)  // 0.0
clamp(15.0, 0.0, 10.0)  // 10.0
final opacity = clamp(userInput, 0.0, 1.0);
final volume  = clamp(rawVolume, 0.0, 100.0);

Lifecycle and cancellation

Both debounce and throttle return objects with a cancel() method. Always call cancel() in dispose() to prevent callbacks from firing after a widget is removed:

@override
void dispose() {
  _debouncedSearch.cancel();
  _throttledScroll.cancel();
  super.dispose();
}

Platform support

Platform Supported
Flutter iOS
Flutter Android
Flutter Web
Flutter Desktop (Windows, macOS, Linux)
Dart VM (server-side)
Dart Web (compiled to JS)

Compatibility: Flutter 3.0+ · Dart SDK ≥ 3.0.0


Documentation

  • Flutter Guide — Detailed usage with complete widget examples
  • Main README — Project overview and cross-platform APIs
  • Architecture — API parity contract and platform differences
  • Recipes — Real-world usage patterns across all platforms
  • API Reference — DartDoc generated documentation (generated locally via dart doc)

Testing

flutter test        # Flutter projects
dart test           # Dart-only projects
flutter test --coverage  # with coverage report

Libraries

kompkit_core
KompKit Core - Cross-platform utilities for Flutter and Dart