@financial-times/o-autocomplete 1.6.2 → 1.7.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 +7 -0
- package/README.md +14 -8
- package/demos/src/dynamic/dynamic.mustache +5 -5
- package/demos/src/dynamic-complex/dynamic-complex.js +10 -3
- package/demos/src/dynamic-complex/dynamic-complex.mustache +4 -4
- package/demos/src/dynamic-delayed/dynamic-delayed.mustache +4 -4
- package/demos/src/static/static.mustache +3 -3
- package/package.json +3 -2
- package/src/js/autocomplete.js +22 -10
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.7.0](https://www.github.com/Financial-Times/origami/compare/o-autocomplete-v1.6.2...o-autocomplete-v1.7.0) (2022-09-14)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* autocomplete, add a `defaultValue` for a default input value ([#812](https://www.github.com/Financial-Times/origami/issues/812)) ([70a77ae](https://www.github.com/Financial-Times/origami/commit/70a77ae218c9c19967fe3bb32c18206d7cd9c2c3))
|
|
9
|
+
|
|
3
10
|
### [1.6.2](https://www.github.com/Financial-Times/origami/compare/o-autocomplete-v1.6.1...o-autocomplete-v1.6.2) (2022-04-21)
|
|
4
11
|
|
|
5
12
|
|
package/README.md
CHANGED
|
@@ -43,7 +43,7 @@ To provide a static set of suggestions, we recommend using a `select` element. o
|
|
|
43
43
|
|
|
44
44
|
### For a dynamic set of suggestions
|
|
45
45
|
|
|
46
|
-
To provide a dynamic set of suggestions,
|
|
46
|
+
To provide a dynamic set of suggestions, provide a javascript function or name of a javascript function on the window object which follows the [dynamic-suggestions-function](#dynamic-suggestions-function) <abbr title="application programming interface">API</abbr>.
|
|
47
47
|
|
|
48
48
|
The input element requires an `id` attribute, this is used within the component to implement the accessibility features.
|
|
49
49
|
```html
|
|
@@ -56,12 +56,12 @@ The input element requires an `id` attribute, this is used within the component
|
|
|
56
56
|
|
|
57
57
|
To have styling for labels, you will need to use [o-forms](https://registry.origami.ft.com/components/o-forms) as part of the autocomplete implementation.
|
|
58
58
|
|
|
59
|
-
Below is an example of how to combine o-forms and o-autocomplete components together
|
|
59
|
+
Below is an example of how to combine o-forms and o-autocomplete components together. Note the `label` and `select` element are connected using `for` and `id` attributes.
|
|
60
60
|
```html
|
|
61
|
-
<
|
|
62
|
-
<
|
|
61
|
+
<span class="o-forms-field" >
|
|
62
|
+
<label for="my-autocomplete" class="o-forms-title">
|
|
63
63
|
<span class="o-forms-title__main">Select your country</span>
|
|
64
|
-
</
|
|
64
|
+
</label>
|
|
65
65
|
<span class="o-forms-input o-forms-input--select">
|
|
66
66
|
<span data-o-component="o-autocomplete" class="o-autocomplete">
|
|
67
67
|
<select id="my-autocomplete">
|
|
@@ -70,7 +70,7 @@ Below is an example of how to combine o-forms and o-autocomplete components toge
|
|
|
70
70
|
</select>
|
|
71
71
|
</span>
|
|
72
72
|
</span>
|
|
73
|
-
</
|
|
73
|
+
</span>
|
|
74
74
|
```
|
|
75
75
|
## Sass
|
|
76
76
|
|
|
@@ -101,7 +101,6 @@ import oAutocomplete from 'o-autocomplete';
|
|
|
101
101
|
const oAutocompleteElement = document.getElementById('#my-o-autocomplete-element');
|
|
102
102
|
new oAutocomplete(oAutocompleteElement);
|
|
103
103
|
```
|
|
104
|
-
|
|
105
104
|
### dynamic suggestions function
|
|
106
105
|
|
|
107
106
|
#### Example
|
|
@@ -111,7 +110,7 @@ import oAutocomplete from 'o-autocomplete';
|
|
|
111
110
|
|
|
112
111
|
/**
|
|
113
112
|
* @callback PopulateOptions
|
|
114
|
-
* @param {Array<*>} options - The options which match the
|
|
113
|
+
* @param {Array<*>} options - The options which match the text which was typed into the autocomplete by the user
|
|
115
114
|
* @returns {void}
|
|
116
115
|
*/
|
|
117
116
|
/**
|
|
@@ -237,6 +236,13 @@ new oAutocomplete(oAutocompleteElement, {
|
|
|
237
236
|
| --- | --- | --- |
|
|
238
237
|
| option | <code>\*</code> | The option the user selected |
|
|
239
238
|
|
|
239
|
+
#### `defaultValue` (default: `''`)
|
|
240
|
+
|
|
241
|
+
Type: `string`
|
|
242
|
+
|
|
243
|
+
If setting a default input value for a [dynamic set of suggestions](for-a-dynamic-set-of-suggestions) set the `defaultValue` option.
|
|
244
|
+
|
|
245
|
+
_When progressively enhancing a [static set of suggestions](#for-a-static-set-of-suggestions) set a default value using HTML, by providing an appropriate `option` element._
|
|
240
246
|
|
|
241
247
|
## Keyboard Support
|
|
242
248
|
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
<form data-o-component="o-forms">
|
|
2
|
-
<
|
|
2
|
+
<div class="o-forms-field">
|
|
3
3
|
<span class="o-forms-title">
|
|
4
|
-
<
|
|
4
|
+
<label for="my-autocomplete" class="o-forms-title__main">Select your country</label>
|
|
5
5
|
</span>
|
|
6
6
|
<span class="o-forms-input o-forms-input--text">
|
|
7
|
-
<span data-o-component="o-autocomplete" data-o-autocomplete-source="customSuggestions" class="o-autocomplete">
|
|
7
|
+
<span data-o-component="o-autocomplete" data-o-autocomplete-default-value="United Kingdom" data-o-autocomplete-source="customSuggestions" class="o-autocomplete">
|
|
8
8
|
<!-- If the JavaScript executes, then this input will be progressively enhanced to an autocomplete component -->
|
|
9
9
|
<input required type="text" name="text-example" id="my-autocomplete">
|
|
10
10
|
</span>
|
|
11
|
-
<span class="o-forms-input__error">Please fill out this field</span>
|
|
11
|
+
<span role="alert" class="o-forms-input__error">Please fill out this field</span>
|
|
12
12
|
</span>
|
|
13
|
-
</
|
|
13
|
+
</div>
|
|
14
14
|
</form>
|
|
@@ -13,13 +13,19 @@ oForms.init();
|
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
|
-
* @param {CustomOption
|
|
16
|
+
* @param {CustomOption} option - The option to transform into a suggestion string
|
|
17
17
|
* @returns {string} The string to display in the suggestions dropdown for this option
|
|
18
18
|
*/
|
|
19
19
|
function mapOptionToSuggestedValue(option) {
|
|
20
|
-
if (option) {
|
|
21
|
-
|
|
20
|
+
if (typeof option !== 'object') {
|
|
21
|
+
throw new Error(`Could not map option to suggested value, unexpected type: ${typeof option}.`);
|
|
22
22
|
}
|
|
23
|
+
|
|
24
|
+
if (typeof option.Country_Name !== 'string') {
|
|
25
|
+
throw new Error(`Could not map option to suggested value, option.Country_Name is not a string`);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return option.Country_Name;
|
|
23
29
|
}
|
|
24
30
|
|
|
25
31
|
/**
|
|
@@ -56,6 +62,7 @@ function customSuggestions(query, populateOptions) {
|
|
|
56
62
|
new Autocomplete(document.querySelector('[data-o-component="o-autocomplete"]'), {
|
|
57
63
|
source: customSuggestions,
|
|
58
64
|
mapOptionToSuggestedValue,
|
|
65
|
+
defaultValue: data.find((d) => d['Two_Letter_Country_Code'] === 'GB')?.Country_Name,
|
|
59
66
|
onConfirm: function (option) {
|
|
60
67
|
// eslint-disable-next-line no-console
|
|
61
68
|
console.log('You chose option', option);
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
<form data-o-component="o-forms">
|
|
2
|
-
<
|
|
2
|
+
<div class="o-forms-field">
|
|
3
3
|
<span class="o-forms-title">
|
|
4
|
-
<
|
|
4
|
+
<label for="my-autocomplete" class="o-forms-title__main">Select your country</label>
|
|
5
5
|
</span>
|
|
6
6
|
<span class="o-forms-input o-forms-input--text">
|
|
7
7
|
<span data-o-component="o-autocomplete" class="o-autocomplete">
|
|
8
8
|
<!-- If the JavaScript executes, then this input will be progressively enhanced to an autocomplete component -->
|
|
9
9
|
<input required type="text" name="text-example" id="my-autocomplete">
|
|
10
10
|
</span>
|
|
11
|
-
<span class="o-forms-input__error">Please fill out this field</span>
|
|
11
|
+
<span role="alert" class="o-forms-input__error">Please fill out this field</span>
|
|
12
12
|
</span>
|
|
13
|
-
</
|
|
13
|
+
</div>
|
|
14
14
|
</form>
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
<form data-o-component="o-forms">
|
|
2
|
-
<
|
|
2
|
+
<div class="o-forms-field">
|
|
3
3
|
<span class="o-forms-title">
|
|
4
|
-
<
|
|
4
|
+
<label for="my-autocomplete" class="o-forms-title__main">Select your country</label>
|
|
5
5
|
</span>
|
|
6
6
|
<span class="o-forms-input o-forms-input--text">
|
|
7
7
|
<span data-o-component="o-autocomplete" data-o-autocomplete-source="customSuggestions" class="o-autocomplete">
|
|
8
8
|
<!-- If the JavaScript executes, then this input will be progressively enhanced to an autocomplete component -->
|
|
9
9
|
<input required type="text" name="text-example" id="my-autocomplete">
|
|
10
10
|
</span>
|
|
11
|
-
<span class="o-forms-input__error">Please fill out this field</span>
|
|
11
|
+
<span role="alert" class="o-forms-input__error">Please fill out this field</span>
|
|
12
12
|
</span>
|
|
13
|
-
</
|
|
13
|
+
</div>
|
|
14
14
|
</form>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
<
|
|
1
|
+
<div class="o-forms-field">
|
|
2
2
|
<span class="o-forms-title">
|
|
3
|
-
<
|
|
3
|
+
<label for="my-autocomplete" class="o-forms-title__main">Select your country</label>
|
|
4
4
|
</span>
|
|
5
5
|
{{! o-forms styles for select input needed for the core experience }}
|
|
6
6
|
{{! o-forms styles for text input needed for the enhances JS experience }}
|
|
@@ -267,4 +267,4 @@
|
|
|
267
267
|
</select>
|
|
268
268
|
</span>
|
|
269
269
|
</span>
|
|
270
|
-
</
|
|
270
|
+
</div>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@financial-times/o-autocomplete",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0",
|
|
4
4
|
"description": "An origami component for autocomplete inputs",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"autocomplete",
|
|
@@ -22,7 +22,8 @@
|
|
|
22
22
|
"scripts": {
|
|
23
23
|
"build": "bash ../../scripts/component/build.bash",
|
|
24
24
|
"test": "bash ../../scripts/component/test.bash",
|
|
25
|
-
"lint": "bash ../../scripts/component/lint.bash"
|
|
25
|
+
"lint": "bash ../../scripts/component/lint.bash",
|
|
26
|
+
"watch": "bash ../../scripts/component/watch.bash"
|
|
26
27
|
},
|
|
27
28
|
"engines": {
|
|
28
29
|
"npm": "^7 || ^8"
|
package/src/js/autocomplete.js
CHANGED
|
@@ -173,6 +173,7 @@ function initClearButton(instance) {
|
|
|
173
173
|
|
|
174
174
|
/**
|
|
175
175
|
* @typedef {object} AutocompleteOptions
|
|
176
|
+
* @property {string} [defaultValue] - Specify a string to prefill the autocomplete with
|
|
176
177
|
* @property {Source} [source] - The function which retrieves the suggestions to display
|
|
177
178
|
* @property {MapOptionToSuggestedValue} [mapOptionToSuggestedValue] - Function which transforms a suggestion before rendering
|
|
178
179
|
* @property {onConfirm} [onConfirm] - Function which is called when the user selects an option
|
|
@@ -192,6 +193,7 @@ class Autocomplete {
|
|
|
192
193
|
this.options = {};
|
|
193
194
|
if (opts.source) {
|
|
194
195
|
this.options.source = opts.source;
|
|
196
|
+
this.options.defaultValue = opts.defaultValue;
|
|
195
197
|
}
|
|
196
198
|
if (opts.mapOptionToSuggestedValue) {
|
|
197
199
|
this.options.mapOptionToSuggestedValue = opts.mapOptionToSuggestedValue;
|
|
@@ -250,6 +252,7 @@ class Autocomplete {
|
|
|
250
252
|
if (!id) {
|
|
251
253
|
throw new Error("Missing `id` attribute on the o-autocomplete input. An `id` needs to be set as it is used within the o-autocomplete to implement the accessibility features.");
|
|
252
254
|
}
|
|
255
|
+
|
|
253
256
|
this.autocompleteEl.innerHTML = '';
|
|
254
257
|
this.autocompleteEl.appendChild(this.container);
|
|
255
258
|
accessibleAutocomplete({
|
|
@@ -266,16 +269,17 @@ class Autocomplete {
|
|
|
266
269
|
source: this.options.source,
|
|
267
270
|
cssNamespace: 'o-autocomplete',
|
|
268
271
|
displayMenu: 'overlay',
|
|
272
|
+
defaultValue: this.options.defaultValue || '',
|
|
269
273
|
showNoOptionsFound: false,
|
|
270
274
|
templates: {
|
|
271
275
|
/**
|
|
272
276
|
* Used when rendering suggestions, the return value of this will be used as the innerHTML for a single suggestion.
|
|
273
277
|
*
|
|
274
278
|
* @param {*} option The suggestion to apply the template with.
|
|
275
|
-
* @returns {string} HTML string to represent a single suggestion.
|
|
279
|
+
* @returns {string|undefined} HTML string to represent a single suggestion.
|
|
276
280
|
*/
|
|
277
281
|
suggestion: (option) => {
|
|
278
|
-
if (typeof option
|
|
282
|
+
if (typeof option === 'object') {
|
|
279
283
|
// If the `mapOptionToSuggestedValue` function is defined
|
|
280
284
|
// Apply the function to the option. This is a way for the
|
|
281
285
|
// consuming application to decide what text should be
|
|
@@ -285,21 +289,23 @@ class Autocomplete {
|
|
|
285
289
|
// which should be used as the suggestion string.
|
|
286
290
|
if (typeof this.mapOptionToSuggestedValue === 'function') {
|
|
287
291
|
option = this.mapOptionToSuggestedValue(option);
|
|
288
|
-
} else if (typeof option !== 'string') {
|
|
289
|
-
throw new Error(`The option trying to be displayed as a suggestion is not a string, it is "${typeof option}". o-autocomplete can only display strings as suggestions. Define a \`mapOptionToSuggestedValue\` function to convert the option into a string to be used as the suggestion.`);
|
|
290
292
|
}
|
|
291
293
|
}
|
|
292
294
|
|
|
295
|
+
if (typeof option !== 'string' && typeof option !== 'undefined') {
|
|
296
|
+
throw new Error(`The option trying to be displayed as a suggestion is not a string, it is "${typeof option}". o-autocomplete can only display strings as suggestions. Define a \`mapOptionToSuggestedValue\` function to convert the option into a string to be used as the suggestion.`);
|
|
297
|
+
}
|
|
298
|
+
|
|
293
299
|
return this.suggestionTemplate(option);
|
|
294
300
|
},
|
|
295
301
|
/**
|
|
296
302
|
* Used when a suggestion is selected, the return value of this will be used as the value for the input element.
|
|
297
303
|
*
|
|
298
304
|
* @param {*} option The suggestion which was selected.
|
|
299
|
-
* @returns {string} String to represent the suggestion.
|
|
305
|
+
* @returns {string|undefined} String to represent the suggestion.
|
|
300
306
|
*/
|
|
301
307
|
inputValue: (option) => {
|
|
302
|
-
if (typeof option
|
|
308
|
+
if (typeof option === 'object') {
|
|
303
309
|
// If the `mapOptionToSuggestedValue` function is defined
|
|
304
310
|
// Apply the function to the option. This is a way for the
|
|
305
311
|
// consuming application to decide what text should be
|
|
@@ -309,11 +315,13 @@ class Autocomplete {
|
|
|
309
315
|
// which should be used as the suggestion string.
|
|
310
316
|
if (typeof this.mapOptionToSuggestedValue === 'function') {
|
|
311
317
|
option = this.mapOptionToSuggestedValue(option);
|
|
312
|
-
} else if (typeof option !== 'string') {
|
|
313
|
-
throw new Error(`The option trying to be displayed as a suggestion is not a string, it is "${typeof option}". o-autocomplete can only display strings as suggestions. Define a \`mapOptionToSuggestedValue\` function to convert the option into a string to be used as the suggestion.`);
|
|
314
318
|
}
|
|
315
319
|
}
|
|
316
320
|
|
|
321
|
+
if (typeof option !== 'string' && typeof option !== 'undefined') {
|
|
322
|
+
throw new Error(`The option trying to be displayed as a suggestion is not a string, it is "${typeof option}". o-autocomplete can only display strings as suggestions. Define a \`mapOptionToSuggestedValue\` function to convert the option into a string to be used as the suggestion.`);
|
|
323
|
+
}
|
|
324
|
+
|
|
317
325
|
return option;
|
|
318
326
|
}
|
|
319
327
|
}
|
|
@@ -338,6 +346,8 @@ class Autocomplete {
|
|
|
338
346
|
}
|
|
339
347
|
},
|
|
340
348
|
autoselect: false,
|
|
349
|
+
// To fallback with JS an enhanced element's default value should
|
|
350
|
+
// be set using static html.
|
|
341
351
|
defaultValue: '',
|
|
342
352
|
placeholder: '',
|
|
343
353
|
cssNamespace: 'o-autocomplete',
|
|
@@ -362,10 +372,11 @@ class Autocomplete {
|
|
|
362
372
|
*/
|
|
363
373
|
suggestionTemplate (suggestedValue) {
|
|
364
374
|
// o-autocomplete has a UI design to highlight characters in the suggestions.
|
|
375
|
+
const input = this.autocompleteEl.querySelector('input');
|
|
365
376
|
/**
|
|
366
377
|
* @type {CharacterHighlight[]} An array of arrays which contain two items, the first is the character in the suggestion, the second is a boolean which indicates whether the character should be highlighted.
|
|
367
378
|
*/
|
|
368
|
-
const characters = highlightSuggestion(suggestedValue,
|
|
379
|
+
const characters = highlightSuggestion(suggestedValue, input ? input.value : suggestedValue);
|
|
369
380
|
|
|
370
381
|
let output = '';
|
|
371
382
|
for (const [character, shoudHighlight] of characters) {
|
|
@@ -395,7 +406,8 @@ class Autocomplete {
|
|
|
395
406
|
|
|
396
407
|
if (autocompleteEl.dataset.oAutocompleteSource) {
|
|
397
408
|
return {
|
|
398
|
-
source: autocompleteEl.dataset.oAutocompleteSource
|
|
409
|
+
source: autocompleteEl.dataset.oAutocompleteSource,
|
|
410
|
+
defaultValue: autocompleteEl.dataset.oAutocompleteDefaultValue
|
|
399
411
|
};
|
|
400
412
|
} else {
|
|
401
413
|
return {};
|