Skip to content

Commit

Permalink
Add autocomplete stimulus controller
Browse files Browse the repository at this point in the history
This is based on the implementation in the prototype and customises the
accessible-autocomplete with some of the available options.
  • Loading branch information
tvararu committed Sep 27, 2024
1 parent 84f4e52 commit cfb0dcf
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 0 deletions.
16 changes: 16 additions & 0 deletions app/assets/stylesheets/_autocomplete.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
.autocomplete__input {
background-color: $color_nhsuk-white;
}

.autocomplete__option {
margin-bottom: 0;
}

.autocomplete__option-hint {
color: $nhsuk-secondary-text-color;

.autocomplete__option:hover &,
.autocomplete__option:focus & {
color: $color_nhsuk-grey-5;
}
}
1 change: 1 addition & 0 deletions app/assets/stylesheets/application.scss
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ $color_app-dark-orange: darken(

// Application components
@import "action_list";
@import "autocomplete";
@import "button";
@import "button-group";
@import "card";
Expand Down
60 changes: 60 additions & 0 deletions app/javascript/controllers/autocomplete_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { Controller } from "@hotwired/stimulus";
import accessibleAutocomplete from "accessible-autocomplete";

const enhanceOption = (option) => {
return {
name: option.label,
append: option.getAttribute("data-append"),
hint: option.getAttribute("data-hint"),
};
};

const suggestion = (value, options) => {
const option = options.find(({ name }) => name === value);
if (option) {
const html = option.append ? `${value}${option.append}` : value;
return option.hint
? `${html}<br><span class="autocomplete__option-hint">${option.hint}</span>`
: html;
} else {
return "No results found";
}
};

const autocomplete = ($module) => {
if (!$module) {
return;
}

const params = $module.dataset;

const selectOptions = Array.from($module.options);
const options = selectOptions.map((option) => enhanceOption(option));

accessibleAutocomplete.enhanceSelectElement({
autoselect: params.autoselect === "true",
defaultValue: params.defaultValue || "",
displayMenu: params.displayMenu,
minLength: params.minLength ? parseInt(params.minLength) : 0,
selectElement: $module,
showAllValues: params.showAllValues === "true",
showNoOptionsFound: params.showNoOptionsFound === "true",
templates: {
suggestion: (value) => suggestion(value, options),
},
onConfirm: (value) => {
const selectedOption = [].filter.call(
selectOptions,
(option) => (option.textContent || option.innerText) === value,
)[0];
if (selectedOption) selectedOption.selected = true;
},
});
};

// Connects to data-module="autocomplete"
export default class extends Controller {
connect() {
autocomplete(this.element);
}
}
3 changes: 3 additions & 0 deletions app/javascript/controllers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

import { application } from "./application";

import AutocompleteController from "./autocomplete_controller";
application.register("autocomplete", AutocompleteController);

import AutosubmitController from "./autosubmit_controller";
application.register("autosubmit", AutosubmitController);

Expand Down

0 comments on commit cfb0dcf

Please sign in to comment.