ghost_autocomplete 1.2.2 copy "ghost_autocomplete: ^1.2.2" to clipboard
ghost_autocomplete: ^1.2.2 copied to clipboard

A comprehensive Flutter package for ghost (predictive inline) autocomplete and dropdown-style suggestions. Includes Form support, Copilot-style Tab badges, and pixel-perfect alignment.

example/lib/main.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: 'Ghost Autocomplete Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.indigo),
        useMaterial3: true,
        brightness: Brightness.light,
      ),
      home: const ExampleScreen(),
    );
  }
}

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

  @override
  State<ExampleScreen> createState() => _ExampleScreenState();
}

class _ExampleScreenState extends State<ExampleScreen> {
  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
      length: 4,
      child: Scaffold(
        appBar: AppBar(
          title: const Text('Ghost Autocomplete'),
          bottom: const TabBar(
            isScrollable: true,
            tabs: [
              Tab(text: 'Inline Ghost', icon: Icon(Icons.text_fields)),
              Tab(text: 'Custom Spell', icon: Icon(Icons.spellcheck)),
              Tab(text: 'Form Field', icon: Icon(Icons.assignment)),
              Tab(text: 'Dropdown List', icon: Icon(Icons.list)),
            ],
          ),
        ),
        body: const TabBarView(
          children: [
            InlineGhostTab(),
            CustomSpellTab(),
            FormFieldTab(),
            DropdownListTab(),
          ],
        ),
      ),
    );
  }
}

class TabLayout extends StatelessWidget {
  final String title;
  final String subtitle;
  final Widget child;

  const TabLayout({
    super.key,
    required this.title,
    required this.subtitle,
    required this.child,
  });

  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      padding: const EdgeInsets.all(24.0),
      child: Center(
        child: Container(
          constraints: const BoxConstraints(maxWidth: 600),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text(
                title,
                style: Theme.of(context).textTheme.headlineMedium?.copyWith(
                  color: Theme.of(context).colorScheme.primary,
                  fontWeight: FontWeight.bold,
                ),
              ),
              const SizedBox(height: 4),
              Text(
                subtitle,
                style: Theme.of(context).textTheme.bodyMedium?.copyWith(
                  color: Colors.grey[600],
                ),
              ),
              const Divider(height: 48),
              child,
            ],
          ),
        ),
      ),
    );
  }
}

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

  @override
  State<CustomSpellTab> createState() => _CustomSpellTabState();
}

class _CustomSpellTabState extends State<CustomSpellTab> {
  @override
  Widget build(BuildContext context) {
    return TabLayout(
      title: 'Custom Spell Check',
      subtitle: 'Suggestions from your own list or API.',
      child: Column(
        children: [
          const Text('Local List Suggestion', style: TextStyle(fontWeight: FontWeight.bold)),
          const SizedBox(height: 8),
          GhostSpellCheckTextField(
            suggestionProvider: getSuggestion,
            spellCheckSuggestions: const ['how', 'ok', 'what', 'why', 'flutter', 'ghost'],
            misspelledTextStyle: const TextStyle(
              decoration: TextDecoration.underline,
              decorationColor: Colors.red,
              decorationStyle: TextDecorationStyle.dotted,
              decorationThickness: 3,
            ),
            decoration: const InputDecoration(
              labelText: 'Custom Styled Spell Check',
              hintText: 'Type "hw" (dotted red underline)',
              border: OutlineInputBorder(),
            ),
          ),
          const SizedBox(height: 32),
          const Text('Asynchronous API Spell Check', style: TextStyle(fontWeight: FontWeight.bold)),
          const SizedBox(height: 8),
          GhostSpellCheckTextField(
            suggestionProvider: getSuggestion,
            spellCheckSuggestionsProvider: (word) async {
              // Simulate API call
              await Future.delayed(const Duration(milliseconds: 800));
              if (word.toLowerCase() == 'api') {
                return ['Application', 'Programming', 'Interface'];
              }
              return ['suggestion1', 'suggestion2'];
            },
            decoration: const InputDecoration(
              labelText: 'API Spell Check',
              hintText: 'Type "api" and tap it',
              border: OutlineInputBorder(),
              suffixIcon: Icon(Icons.api),
            ),
          ),
        ],
      ),
    );
  }
}

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

  @override
  State<DropdownListTab> createState() => _DropdownListTabState();
}

class _DropdownListTabState extends State<DropdownListTab> {
  @override
  Widget build(BuildContext context) {
    return TabLayout(
      title: 'Dropdown Selection',
      subtitle: 'Multiple choices like Google Maps search.',
      child: Column(
        children: [
          GhostAutocompleteListTextField(
            suggestionProvider: (text) {
              return suggestions
                  .where((s) => s.toLowerCase().contains(text.toLowerCase()))
                  .toList();
            },
            decoration: const InputDecoration(
              labelText: 'Search Places',
              border: OutlineInputBorder(),
              prefixIcon: Icon(Icons.search),
            ),
            onSuggestionSelected: (val) {
              debugPrint('Selected: $val');
            },
          ),
          const SizedBox(height: 32),
          const Card(
            child: Padding(
              padding: EdgeInsets.all(16.0),
              child: Text(
                'This widget shows a scrollable list of all matching suggestions using an Overlay.',
                style: TextStyle(fontStyle: FontStyle.italic),
              ),
            ),
          ),
          const SizedBox(height: 32),
          const Text('Asynchronous API Demo', style: TextStyle(fontWeight: FontWeight.bold)),
          const SizedBox(height: 8),
          GhostAutocompleteTextField(
            suggestionProvider: (text) async {
              if (text.isEmpty) return null;
              // Simulate network delay
              await Future.delayed(const Duration(milliseconds: 500));
              // Find match
              return getSuggestion(text);
            },
            decoration: const InputDecoration(
              labelText: 'API-backed Input',
              hintText: 'Simulates 500ms delay...',
              border: OutlineInputBorder(),
              suffixIcon: Icon(Icons.cloud_queue),
            ),
          ),
        ],
      ),
    );
  }
}


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

  @override
  State<FormFieldTab> createState() => _FormFieldTabState();
}

class _FormFieldTabState extends State<FormFieldTab> {
  final _formKey = GlobalKey<FormState>();

  @override
  Widget build(BuildContext context) {
    return TabLayout(
      title: 'Text Form Field',
      subtitle: 'Validation and Form integration.',
      child: Form(
        key: _formKey,
        child: Column(
          children: [
            GhostAutocompleteTextFormField(
              suggestionProvider: getSuggestion,
              decoration: const InputDecoration(
                labelText: 'Email Address',
                border: OutlineInputBorder(),
                prefixIcon: Icon(Icons.email),
              ),
              validator: (value) {
                if (value == null || value.isEmpty) {
                  return 'Please enter some text';
                }
                return null;
              },
            ),
            const SizedBox(height: 24),
            SizedBox(
              width: double.infinity,
              child: FilledButton.icon(
                onPressed: () {
                  if (_formKey.currentState!.validate()) {
                    ScaffoldMessenger.of(context).showSnackBar(
                      const SnackBar(content: Text('Form Validated!')),
                    );
                  }
                },
                icon: const Icon(Icons.check),
                label: const Text('Validate and Save'),
              ),
            ),
          ],
        ),
      ),
    );
  }
}



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

  @override
  State<InlineGhostTab> createState() => _InlineGhostTabState();
}

class _InlineGhostTabState extends State<InlineGhostTab> {
  final TextEditingController _controller = TextEditingController();

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

  void _updateText() {
    _controller.text = "Hello Flutter";
    _controller.selection = TextSelection.fromPosition(
      TextPosition(offset: _controller.text.length),
    );
  }

  @override
  Widget build(BuildContext context) {
    return TabLayout(
      title: 'Inline Ghost Text',
      subtitle: 'Predictive typing like GitHub Copilot.',
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: [
          GhostAutocompleteTextField(
            controller: _controller,
            suggestionProvider: getSuggestion,
            style: const TextStyle(fontSize: 18),
            decoration: const InputDecoration(
              labelText: 'Standard Input',
              hintText: 'Try typing "hello"...',
              border: OutlineInputBorder(),
            ),
          ),
          const SizedBox(height: 16),
          ElevatedButton(
            onPressed: _updateText,
            child: const Text('Update Text'),
          ),
        ],
      ),
    );
  }
}


final List<String> suggestions = [
  'hello world!',
  'flutter is incredible',
  'ghost text autocomplete is here',
  'type something and see',
  'alright then, let\'s go!',
  'yeah alright',
  'support@example.com',
  'admin@domain.com',
  'google maps integration',
  'location search',
  'awesome flutter packages',
  'building beautiful uis',
  'dart programming language',
  'mobile app development',
  'web development with flutter',
  'desktop apps are easy',
  'machine learning on edge',
  'firebase cloud storage',
  'state management solutions',
  'widget testing fundamentals',
  'reactive programming style',
  'user experience design',
];

String? getSuggestion(String text) {
  if (text.isEmpty) return null;
  try {
    return suggestions.firstWhere(
          (s) => s.toLowerCase().startsWith(text.toLowerCase()) &&
          s.toLowerCase() != text.toLowerCase(),
    );
  } catch (_) {
    return null;
  }
}
1
likes
140
points
284
downloads

Documentation

API reference

Publisher

verified publishershirsh.dev

Weekly Downloads

A comprehensive Flutter package for ghost (predictive inline) autocomplete and dropdown-style suggestions. Includes Form support, Copilot-style Tab badges, and pixel-perfect alignment.

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

flutter

More

Packages that depend on ghost_autocomplete