super_auto_suggestion_box 1.7.0
super_auto_suggestion_box: ^1.7.0 copied to clipboard
Super Auto Suggestion Box is a GeniusLink Flutter package providing a typeahead/combobox with local and remote sources, fuzzy matching, single or multi-select, free-text entry, progressive fallback, i [...]
super_auto_suggestion_box #
A Flutter typeahead / combobox for local and remote data with rich suggestion rows, fuzzy matching, single or multi-select, advanced search, validation, recents, inline creation, paging, shadow-hint completion, and controller-driven ERP form workflows.
SuperAutoSuggestionsBox<T> keeps domain data as raw T values. A
SuperAutoSuggestionBuilder<T> converts each value into searchable and
renderable SuperAutoSuggestionsItem<T> metadata at the presentation boundary.
Current package version: 1.6.0.
Table of contents
- Features
- Getting started
- Basic usage
- Suggestion builder
- Suggestion sources
- Matching strategies
- Search modes
- Multi-select
- Recent suggestions
- Inline create
- Shadow-hint completion
- Forms and validation
- Controller
- Rich and custom rows
- Field states and embedding
- Input configuration
- Theming
- Documentation
- Changelog
- Issues
Features #
- Local, asynchronous, hybrid, remote-fallback, and paged suggestion sources.
contains,prefix,words, and fuzzy matching strategies.- Relevance-ranked fuzzy results and matched-text highlighting.
- Single-select and multi-select workflows using raw domain values.
- Rich rows with title, description, trailing metadata, icons, groups, keywords, enabled state, and custom widgets.
BuildContext-awareSuperAutoSuggestionBuilder<T>for theme, localization, MediaQuery, and inherited design-system values.- Inline text-box search, Advanced Search, or both search surfaces.
- Recent suggestions with caller-controlled persistence callbacks.
- Server-side zero-based paging and infinite-scroll support.
- Inline creation for missing values with synchronous or asynchronous creation.
- Shadow-hint completion with keyboard-first Tab acceptance.
- Form integration, required validation, custom validators, and configurable validation placement.
- Read-only, disabled, fixed, bare/embed, and record-binding-friendly states.
- Keyboard, focus, formatter, directionality, and text-input configuration for ERP identifiers and general text entry.
- English and Arabic package localization, LTR/RTL support, and shared
GeniusLink theming through
super_core.
Getting started #
Install #
Add the package to pubspec.yaml:
dependencies:
super_auto_suggestion_box: ^1.7.0
Then resolve dependencies using your normal Flutter workflow.
Import #
import 'package:super_auto_suggestion_box/super_auto_suggestion_box.dart';
The package barrel exports the suggestion box feature, localization,
super_form_field integration types used by the widget, and the shared
super_core foundation used by the component.
Localization #
Register the package localization delegate when the package-owned strings should follow the application's locale:
MaterialApp(
localizationsDelegates: const [
SuperAutoSuggestionLocalization.delegate,
],
supportedLocales: SuperAutoSuggestionLocalization.supportedLocales,
);
The package also has a safe English fallback when its delegate is not installed.
Basic usage #
A source and a suggestion builder are required. The source owns raw data; the builder owns searchable and visual metadata.
final units = <String>['Each', 'Box', 'Carton'];
SuperAutoSuggestionsItem<String> unitSuggestion(
BuildContext context,
List<String> items,
int index,
String unit,
) {
return SuperAutoSuggestionsItem<String>(
value: unit,
titleText: unit,
);
}
SuperAutoSuggestionsBox<String>(
source: SuperAutoSuggestionSources.list<String>(units),
suggestionBuilder: unitSuggestion,
hintText: 'Type or pick...',
onSelectionChanged: (selected) {
final value = selected.isEmpty ? null : selected.last;
debugPrint('Selected: $value');
},
);
A controller is optional. Use one when the host needs imperative selection, focus, form, recents, query, or paging state.
Suggestion builder #
Since 1.6.0, the canonical builder is:
typedef SuperAutoSuggestionBuilder<T> =
SuperAutoSuggestionsItem<T> Function(
BuildContext context,
List<T> items,
int index,
T element,
);
The active BuildContext can safely read inherited presentation values:
SuperAutoSuggestionsItem<Account> accountSuggestion(
BuildContext context,
List<Account> items,
int index,
Account account,
) {
final colors = Theme.of(context).colorScheme;
return SuperAutoSuggestionsItem<Account>(
value: account,
titleText: account.name,
descriptionText: account.code,
trailingText: account.balanceText,
icon: Icon(Icons.account_balance_outlined, color: colors.primary),
keywords: [account.code],
);
}
titleText is the canonical searchable, displayed, and committed title.
keywords extend the searchable haystack without changing the visible title.
Suggestion sources #
Context-aware fetch callbacks #
Starting with 1.7.0, remote fetch callbacks receive the active
BuildContext before the query arguments. This lets the request read inherited
values such as locale or application-scoped configuration at the moment the
request starts.
final source = SuperAutoSuggestionSources.async<Account>(
(context, query) async {
final locale = Localizations.localeOf(context);
return repository.searchAccounts(query, locale: locale);
},
);
Hybrid and remote-fallback sources use fetch: (context, query). Paged sources
use (context, query, page). Local list, strings, and fuzzy sources remain
synchronous.
Use SuperAutoSuggestionSources for normal source construction.
| Factory | Use case | Concrete source |
|---|---|---|
list |
In-memory data | SuperAutoListSuggestionsSource<T> |
strings |
In-memory String values |
SuperAutoListSuggestionsSource<String> |
fuzzy |
Ranked fuzzy in-memory search | SuperAutoListSuggestionsSource<T> |
async |
Remote or repository search | SuperAutoAsyncSuggestionsSource<T> |
hybrid |
Local results plus remote expansion | SuperAutoHybridSuggestionsSource<T> |
remoteFallback |
Local-first search with sparse-result fallback | SuperAutoRemoteFallbackSuggestionsSource<T> |
paged |
Server-side paging / infinite scroll | SuperAutoPagedSuggestionsSource<T> |
Local list #
final source = SuperAutoSuggestionSources.list<Account>(
accounts,
match: AutoSuggestionMatch.contains,
caseSensitive: false,
);
For plain strings:
final source = SuperAutoSuggestionSources.strings(
['Aden', 'Amman', 'Cairo', 'Dubai'],
match: AutoSuggestionMatch.prefix,
);
The widget still receives a suggestionBuilder, including when strings() is
used.
Fuzzy #
final source = SuperAutoSuggestionSources.fuzzy<Account>(accounts);
Fuzzy results are ranked by match quality rather than preserving only insertion order.
Async #
final source = SuperAutoSuggestionSources.async<Account>(
(context, query) => repository.searchAccounts(query),
initialItems: initiallyKnownAccounts,
);
SuperAutoSuggestionsBox<Account>(
source: source,
suggestionBuilder: accountSuggestion,
debounce: const Duration(milliseconds: 300),
);
initialItems seed value resolution; they are not automatically returned as the
result of every async query.
Hybrid #
Hybrid search always lets local matches contribute to the final result and fetches remotely when the local result count is below the configured threshold.
final source = SuperAutoSuggestionSources.hybrid<Account>(
initialItems: recentAccounts,
fetch: repository.searchAccounts,
remoteThreshold: 3,
remoteMinChars: 2,
);
The remote condition is localMatches.length < remoteThreshold.
When the source is used by SuperAutoSuggestionsBox, prefer the widget's minResult to control the progressive remote-fetch threshold. remoteThreshold remains relevant to direct source query/progressive calls.
Remote fallback #
Use remoteFallback when remote data should primarily extend sparse local
results:
final source = SuperAutoSuggestionSources.remoteFallback<Account>(
initialItems: recentAccounts,
fetch: repository.searchAccounts,
remoteThreshold: 5,
remoteMinChars: 2,
);
The remote condition is inclusive:
localMatches.length <= remoteThreshold.
Inside SuperAutoSuggestionsBox, minResult is the widget-level inclusive threshold for progressive remote fetching. The source-level remoteThreshold is retained for direct source calls.
Paged #
The page callback uses zero-based page indexes. Page 0 is the first page.
final source = SuperAutoSuggestionSources.paged<Account>(
(context, query, page) async {
final response = await repository.searchAccountsPage(
query: query,
page: page,
);
return SuperSuggestionsPage<Account>(
items: response.items,
hasMore: response.hasMore,
);
},
resolveFrom: initiallySelectedAccounts,
);
Fetched pages are retained for value resolution. The paged source does not de-duplicate rows across pages, so APIs that can repeat rows should be normalized in the repository or fetch callback.
Matching strategies #
AutoSuggestionMatch supports:
| Strategy | Behavior |
|---|---|
contains |
Query appears anywhere in the searchable text. |
prefix |
Searchable text starts with the query. |
words |
Every whitespace-separated query token must appear. |
fuzzy |
Query characters appear in order with gaps allowed. |
Example:
final source = SuperAutoSuggestionSources.list<Account>(
accounts,
match: AutoSuggestionMatch.words,
);
Use the box's highlightMatch and highlightMatches options to control row
highlighting behavior.
Search modes #
SuperAutoSuggestionsMode controls which search surface is exposed:
textBox: editable field with anchored suggestions.advanceView: field-like launcher for the Advanced Search view.both: editable field plus Advanced Search access.
SuperAutoSuggestionsBox<Account>(
source: source,
suggestionBuilder: accountSuggestion,
mode: SuperAutoSuggestionsMode.both,
);
When mode is omitted, desktop platforms default to textBox; Android, iOS,
and Fuchsia default to advanceView.
A custom Advanced Search surface can be supplied with advancedSearchBuilder.
Multi-select #
Initial selected values belong to the controller. Multi-select behavior belongs to the widget.
final controller = SuperAutoSuggestionsController<Account>(
initialSelected: initialAccounts,
);
SuperAutoSuggestionsBox<Account>(
controller: controller,
source: source,
suggestionBuilder: accountSuggestion,
multiSelect: true,
onSelectionChanged: (selected) {
debugPrint('Selected ${selected.length} accounts');
},
);
Read the current values from controller.selectedItems.
Recent suggestions #
SuperAutoSuggestionsBox<Account>(
source: source,
suggestionBuilder: accountSuggestion,
showRecents: true,
maxRecents: 8,
initialRecents: persistedRecents,
onRecentsChanged: persistRecents,
);
Recents are most-recent-first. The package owns runtime ordering while the host
can persist changes through onRecentsChanged.
Inline create #
When onCreate is set and a non-empty query has no match, the component can
show a create action in both inline and Advanced Search surfaces.
SuperAutoSuggestionsBox<Account>(
source: source,
suggestionBuilder: accountSuggestion,
onCreate: (query) async {
return repository.createAccount(name: query);
},
createLabelBuilder: (query) => 'Create "$query"',
);
Return the created raw T to commit it, or null to cancel creation.
Shadow-hint completion #
Shadow hints render the untyped suffix of the highlighted prefix match without changing the actual editable value.
SuperAutoSuggestionsBox<String>(
source: source,
suggestionBuilder: referenceSuggestion,
showShadowHint: true,
completeShadowHintOnTab: true,
);
Forward Tab accepts a visible shadow hint. Shift+Tab keeps reverse focus
traversal. If no shadow hint is visible, Tab keeps normal focus traversal or
uses onTabNext when supplied.
Forms and validation #
SuperAutoSuggestionsBox<T> participates in Flutter forms with the committed
raw T? value.
final formKey = GlobalKey<FormState>();
final fieldKey = GlobalKey<FormFieldState<Account>>();
final controller = SuperAutoSuggestionsController<Account>(
formFieldKey: fieldKey,
);
Form(
key: formKey,
child: SuperAutoSuggestionsBox<Account>(
controller: controller,
source: source,
suggestionBuilder: accountSuggestion,
required: true,
validator: (account) {
if (account != null && account.isBlocked) {
return 'Blocked accounts cannot be selected';
}
return null;
},
autovalidateMode: AutovalidateMode.onUserInteraction,
validationPosition: ValidationPosition.underBox,
),
);
Validation is selection-driven. Use FormState.validate() for form-level
validation and controller state for the selected value.
If autovalidateMode is omitted, the field inherits the nearest Form setting
and otherwise defaults to AutovalidateMode.disabled.
Debounce and minResult #
Local matching is never debounced. On every query change, data that is already available in memory is matched immediately and can be rendered without waiting for the debounce window.
SuperAutoSuggestionsBox.debounce applies only to work that reaches an
external source: remote fetch callbacks, progressive loadMore work, and the
first request of a paged source. Version 1.7.0 uses easy_debounce, so rapid
keystrokes reset only the pending remote request.
SuperAutoSuggestionsBox<Account>(
source: SuperAutoSuggestionSources.async<Account>(
(context, query) => repository.searchAccounts(query),
initialItems: cachedAccounts,
),
debounce: const Duration(milliseconds: 300),
minResult: 0,
suggestionBuilder: accountSuggestion,
);
In this example, cachedAccounts are matched immediately. If the local match
count allows remote loading, the repository request starts after 300ms.
Changing the debounce duration never delays local filtering.
The built-in sources behave as follows:
list/strings/fuzzy: local-only matching;debounceis ignored.async:initialItemsand previously cached results are matched immediately; remotefetchis debounced when more data is needed.hybrid/remoteFallback: local matching is immediate; only the remote augmentation step is debounced.paged: page requests are external work and remain debounced;resolveFromcontinues to be a resolution cache rather than a local search collection.
SuperAutoSuggestionSources.async accepts match and caseSensitive for its
local cache matching:
final source = SuperAutoSuggestionSources.async<Account>(
(context, query) => repository.searchAccounts(query),
initialItems: cachedAccounts,
match: AutoSuggestionMatch.contains,
caseSensitive: false,
);
Use Duration.zero when remote requests should start immediately. Values such
as 300ms or 800ms reduce external request churn without making local search
feel slower.
minResult #
minResult is evaluated against the immediate local result count. Remote
work is eligible when the local count is less than or equal to minResult.
The default is 0, so a remote request is needed only when local matching
returns no rows.
SuperAutoSuggestionsBox<Account>(
source: SuperAutoSuggestionSources.hybrid<Account>(
initialItems: recentAccounts,
fetch: (context, query) => repository.searchAccounts(query),
remoteMinChars: 2,
),
minResult: 3,
debounce: const Duration(milliseconds: 300),
suggestionBuilder: accountSuggestion,
);
With minResult: 3, 0, 1, 2, or 3 local rows are shown immediately and the
remote fetch is then scheduled through debounce. With 4 or more local matches,
no remote request is started. Source-specific minimum query-length rules still
apply.
A pure async source with an empty local cache naturally has 0 local results,
so its remote fetch proceeds after debounce. As remote results are cached, later
queries can match those cached values immediately before deciding whether
another external request is necessary.
Controller #
Create a SuperAutoSuggestionsController<T> when the host needs direct state
or commands:
final controller = SuperAutoSuggestionsController<Account>(
initialValue: initialAccount,
allowFreeText: false,
focusNode: accountFocusNode,
);
Common reads:
controller.query;
controller.results;
controller.suggestions;
controller.selected;
controller.selectedItems;
controller.recents;
controller.isOpen;
controller.isLoading;
controller.isLoadingMore;
controller.isPaged;
controller.hasMore;
controller.error;
Common commands:
controller.open();
controller.close();
controller.toggle();
controller.setText('1001');
controller.refresh();
controller.selectByValue(account);
controller.setSelectedItems(accounts);
controller.clearSelection();
controller.setRecents(accounts);
controller.clearRecents();
controller.loadNextPage();
controller.clear();
The widget owns the source, builder, query timing, recents configuration, result limit, and multi-select configuration; the controller is the runtime state/command surface.
Rich and custom rows #
Use SuperAutoSuggestionsItem<T> for default rich rows:
SuperAutoSuggestionsItem<Account>(
value: account,
titleText: account.name,
descriptionText: account.code,
trailingText: account.balanceText,
group: account.typeLabel,
iconData: Icons.account_balance_outlined,
keywords: [account.code, account.alias],
enabled: account.isActive,
);
Custom supporting widgets can be supplied directly:
SuperAutoSuggestionsItem<Account>(
value: account,
titleText: account.name,
description: Text(account.code),
trailing: Chip(label: Text(account.statusLabel)),
icon: const Icon(Icons.account_balance_outlined),
);
For complete row control, use itemBuilder:
SuperAutoSuggestionsBox<Account>(
source: source,
suggestionBuilder: accountSuggestion,
itemBuilder: (context, account, suggestion, highlighted) {
return ListTile(
selected: highlighted,
title: Text(suggestion.displayText),
subtitle: Text(account.code),
);
},
);
Other presentation hooks include emptyBuilder and loadingBuilder.
Field states and embedding #
The box supports several distinct states:
enabled: false: disables the standard field interaction.disabled: true: dims the field and suppresses interaction and validation.readOnly: true: keeps normal contrast while blocking editing and opening.allowFixed: true: exposes a lock/unlock action backed bycontroller.isFixed.bare: true: removes the outer border/fill and tightens padding for embedded surfaces such as editable table cells.
Keyboard-oriented embedders can use onEscape, onTabNext, and onTabPrev.
Use restoreOnBlur to control whether uncommitted typing reverts to the last
committed selection.
Input configuration #
The widget exposes Flutter text-input controls needed for ERP and structured identifiers, including:
keyboardType,textInputAction, andtextCapitalization.inputFormatters,maxLength, andmaxLengthEnforcement.textDirection,textAlign, andtextAlignVertical.autocorrect,enableSuggestions, andenableIMEPersonalizedLearning.autofillHints, smart dashes/quotes, cursor options, and selection controls.focusNode,autofocus,canRequestFocus, andscrollOnFocus.
Example for an exact numeric account code:
SuperAutoSuggestionsBox<Account>(
source: source,
suggestionBuilder: accountSuggestion,
keyboardType: TextInputType.number,
enableSuggestions: false,
autocorrect: false,
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
textDirection: TextDirection.ltr,
);
Theming #
Use SuperAutoSuggestionsBoxThemeData for component styling and
SuperAutoSuggestionsBoxFocusedStyle for focused-state overrides.
A field-level theme can override the ambient package theme:
SuperAutoSuggestionsBox<Account>(
source: source,
suggestionBuilder: accountSuggestion,
theme: SuperAutoSuggestionsBoxThemeData.light.copyWith(
borderFocus: Colors.indigo,
),
);
The package integrates with the shared GeniusLink design-system foundation from
super_core, including light/dark themes, spacing, typography, and RTL-aware
presentation.
Documentation #
The example/ application contains runnable scenarios for local and remote
search, Advanced Search modes, validation placement, autovalidation, rich rows,
and newer package behavior.
Changelog #
See CHANGELOG.md for new features, fixes, and breaking changes.
Issues #
Use the GitHub issue tracker for bug reports and feature requests.