Code Monkey home page Code Monkey logo

multi_trigger_autocomplete's Introduction

Multi Trigger Autocomplete

Open Source Love License Dart CI CodeCov Version

A flutter widget to add trigger based autocomplete functionality to your app.

Show some ❤️ and star the repo to support the project

An animated image of the MultiTriggerAutocomplete

Installation

Add the following to your pubspec.yaml and replace [version] with the latest version:

dependencies:
  multi_trigger_autocomplete: ^[version]

Usage

To use this package you must first wrap your top most widget with Portal as this package uses flutter_portal to show the options view.

(Credits to: Remi Rousselet)

Portal, is the equivalent of [Overlay].

This widget will need to be inserted above the widget that needs to render under your overlays.

If you want to display your overlays on the top of everything, a good place to insert that Portal is above MaterialApp:

Portal(
  child: MaterialApp(
    ...
  )
);

(works for CupertinoApp too)

This way Portal will render above everything. But you could place it somewhere else to change the clip behavior.

Import the package:

import 'package:multi_trigger_autocomplete/multi_trigger_autocomplete.dart';

Use the widget:

MultiTriggerAutocomplete(
  optionsAlignment: OptionsAlignment.topStart,
  autocompleteTriggers: [
    // Add the triggers you want to use for autocomplete
    AutocompleteTrigger(
      trigger: '@',
      optionsViewBuilder: (context, autocompleteQuery, controller) {
        return MentionAutocompleteOptions(
          query: autocompleteQuery.query,
          onMentionUserTap: (user) {
            final autocomplete = MultiTriggerAutocomplete.of(context);
            return autocomplete.acceptAutocompleteOption(user.id);
          },
        );
      },
    ),
    AutocompleteTrigger(
      trigger: '#',
      optionsViewBuilder: (context, autocompleteQuery, controller) {
        return HashtagAutocompleteOptions(
          query: autocompleteQuery.query,
          onHashtagTap: (hashtag) {
            final autocomplete = MultiTriggerAutocomplete.of(context);
            return autocomplete
                .acceptAutocompleteOption(hashtag.name);
          },
        );
      },
    ),
    AutocompleteTrigger(
      trigger: ':',
      optionsViewBuilder: (context, autocompleteQuery, controller) {
        return EmojiAutocompleteOptions(
          query: autocompleteQuery.query,
          onEmojiTap: (emoji) {
            final autocomplete = MultiTriggerAutocomplete.of(context);
            return autocomplete.acceptAutocompleteOption(
              emoji.char,
              // Passing false as we don't want the trigger [:] to
              // get prefixed to the option in case of emoji.
              keepTrigger: false,
            );
          },
        );
      },
    ),
  ],
  // Add the text field widget you want to use for autocomplete
  fieldViewBuilder: (context, controller, focusNode) {
    return Padding(
      padding: const EdgeInsets.all(8.0),
      child: ChatMessageTextField(
        focusNode: focusNode,
        controller: controller,
      ),
    );
  },
),

Demo

Mention Autocomplete Hashtag Autocomplete Emoji Autocomplete
Mention Autocomplete Hashtag Autocomplete Emoji Autocomplete

Customization

MultiTriggerAutocomplete

MultiTriggerAutocomplete(
  // Defines the autocomplete trigger that will be used to match the
  // text.
  autocompleteTriggers: autocompleteTriggers,
  
  // Defines the alignment of the options view relative to the
  // fieldView.
  //
  // By default, the options view is aligned to the bottom of the
  // fieldView.
  optionsAlignment: OptionsAlignment.topStart,
  
  // Defines the width to make the options as a multiple of the width
  // of the fieldView.
  //
  // Setting this to 1 makes the options view width matches the width
  // of the fieldView.
  //
  // Use null to remove this constraint.
  optionsWidthFactor: 1.0,
  
  // Defines the duration of the debounce period for the
  // [TextEditingController].
  //
  // This is the time between the last character typed and the matching
  // is performed.
  debounceDuration: const Duration(milliseconds: 350),
  
  // Defines the initial value to set in the internal
  // [TextEditingController].
  //
  // This value will be ignored if [TextEditingController] is provided.
  initialValue: const TextEditingValue(text: 'Hello'),
  
  // Defines the [TextEditingController] that will be used for the
  // fieldView.
  //
  // If this parameter is provided, then [focusNode] must also be
  // provided.
  textEditingController: TextEditingController(text: 'Hello'),
  
  // Defines the [FocusNode] that will be used for the fieldView.
  //
  // If this parameter is provided, then [textEditingController] must
  // also be provided.
  focusNode: FocusNode(),
  
  // Defines the fieldView that will be used to input the text.
  //
  // By default, a [TextFormField] is used.
  fieldViewBuilder: (context, controller, focusNode) {
    return TextField(
      controller: controller,
      focusNode: focusNode,
    );
  },
),

AutocompleteTrigger

AutocompleteTrigger(
  // The trigger string/character that will be used to trigger the
  // autocomplete.
  trigger: '@',
  
  // If true, the [trigger] should only be recognised at
  // the start of the input text.
  //
  // valid example: "@luke hello"
  // invalid example: "Hello @luke"
  triggerOnlyAtStart: false,
  
  // If true, the [trigger] should only be recognised after
  // a space.
  //
  // valid example: "@luke", "Hello @luke"
  // invalid example: "Hello@luke"
  triggerOnlyAfterSpace: true,
  
  // A minimum number of characters can be provided to only show
  // suggestions after the user has input enough characters.
  //
  // example:
  // "Hello @l" -> Shows zero suggestions.
  // "Hello @lu" -> Shows suggestions for @lu.
  minimumRequiredCharacters: 2,
  
  // The options view builder is used to build the options view
  // that will be shown when the [trigger] is detected.
  optionsViewBuilder: (context, autocompleteQuery, controller) {
    return MentionAutocompleteOptions(
      query: autocompleteQuery.query,
      onMentionUserTap: (user) {
        // Accept the autocomplete option.
        final autocomplete = MultiTriggerAutocomplete.of(context);
        return autocomplete.acceptAutocompleteOption(user.id);
      },
    );
  },
)

License

MIT License

multi_trigger_autocomplete's People

Contributors

dependabot[bot] avatar xsahil03x avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

multi_trigger_autocomplete's Issues

prevent default keyboard event on the desktop platform

Is your feature request related to a problem? Please describe.
I hope to be able to use the tab, up and down arrow keys, and other keys to select options. For TextField, the default key events need to be blocked.

Describe the solution you'd like
prevent default key event like tab, up and down arrows key .

[BUG] RangeError when selection.isValid is false

text.substring(0, cursorPosition).lastIndexOf(trigger);

Unhandled Exception: RangeError (end): Invalid value: Not in inclusive range 0..21: -1

When isValid is false baseOffset and other properties are -1

So

AutocompleteQuery? invokingTrigger(TextEditingValue textEditingValue) {
final text = textEditingValue.text;
final cursorPosition = textEditingValue.selection.baseOffset;

I fixed it like this:

  AutocompleteQuery? invokingTrigger(TextEditingValue textEditingValue) {
    if (!textEditingValue.selection.isValid) {
      return null;
    }

    final text = textEditingValue.text;
    final cursorPosition = textEditingValue.selection.baseOffset;

In my case it happens that selection.isValid is false when the Widget is a child of a custom SliverReorderableList and I change its position by drag and drop.

Attach multi trigger to scaffold

Is your feature request related to a problem? Please describe.
Textarea with minlines 10 and maxlines 20 has potential problem to not show autocomplete, if the textarea covers entire user screen.

Describe the solution you'd like
attach it to bottom, right above keyboard.

Describe alternatives you've considered
tried topStart and bottomEnd if else, but since i have it responsive, its much harder to know where to place it.

Additional context
its for blog post and the user needs bigger input field to see more text, which is problematic with showing autocomplete data.

on data changed event

I am using this with my custom user list model class and on tap I am returning that class because want to store selected user ids, but when I replace one user how can I replace that user id?
Can this have any particular events for replacement of mentioned user?

Appears to be broken in Flutter 3.22.0

I've created a bug over on the Flutter board related to this: flutter/flutter#148653

The TL;DR is that it appears that something in commit 8e418d18185697e56024ef3d5784afba4ac96370 seems to have broken something that is being done with rendering the popup on Linux. I haven't had luck figuring out what exactly yet though. I'm going to keep dabbling with it to see if there is a work around. For now, using the standard example, in previous releases one would get:
WorkingExample

...but now one gets:

BrokenExample

The case degenerates in a different way in my own app though.

Trigger on typing

I have set trigger: '@', Is it possible to trigger it after typing each character?

An issue with multiline keyboard

Hello,

I've a strange bug with multiline-keyboard.

TextField(
            focusNode: focusNode,
            controller: c,
            key: const Key('contentForm_contentInput_textField'),
            onChanged: controller.onContentChanged,
            keyboardType: TextInputType.multiline,
            minLines: 1,
            maxLines: 200,

When I clicked return(so new line happened), auto-suggestion doesn;t work, but for the first line only it works.

How can i resolve this issue ?

Add custom widget in text field

Is your feature request related to a problem? Please describe.
Im missing a feature to add custom widget in textfield (i.e. #dart) shows hastags, upon clicking, it adds it, i would like to have chip that holds another data inside.

Describe the solution you'd like
upon clicking on autocompleted findings -> save to text #dart:123 (chosen String by developer) but shows custom widget.

Describe alternatives you've considered
https://pub.dev/packages/extended_text_field but its chaotic and no clear way.

Additional context
i want exactly discord behavior with @ sign (they show @name but holds internally userid)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.