Skip to content

Commit

Permalink
v1.1.0 prep changes
Browse files Browse the repository at this point in the history
  • Loading branch information
mynamesleon committed Jan 29, 2020
1 parent 1b2d75d commit e4959a0
Show file tree
Hide file tree
Showing 22 changed files with 4,956 additions and 6,937 deletions.
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Changelog

All notable changes to this project will be documented in this file.

## [1.1.0] - 2020-01-29

### Added

- Home key usage to go to first item in the list
- End key usage to go to last item in the list
- `onAsyncError` callback option

### Changed

- Moved code and build over to TypeScript for: code improvements, self-documentation, and reduced bundle size by using an ES6 output from TypeScript that's bundled to UMD with webpack.

### Fixed

- Issue with the API filter method getting an error
- Issue when clicking on a single-select autocomplete with minLength of 0 with a current selection, which was correctly searching with an empty string, but the polling method was then triggering a search with the value afterwards.
- Screen reader announcements for results ignoring the number of results rendered

[1.1.0]: https://github.com/mynamesleon/aria-autocomplete/compare/v1.0.0...v1.1.0
187 changes: 91 additions & 96 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,23 +33,23 @@ Then import it, and call it on an element (ideally a text `<input />`, but not n
```javascript
import AriaAutocomplete from 'aria-autocomplete';

new AriaAutocomplete(document.getElementById('some-element'), {
AriaAutocomplete(document.getElementById('some-element'), {
source: ArrayOrStringOrFunction
});
```

At its core, the autocomplete requires only an element and a `source`. When the element is an input, its value will be set using the user's selection(s). If a `source` option isn't provided (is falsy, or an empty Array), and the element is either a `<select>`, or has child checkboxes, those will be used to build up the `source`.

```javascript
new AriaAutocomplete(document.getElementById('some-input'), {
AriaAutocomplete(document.getElementById('some-input'), {
source: ['Afghanistan', 'Albania', 'Algeria', ...more]
});

const select = document.getElementById('some-select');
new AriaAutocomplete(select);
AriaAutocomplete(select);

const div = document.getElementById('some-div-with-child-checkboxes');
new AriaAutocomplete(div);
AriaAutocomplete(div);
```

### Plain JavaScript module
Expand All @@ -74,236 +74,231 @@ As we all know however, Internet Explorer _sucks_. If you need to support Intern

The full list of options, and their defaults:

```javascript
```typescript
{
/**
* @description Give the autocomplete a name to be included in form submissions
* Give the autocomplete a name to be included in form submissions
* (Instead of using this option, I would advise initialising the autocomplete on
* an existing input that will be submitted, to also use any existing validation;
* this approach is also compatible with the control in multiple mode)
*/
name: '',
name: string;

/**
* @type {string | string[] | Object[] | Function}
* @description Specify source. See examples file for more specific usage.
* Specify source. See examples file for more specific usage.
* @example ['Afghanistan', 'Albania', 'Algeria', ...more]
* @example (query: String, render: Function) => render([])
* @example (query, render) => render(arrayToUse)
*/
source: '',
source: string[] | any[] | string | Function;

/**
* @description Properties to use for label and value
* when source is an Array of Objects
* Properties to use for label and value when source is an Array of Objects
*/
sourceMapping: { value: 'value', label: 'label' },
sourceMapping: any = {};

/**
* @type {string[]}
* @description Additional properties to use when searching for a match.
* Additional properties to use when searching for a match.
* `label` will always be used
*/
alsoSearchIn: [],
alsoSearchIn: string[] = [];

/**
* @description Input delay after typing before running a search
* Input delay after typing before running a search
*/
delay: 100,
delay: number = 100;

/**
* @description Minimum number of characters to run a search (includes spaces)
* Minimum number of characters to run a search (includes spaces)
*/
minLength: 1,
minLength: number = 1;

/**
* @description Maximum number of results to render. Also used with async endpoint
* Maximum number of results to render. Also used in async endpoint URL
*/
maxResults: 9999,
maxResults: number = 9999;

/**
* @description Render a control that triggers showing all options.
* Render a control that triggers showing all options.
* Runs a search with an empty query: '', and maxResults of 9999
*/
showAllControl: false,
showAllControl: boolean = false;

/**
* @description Confirm currently active selection when blurring off of the control.
* If no active selection, will compare current input value against available labels
* Confirm currently active selection when blurring off of the control. If
* no active selection, will compare current input value against available labels
*/
confirmOnBlur: true,
confirmOnBlur: boolean = true;

/**
* @description Allow multiple items to be selected
* Allow multiple items to be selected
*/
multiple: false,
multiple: boolean = false;

/**
* @description Adjust input width to match its value.
* Experimental, and a performance hit
* Adjust input width to match its value. This will incur a performance hit
*/
autoGrow: false,
autoGrow: boolean = false;

/**
* @description Maximum number of items that can be selected
* Maximum number of items that can be selected in multiple mode
*/
maxItems: 9999,
maxItems: number = 9999;

/**
* @description If initialised element is an input, and in multiple mode,
* If initialised element is an input, and in multiple mode,
* character that separates the selected values e.g. "GLP,ZWE"
*/
multipleSeparator: ',',
multipleSeparator: string = `,`;

/**
* @description If input is empty and in multiple mode,
* If input is empty and in multiple mode,
* delete last selected item on backspace
*/
deleteOnBackspace: false,
deleteOnBackspace: boolean = false;

/**
* @description In async mode, parameter to use when adding the input value
* to the endpoint String. e.g. https://some-endpoint?q=norway&limit=9999
* In async mode, parameter to use when adding the input value to the
* endpoint String. e.g. https://some-endpoint?q=norway&limit=9999
*/
asyncQueryParam: 'q',
asyncQueryParam: string = `q`;

/**
* @description In async mode, parameter to use when adding results limit
* to the endpoint String. e.g. https://some-endpoint?q=norway&limit=9999
* In async mode, parameter to use when adding results limit to the
* endpoint String. e.g. https://some-endpoint?q=norway&limit=9999
*/
asyncMaxResultsParam: 'limit',
asyncMaxResultsParam: string = `limit`;

/**
* @description Placeholder text to show in generated input
* Placeholder text to show in generated input
*/
placeholder: '',
placeholder: string;

/**
* @description Text to show (and announce to screen readers) if no results found.
* Text to show (and announce to screen readers) if no results found.
* If empty, the list of options will remain hidden when there are no results
*/
noResultsText: 'No results',
noResultsText: string = `No results`;

/**
* @description String to prepend to classes for BEM naming
* String to prepend to classes for BEM naming
* e.g. aria-autocomplete__input
*/
cssNameSpace: 'aria-autocomplete',
cssNameSpace: string = `aria-autocomplete`;

/**
* @description Custom class name to add to the options list holder
* Custom class name to add to the options list holder
*/
listClassName: '',
listClassName: string;

/**
* @description Custom class name to add to the generated input
* Custom class name to add to the generated input
*/
inputClassName: '',
inputClassName: string;

/**
* @description Custom class name to add to the component wrapper
* Custom class name to add to the component wrapper
*/
wrapperClassName: '',
wrapperClassName: string;

/**
* @description In multiple mode, screen reader text used for element deletion.
* Screen reader text used in multiple mode for element deletion.
* Prepended to option label in aria-label attribute e.g. 'delete Canada'
*/
srDeleteText: 'delete',
srDeleteText: string = `delete`;

/**
* @description Screen reader text announced after deletion.
* Screen reader text announced after deletion.
* Apended to option label e.g. 'Canada deleted'
*/
srDeletedText: 'deleted',
srDeletedText: string = `deleted`;

/**
* @description Value for aria-label attribute on the show all control
* Value for aria-label attribute on the show all control
*/
srShowAllText: 'Show all',
srShowAllText: string = `Show all`;

/**
* @description Screen reader text announced after confirming a selection.
* Screen reader text announced after confirming a selection.
* Appended to option label e.g. 'Canada selected'
*/
srSelectedText: 'selected',
srSelectedText: string = `selected`;

/**
* @description Screen reader explainer added to the list element
* via aria-label attribute
* Screen reader explainer added to the list element via aria-label attribute
*/
srListLabelText: 'Search suggestions',
srListLabelText: string = `Search suggestions`;

/**
* @description Screen reader description announced when the input receives focus.
* Screen reader description announced when the input receives focus.
* Only announced when input is empty
*/
srAssistiveText: 'When results are available use up and down arrows to review and '
+ 'enter to select. Touch device users, explore by touch or with swipe gestures.',
srAssistiveText: string =
`When results are available use up and down arrows to review and ` +
`enter to select. Touch device users, explore by touch or with swipe gestures.`;

/**
* @description Screen reader announcement after results are rendered
* Screen reader announcement after results are rendered
*/
srResultsText: length =>
`${length} ${length === 1 ? 'result' : 'results'} available.`,
srResultsText: (length: number) => string | void = (length: number) =>
`${length} ${length === 1 ? 'result' : 'results'} available.`;

/**
* @description Callback before a search is performed - receives the input value.
* Callback before a search is performed - receives the input value.
* Can be used to alter the search value by returning a String
*/
onSearch: query => query,
onSearch: (value: string) => string | void;

/**
* @description Callback before async call is made - receives the URL.
* Callback before async call is made - receives the URL.
* Can be used to format the endpoint URL by returning a String
*/
onAsyncPrep: url => url,
onAsyncPrep: (url: string) => string | void;

/**
* @description Callback after async call completes - receives the xhr object.
* Callback after async call completes - receives the xhr object.
* Can be used to format the results by returning an Array
*/
onAsyncSuccess: (query, xhr) => xhr.responseText,
onAsyncSuccess: (xhr: XMLHttpRequest) => any[] | void;

/**
* @description Callback prior to rendering - receives the options that are going
* Callback prior to rendering - receives the options that are going
* to render. Can be used to format the results by returning an Array
*/
onResponse: optionsToRender => optionsToRender,
onResponse: (options: any[]) => any[] | void;

/**
* @description Callback when rendering items in the list.
* Callback when rendering items in the list - receives the source option.
* Can be used to format the <li> content by returning a String
*/
onItemRender: itemData => itemData.label,
onItemRender: (sourceEntry: any) => string | void;

/**
* @description Callback after selection is made -
* receives an object with the option details
* Callback after selection is made - receives an object with the option details
*/
onConfirm: selection => {},
onConfirm: (selected: any) => void;

/**
* @description Callback after an autocomplete selection is deleted.
* Callback after an autocomplete selection is deleted.
* Fires in single-select mode when selection is deleted automatically.
* Fires in multi-select mode when selected is deleted by user action
*/
onDelete: selection => {},
onDelete: (deleted: any) => void;

/**
* @description Callback when main script processing and initial rendering has finished
* Callback when main script processing and initial rendering has finished
*/
onReady: componentWrapper => {},
onReady: (wrapper: HTMLDivElement) => void;

/**
* @description Callback when list area closes - receives the list holder element
* Callback when list area closes - receives the list holder element
*/
onClose: listElement => {},
onClose: (list: HTMLUListElement) => void;

/**
* @description Callback when list area opens - receives the list holder element
* Callback when list area opens - receives the list holder element
*/
onOpen: listElement => {}
onOpen: (list: HTMLUListElement) => void;
}
```

Calling `new AriaAutocomplete(element, options);` returns the API object, which can also be accessed on the element via `element.ariaAutocomplete`.
Calling `AriaAutocomplete(element, options);` returns the API object, which can also be accessed on the element via `element.ariaAutocomplete`.
Loading

0 comments on commit e4959a0

Please sign in to comment.