@financial-times/o-autocomplete 1.9.1 → 1.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.10.0](https://github.com/Financial-Times/origami/compare/o-autocomplete-v1.9.2...o-autocomplete-v1.10.0) (2024-04-19)
4
+
5
+
6
+ ### Features
7
+
8
+ * Enable highlighting of custom suggestions ([#1516](https://github.com/Financial-Times/origami/issues/1516)) ([c326099](https://github.com/Financial-Times/origami/commit/c3260998c4a8926f875e7ba95134b230ca517669))
9
+
10
+ ## [1.9.2](https://github.com/Financial-Times/origami/compare/o-autocomplete-v1.9.1...o-autocomplete-v1.9.2) (2024-04-12)
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * Update financial-times/accessible-autocomplete ([#1524](https://github.com/Financial-Times/origami/issues/1524)) ([8bcd024](https://github.com/Financial-Times/origami/commit/8bcd02402f3fa50e35756d3eb2a22b10435d634b))
16
+
3
17
  ## [1.9.1](https://github.com/Financial-Times/origami/compare/o-autocomplete-v1.9.0...o-autocomplete-v1.9.1) (2023-10-27)
4
18
 
5
19
 
package/README.md CHANGED
@@ -98,7 +98,7 @@ Or pass an element to initialise a specific `o-autocomplete` instance:
98
98
 
99
99
  ```js
100
100
  import oAutocomplete from 'o-autocomplete';
101
- const oAutocompleteElement = document.getElementById('#my-o-autocomplete-element');
101
+ const oAutocompleteElement = document.getElementById('my-o-autocomplete-element');
102
102
  new oAutocomplete(oAutocompleteElement);
103
103
  ```
104
104
  ### dynamic suggestions function
@@ -123,7 +123,7 @@ async function customSuggestions(query, populateOptions) {
123
123
  populateOptions(suggestions);
124
124
  }
125
125
 
126
- const oAutocompleteElement = document.getElementById('#my-o-autocomplete-element');
126
+ const oAutocompleteElement = document.getElementById('my-o-autocomplete-element');
127
127
  new oAutocomplete(oAutocompleteElement, {
128
128
  source: customSuggestions
129
129
  });
@@ -176,7 +176,7 @@ function mapOptionToSuggestedValue(option) {
176
176
  return option.suggestionText;
177
177
  }
178
178
 
179
- const oAutocompleteElement = document.getElementById('#my-o-autocomplete-element');
179
+ const oAutocompleteElement = document.getElementById('my-o-autocomplete-element');
180
180
  new oAutocomplete(oAutocompleteElement, {
181
181
  mapOptionToSuggestedValue,
182
182
  source: customSuggestions,
@@ -221,7 +221,7 @@ function onConfirm(option) {
221
221
  console.log('You selected option: ', option);
222
222
  }
223
223
 
224
- const oAutocompleteElement = document.getElementById('#my-o-autocomplete-element');
224
+ const oAutocompleteElement = document.getElementById('my-o-autocomplete-element');
225
225
  new oAutocomplete(oAutocompleteElement, {
226
226
  onConfirm
227
227
  mapOptionToSuggestedValue,
@@ -236,10 +236,14 @@ This function is used to override the default rendering of suggestion items, wit
236
236
 
237
237
  It is typically used when wanting to provide additional context or styling for each suggestion item.
238
238
 
239
+ The `query` value (text which was typed into the autocomplete text input field by the user) is provided so that it can be used as a basis for highlighting the `option` value (or one of its values if it is an object).
240
+
239
241
  :warning: **Caution:** because this function allows you to output arbitrary HTML, you should [make sure it's trusted](https://en.wikipedia.org/wiki/Cross-site_scripting), and accessible. The HTML will be output within listbox options, so [ensure all descendants are presentational](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/option_role#all_descendants_are_presentational).
240
242
 
241
243
  #### Example
242
244
 
245
+ Providing additional context by displaying multiple `option` properties:
246
+
243
247
  ```js
244
248
  import oAutocomplete from 'o-autocomplete';
245
249
 
@@ -250,6 +254,7 @@ async function customSuggestions(query, populateOptions) {
250
254
 
251
255
  /**
252
256
  * @param {{"name": string, "role": string}} option - The option to transform into a suggestion
257
+ * @param {string} [query] - Text which was typed into the autocomplete text input field by the user
253
258
  * @returns {string} The HTML to render in the suggestion list*/
254
259
  function suggestionTemplate(option) {
255
260
  return `
@@ -260,7 +265,61 @@ function suggestionTemplate(option) {
260
265
  `;
261
266
  }
262
267
 
263
- const oAutocompleteElement = document.getElementById('#my-o-autocomplete-element');
268
+ const oAutocompleteElement = document.getElementById('my-o-autocomplete-element');
269
+ new oAutocomplete(oAutocompleteElement, {
270
+ suggestionTemplate,
271
+ source: customSuggestions,
272
+ });
273
+ ```
274
+
275
+ Using the `query` value to apply highlighting to one of the `option` properties:
276
+
277
+ ```js
278
+ import oAutocomplete from 'o-autocomplete';
279
+
280
+ async function customSuggestions(query, populateOptions) {
281
+ const suggestions = await getSuggestions(query);
282
+ populateOptions(suggestions);
283
+ }
284
+
285
+ function highlightSuggestion(suggestion, query) {
286
+ const result = suggestion.split('');
287
+
288
+ const matchIndex = suggestion.toLocaleLowerCase().indexOf(query.toLocaleLowerCase());
289
+ return result.map(function(character, index) {
290
+ let shouldHighlight = true;
291
+ const hasMatched = matchIndex > -1;
292
+ const characterIsWithinMatch = index >= matchIndex && index <= matchIndex + query.length - 1;
293
+ if (hasMatched && characterIsWithinMatch) {
294
+ shouldHighlight = false;
295
+ }
296
+ return [character, shouldHighlight];
297
+ });
298
+ }
299
+
300
+ /**
301
+ * @param {{"name": string, "role": string}} option - The option to transform into a suggestion
302
+ * @param {string} [query] - Text which was typed into the autocomplete text input field by the user
303
+ * @returns {string} The HTML to render in the suggestion list*/
304
+ function suggestionTemplate(option, query) {
305
+ const characters = highlightSuggestion(option.name, query || option.name);
306
+
307
+ let output = '';
308
+ for (const [character, shoudHighlight] of characters) {
309
+ if (shoudHighlight) {
310
+ output += `<span class="o-autocomplete__option--highlight">${character}</span>`;
311
+ } else {
312
+ output += `${character}`;
313
+ }
314
+ }
315
+ output += ` (${option.role})`;
316
+ const span = document.createElement('span');
317
+ span.setAttribute('aria-label', option.name);
318
+ span.innerHTML = output;
319
+ return span.outerHTML;
320
+ }
321
+
322
+ const oAutocompleteElement = document.getElementById('my-o-autocomplete-element');
264
323
  new oAutocomplete(oAutocompleteElement, {
265
324
  suggestionTemplate,
266
325
  source: customSuggestions,
@@ -274,7 +333,8 @@ new oAutocomplete(oAutocompleteElement, {
274
333
 
275
334
  | Param | Type | Description |
276
335
  | --- | --- | --- |
277
- | option | <code>\*</code> | The option to transform into a suggestio |
336
+ | option | <code>\*</code> | The option to transform into a suggestion |
337
+ | query | <code>string</code> | Text which was typed into the autocomplete text input field by the user |
278
338
 
279
339
  ### onConfirm
280
340
 
@@ -305,7 +365,7 @@ function onConfirm(option) {
305
365
  console.log('You selected option: ', option);
306
366
  }
307
367
 
308
- const oAutocompleteElement = document.getElementById('#my-o-autocomplete-element');
368
+ const oAutocompleteElement = document.getElementById('my-o-autocomplete-element');
309
369
  new oAutocomplete(oAutocompleteElement, {
310
370
  onConfirm
311
371
  mapOptionToSuggestedValue,